modernize pa_play_memblockq() and add a new function pa_memblockq_sink_input_new() which allows creation of memblockq streams without activating them immediately

git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1647 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2007-08-11 23:45:13 +00:00
parent 14d93fce44
commit 3d81dde335
2 changed files with 176 additions and 56 deletions

View file

@ -26,7 +26,6 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -34,50 +33,171 @@
#include <pulsecore/sink-input.h> #include <pulsecore/sink-input.h>
#include <pulsecore/gccmacro.h> #include <pulsecore/gccmacro.h>
#include <pulsecore/thread-mq.h>
#include "play-memblockq.h" #include "play-memblockq.h"
typedef struct memblockq_stream {
pa_msgobject parent;
pa_core *core;
pa_sink_input *sink_input;
pa_memblockq *memblockq;
} memblockq_stream;
enum {
MEMBLOCKQ_STREAM_MESSAGE_UNLINK,
};
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_disconnect(u->sink_input);
pa_sink_input_unref(u->sink_input);
u->sink_input = NULL;
memblockq_stream_unref(u);
}
static void memblockq_stream_free(pa_object *o) {
memblockq_stream *u = MEMBLOCKQ_STREAM(o);
pa_assert(u);
memblockq_stream_unlink(u);
if (u->memblockq)
pa_memblockq_free(u->memblockq);
pa_xfree(u);
}
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) { static void sink_input_kill_cb(pa_sink_input *i) {
pa_memblockq *q; pa_sink_input_assert_ref(i);
assert(i);
assert(i->userdata);
q = i->userdata; memblockq_stream_unlink(MEMBLOCKQ_STREAM(i->userdata));
pa_sink_input_disconnect(i);
pa_sink_input_unref(i);
pa_memblockq_free(q);
} }
static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
pa_memblockq *q; memblockq_stream *u;
assert(i);
assert(chunk);
assert(i->userdata);
q = i->userdata; pa_assert(i);
pa_assert(chunk);
u = MEMBLOCKQ_STREAM(i->userdata);
memblockq_stream_assert_ref(u);
return pa_memblockq_peek(q, chunk); if (!u->memblockq)
} return -1;
static void si_kill_cb(PA_GCC_UNUSED pa_mainloop_api *m, void *i) { if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
sink_input_kill_cb(i); 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;
}
return 0;
} }
static void sink_input_drop_cb(pa_sink_input *i, size_t length) { static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
pa_memblockq *q; memblockq_stream *u;
assert(i); pa_assert(i);
assert(length > 0); pa_assert(length > 0);
assert( i->userdata); u = MEMBLOCKQ_STREAM(i->userdata);
memblockq_stream_assert_ref(u);
q = i->userdata; if (!u->memblockq)
return;
pa_memblockq_drop(u->memblockq, length);
}
pa_memblockq_drop(q, length); 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) {
if (pa_memblockq_get_length(q) <= 0) memblockq_stream *u = NULL;
pa_mainloop_api_once(i->sink->core->mainloop, si_kill_cb, i); pa_sink_input_new_data data;
pa_assert(sink);
pa_assert(ss);
/* 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 NULL;
}
if (volume && pa_cvolume_is_muted(volume)) {
pa_memblockq_free(q);
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_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
pa_sink_input_new_data_set_volume(&data, volume);
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);
/* The reference to u is dangling here, because we want
* to keep this stream around until it is fully played. */
/* This sink input is not "put" yet, i.e. pa_sink_input_put() has
* not been called! */
return pa_sink_input_ref(u->sink_input);
fail:
if (u)
memblockq_stream_unref(u);
return NULL;
} }
int pa_play_memblockq( int pa_play_memblockq(
@ -88,39 +208,29 @@ int pa_play_memblockq(
pa_memblockq *q, pa_memblockq *q,
pa_cvolume *volume) { pa_cvolume *volume) {
pa_sink_input *si; pa_sink_input *i;
pa_sink_input_new_data data;
assert(sink); pa_assert(sink);
assert(ss); pa_assert(ss);
assert(q); pa_assert(q);
if (pa_memblockq_get_length(q) <= 0) { if (!(i = pa_memblockq_sink_input_new(sink, name, ss, map, q, volume)))
pa_memblockq_free(q);
return 0;
}
if (volume && pa_cvolume_is_muted(volume)) {
pa_memblockq_free(q);
return 0;
}
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; return -1;
si->peek = sink_input_peek_cb; pa_sink_input_put(i);
si->drop = sink_input_drop_cb; pa_sink_input_unref(i);
si->kill = sink_input_kill_cb;
si->userdata = q;
return 0; 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;
}

View file

@ -27,6 +27,16 @@
#include <pulsecore/sink.h> #include <pulsecore/sink.h>
#include <pulsecore/memblockq.h> #include <pulsecore/memblockq.h>
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( int pa_play_memblockq(
pa_sink *sink, pa_sink *sink,
const char *name, const char *name,