From 78f386ad45dc046d673fca5441dff188a7297059 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2004 15:18:33 +0000 Subject: more work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@17 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/sink.c | 245 +++++++++++++++++++++++++------------------------------------ 1 file changed, 100 insertions(+), 145 deletions(-) (limited to 'src/sink.c') diff --git a/src/sink.c b/src/sink.c index f2d5373d..82cde8f2 100644 --- a/src/sink.c +++ b/src/sink.c @@ -21,7 +21,7 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->core = core; s->sample_spec = *spec; - s->input_streams = idxset_new(NULL, NULL); + s->inputs = idxset_new(NULL, NULL); if (name) { n = malloc(strlen(name)+9); @@ -36,198 +36,153 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s s->notify = NULL; s->notify_userdata = NULL; + fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name); + return s; } void sink_free(struct sink *s) { - struct input_stream *i, *j = NULL; + struct sink_input *i, *j = NULL; assert(s); - while ((i = idxset_first(s->input_streams, NULL))) { - assert(i != j); - input_stream_kill(i); + while ((i = idxset_first(s->inputs, NULL))) { + assert(i != j && i->kill); + i->kill(i); j = i; } - idxset_free(s->input_streams, NULL, NULL); + + idxset_free(s->inputs, NULL, NULL); idxset_remove_by_data(s->core->sinks, s, NULL); source_free(s->monitor_source); + fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name); + free(s->name); free(s); } -struct pass1_info { - size_t maxlength; - unsigned count; - struct input_stream *last_input_stream; -}; - -static int get_max_length(void *p, uint32_t index, int *del, void*userdata) { - struct memchunk chunk; - struct pass1_info *info = userdata; - struct input_stream*i = p; - assert(info && i); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return 0; - - assert(chunk.length); - - if (info->maxlength > chunk.length) - info->maxlength = chunk.length; - - info->count++; - info->last_input_stream = i; - - memblock_unref(chunk.memblock); +void sink_notify(struct sink*s) { + assert(s); - return 0; + if (s->notify) + s->notify(s, s->notify_userdata); } -struct pass2_info { - struct memchunk *chunk; - struct sample_spec *spec; -}; - -static int do_mix(void *p, uint32_t index, int *del, void*userdata) { - struct memchunk chunk; - struct pass2_info *info = userdata; - struct input_stream*i = p; - assert(info && info->chunk && info->chunk->memblock && i && info->spec); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return 0; - - memblock_assert_exclusive(info->chunk->memblock); - assert(chunk.length && chunk.length <= info->chunk->memblock->length - info->chunk->index); - - add_clip(info->chunk, &chunk, info->spec); - memblock_unref(chunk.memblock); - memblockq_drop(i->memblockq, info->chunk->length); +void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { + assert(s && notify_callback); - input_stream_notify(i); - return 0; + s->notify = notify_callback; + s->notify_userdata = userdata; } -int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { - struct pass1_info pass1_info; - struct pass2_info pass2_info; - assert(s && target && result); - memblock_assert_exclusive(target); - - /* Calculate how many bytes to mix */ - pass1_info.maxlength = target->length; - pass1_info.count = 0; - - idxset_foreach(s->input_streams, get_max_length, &pass1_info); - assert(pass1_info.maxlength); - - /* No data to mix */ - if (pass1_info.count == 0) - return -1; +static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) { + uint32_t index = IDXSET_ANY; + struct sink_input *i; + unsigned n; - /* A shortcut if only a single input stream is connected */ - if (pass1_info.count == 1) { - struct input_stream *i = pass1_info.last_input_stream; - struct memchunk chunk; - size_t l; - - assert(i); - - if (memblockq_peek(i->memblockq, &chunk) != 0) - return -1; + assert(s && info); - l = target->length < chunk.length ? target->length : chunk.length; - memcpy(target->data, result->memblock+result->index, l); - target->length = l; - memblock_unref(chunk.memblock); - memblockq_drop(i->memblockq, l); + while (maxinfo > 0 && i = idxset_rrobin(s->inputs, &index)) { + assert(i->peek); + if (i->peek(i, &info->chunk, &info->volume) < 0) + continue; - input_stream_notify(i); + assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + info->userdata = i; - result->memblock = target; - result->length = l; - result->index = 0; - return 0; + info++; + maxinfo--; + n++; } - /* Do the real mixing */ - result->memblock = silence(target, &s->sample_spec); - result->index = 0; - result->length = pass1_info.maxlength; - pass2_info.chunk = result; - pass2_info.spec = &s->sample_spec; - idxset_foreach(s->input_streams, do_mix, &pass2_info); + return n; +} - assert(s->monitor_source); - source_post(s->monitor_source, result); +static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, size_t length) { + assert(s && info); - return 0; + for (; maxinfo > 0; maxinfo--, info++) { + struct sink_input *i = info->userdata; + assert(i && info->chunk.memblock); + + memblock_unref(info->chunk.memblock); + assert(i->drop); + i->drop(i, length); + } } int sink_render(struct sink*s, size_t length, struct memchunk *result) { - struct pass1_info pass1_info; - struct pass2_info pass2_info; - assert(s && result); - - if (!length) - length = (size_t) -1; + struct mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && length && result); - /* Calculate how many bytes to mix */ - pass1_info.maxlength = length; - pass1_info.count = 0; - - idxset_foreach(s->input_streams, get_max_length, &pass1_info); - assert(pass1_info.maxlength); + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - /* No data to mix */ - if (pass1_info.count == 0) + if (n <= 0) return -1; - if (pass1_info.count == 1) { - struct input_stream *i = pass1_info.last_input_stream; - size_t l; + if (n == 1) { + struct sink_info *i = info[0].userdata; + assert(i && b); + *result = info[0].chunk; + memblock_ref(result->memblock); - assert(i); + if (result->length > length) + result->length = length; - if (memblockq_peek(i->memblockq, result) != 0) - return -1; + l = result->length; + } else { + result->memblock = memblock_new(length); + assert(result->memblock); - l = length < result->length ? length : result->length; - result->length = l; - memblockq_drop(i->memblockq, l); - input_stream_notify(i); + result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec); + result->index = 0; - return 0; + assert(l); } - /* Do the mixing */ - result->memblock = silence(memblock_new(result->length), &s->sample_spec); - result->index = 0; - result->length = pass1_info.maxlength; - pass2_info.chunk = result; - pass2_info.spec = &s->sample_spec; - idxset_foreach(s->input_streams, do_mix, &pass2_info); - - assert(s->monitor_source); - - source_post(s->monitor_source, result); + inputs_drop(s, info, n, l); return 0; } -void sink_notify(struct sink*s) { - assert(s); +int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) { + struct mix_info info[MAX_MIX_CHANNELS]; + unsigned n; + size_t l; + assert(s && target && target->length && target->data && result); + + n = fill_mix_info(s, info, MAX_MIX_CHANNELS); - if (s->notify) - s->notify(s, s->notify_userdata); -} + if (n <= 0) + return -1; -void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) { - assert(s && notify_callback); + if (n == 1) { + struct sink_info *i = info[0].userdata; + assert(i && b); - s->notify = notify_callback; - s->notify_userdata = userdata; -} + l = target->length; + if (l > info[0].chunk.length) + l = info[0].chunk.length; + + result->memblock = target; + memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l); + result->length = target->length = l; + result->index = 0; + if (result->length > length) + result->length = length; + l = result->length; + } else { + + result->memblock = target; + result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec); + result->index = 0; + assert(l); + } + + inputs_drop(s, info, n, l); + return 0; +} -- cgit