summaryrefslogtreecommitdiffstats
path: root/polyp
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-07-20 01:07:06 +0000
committerLennart Poettering <lennart@poettering.net>2004-07-20 01:07:06 +0000
commitbb0b105b83c0f4ee56b4c7e9a179606aee296aa9 (patch)
treec7a83efa8830adee3b4c94a8e28d5c03c9573f20 /polyp
parent527faf01d0605a6ced9a73017cc8155adba59d24 (diff)
sample cache work
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@98 fefdeb5f-60dc-0310-8127-8f9354f1896f
Diffstat (limited to 'polyp')
-rw-r--r--polyp/Makefile.am3
-rw-r--r--polyp/cli-command.c59
-rw-r--r--polyp/clitext.c35
-rw-r--r--polyp/clitext.h1
-rw-r--r--polyp/core.c4
-rw-r--r--polyp/core.h4
-rw-r--r--polyp/debug.h8
-rw-r--r--polyp/hashmap.c14
-rw-r--r--polyp/hashmap.h5
-rw-r--r--polyp/main.c2
-rw-r--r--polyp/modargs.c4
-rw-r--r--polyp/module-alsa-sink.c2
-rw-r--r--polyp/protocol-esound.c194
-rw-r--r--polyp/scache.c181
-rw-r--r--polyp/scache.h24
15 files changed, 520 insertions, 20 deletions
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 <assert.h>
+#include <string.h>
#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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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