mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
add name registrar
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@39 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
010378643e
commit
a74cd2a1bd
17 changed files with 354 additions and 26 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
145
src/hashset.c
Normal file
145
src/hashset.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
16
src/hashset.h
Normal file
16
src/hashset.h
Normal file
|
|
@ -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
|
||||
28
src/idxset.c
28
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
97
src/namereg.c
Normal file
97
src/namereg.c
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
17
src/namereg.h
Normal file
17
src/namereg.h
Normal file
|
|
@ -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
|
||||
15
src/sink.c
15
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
12
src/source.c
12
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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
16
src/todo
16
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue