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 --- src/pulsecore/play-memchunk.c | 160 ++++++++++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 46 deletions(-) (limited to 'src/pulsecore/play-memchunk.c') 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; } + -- cgit