From a96ed347a30fdc7494b96542c0ad8a19ef178b25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Jul 2004 16:59:22 +0000 Subject: [PATCH] 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/{hashset.c => hashmap.c} | 46 ++++----- src/hashmap.h | 16 ++++ 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 +- 10 files changed, 350 insertions(+), 76 deletions(-) rename src/{hashset.c => hashmap.c} (69%) create mode 100644 src/hashmap.h 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 5112953..e8704f7 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 8eb638d..13374e4 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/hashset.c b/src/hashmap.c similarity index 69% rename from src/hashset.c rename to src/hashmap.c index 4815a13..0c963f1 100644 --- a/src/hashset.c +++ b/src/hashmap.c @@ -2,33 +2,33 @@ #include #include -#include "hashset.h" +#include "hashmap.h" #include "idxset.h" -struct hashset_entry { - struct hashset_entry *next, *previous, *bucket_next, *bucket_previous; +struct hashmap_entry { + struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; unsigned hash; const void *key; void *value; }; -struct pa_hashset { +struct pa_hashmap { unsigned size; - struct hashset_entry **data; - struct hashset_entry *first_entry; + 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_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)); +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 hashset_entry*)*(h->size = 1023)); + h->data = malloc(sizeof(struct hashmap_entry*)*(h->size = 1023)); assert(h->data); - memset(h->data, 0, sizeof(struct hashset_entry*)*(h->size = 1023)); + 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; @@ -36,7 +36,7 @@ struct pa_hashset *pa_hashset_new(unsigned (*hash_func) (const void *p), int (*c return h; } -static void remove(struct pa_hashset *h, struct hashset_entry *e) { +static void remove(struct pa_hashmap *h, struct hashmap_entry *e) { assert(e); if (e->next) @@ -57,7 +57,7 @@ static void remove(struct pa_hashset *h, struct hashset_entry *e) { h->n_entries--; } -void pa_hashset_free(struct pa_hashset*h, void (*free_func)(void *p, void *userdata), void *userdata) { +void pa_hashmap_free(struct pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) { assert(h); while (h->first_entry) { @@ -70,8 +70,8 @@ void pa_hashset_free(struct pa_hashset*h, void (*free_func)(void *p, void *userd free(h); } -static struct hashset_entry *get(struct pa_hashset *h, unsigned hash, const void *key) { - struct hashset_entry *e; +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) @@ -80,8 +80,8 @@ static struct hashset_entry *get(struct pa_hashset *h, unsigned hash, const void return NULL; } -int pa_hashset_put(struct pa_hashset *h, const void *key, void *value) { - struct hashset_entry *e; +int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; unsigned hash; assert(h && key); @@ -90,7 +90,7 @@ int pa_hashset_put(struct pa_hashset *h, const void *key, void *value) { if ((e = get(h, hash, key))) return -1; - e = malloc(sizeof(struct hashset_entry)); + e = malloc(sizeof(struct hashmap_entry)); assert(e); e->hash = hash; @@ -113,9 +113,9 @@ int pa_hashset_put(struct pa_hashset *h, const void *key, void *value) { return 0; } -void* pa_hashset_get(struct pa_hashset *h, const void *key) { +void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { unsigned hash; - struct hashset_entry *e; + struct hashmap_entry *e; assert(h && key); hash = h->hash_func(key) % h->size; @@ -126,8 +126,8 @@ void* pa_hashset_get(struct pa_hashset *h, const void *key) { return e->value; } -int pa_hashset_remove(struct pa_hashset *h, const void *key) { - struct hashset_entry *e; +int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { + struct hashmap_entry *e; unsigned hash; assert(h && key); @@ -140,6 +140,6 @@ int pa_hashset_remove(struct pa_hashset *h, const void *key) { return 0; } -unsigned pa_hashset_ncontents(struct pa_hashset *h) { +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 0000000..4a0ad77 --- /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.h b/src/hashset.h deleted file mode 100644 index a6ece8b..0000000 --- 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 0000000..a7b4880 --- /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 0000000..437dd43 --- /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 67c0240..e5e97b5 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 9cfb735..bf381ae 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 bf01a4c..deab216 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 -- 2.7.4