From dd10c982414dfa8fbb9aeeeae61c68e4a6f081cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Jan 2006 16:25:31 +0000 Subject: Mega patch: * implement inner loops using liboil * drop "typeid" stuff * add support for channel maps * add support for seperate volumes per channel * add support for hardware mixer settings (only module-oss implements this for now) * fix a lot of types for _t suffix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@463 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/sink.c | 226 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 75 deletions(-) (limited to 'polyp/sink.c') diff --git a/polyp/sink.c b/polyp/sink.c index aac90c04..bb656649 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -40,43 +40,54 @@ #define MAX_MIX_CHANNELS 32 -pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + pa_sink *s; char *n = NULL; char st[256]; int r; - assert(core && name && *name && spec); - s = pa_xmalloc(sizeof(pa_sink)); + assert(core); + assert(name); + assert(*name); + assert(spec); + + s = pa_xnew(pa_sink, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { pa_xfree(s); return NULL; } - s->name = pa_xstrdup(name); - s->description = NULL; - s->typeid = typeid; - s->ref = 1; + s->core = core; s->state = PA_SINK_RUNNING; - + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); s->owner = NULL; - s->core = core; + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->inputs = pa_idxset_new(NULL, NULL); - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, typeid, n, 0, spec); - assert(s->monitor_source); - pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); - - s->volume = PA_VOLUME_NORM; + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; s->userdata = NULL; r = pa_idxset_put(core->sinks, s, &s->index); @@ -85,6 +96,13 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa pa_sample_spec_snprint(st, sizeof(st), spec); pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + n = pa_sprintf_malloc("%s_monitor", name); + s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); + assert(s->monitor_source); + pa_xfree(n); + s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); return s; @@ -92,7 +110,9 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa void pa_sink_disconnect(pa_sink* s) { pa_sink_input *i, *j = NULL; - assert(s && s->state == PA_SINK_RUNNING); + + assert(s); + assert(s->state == PA_SINK_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -105,16 +125,19 @@ void pa_sink_disconnect(pa_sink* s) { pa_source_disconnect(s->monitor_source); pa_idxset_remove_by_data(s->core->sinks, s, NULL); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; s->state = PA_SINK_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void sink_free(pa_sink *s) { - assert(s && s->ref == 0); + assert(s); + assert(!s->ref); if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); @@ -128,24 +151,29 @@ static void sink_free(pa_sink *s) { pa_xfree(s->name); pa_xfree(s->description); + pa_xfree(s->driver); pa_xfree(s); } void pa_sink_unref(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!(--s->ref)) sink_free(s); } pa_sink* pa_sink_ref(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } void pa_sink_notify(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->notify) s->notify(s); @@ -156,20 +184,25 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { pa_sink_input *i; unsigned n = 0; - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { + /* Increase ref counter, to make sure that this input doesn't + * vanish while we still need it */ pa_sink_input_ref(i); - if (pa_sink_input_peek(i, &info->chunk) < 0) { + if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { pa_sink_input_unref(i); continue; } - info->volume = i->volume; info->userdata = i; - assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + assert(info->chunk.memblock); + assert(info->chunk.memblock->data); + assert(info->chunk.length); info++; maxinfo--; @@ -180,15 +213,21 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { } static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (; maxinfo > 0; maxinfo--, info++) { pa_sink_input *i = info->userdata; - assert(i && info->chunk.memblock); + assert(i); + assert(info->chunk.memblock); + + /* Drop read data */ pa_sink_input_drop(i, &info->chunk, length); pa_memblock_unref(info->chunk.memblock); + /* Decrease ref counter */ pa_sink_input_unref(i); info->userdata = NULL; } @@ -197,8 +236,8 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; + assert(s); assert(s->ref >= 1); assert(length); @@ -212,37 +251,29 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; - pa_sink_input *i = info[0].userdata; - assert(i); + pa_cvolume volume; + *result = info[0].chunk; pa_memblock_ref(result->memblock); if (result->length > length) result->length = length; - l = result->length; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - if (volume != PA_VOLUME_NORM) { + if (!pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - pa_volume_memchunk(result, &s->sample_spec, volume); + pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); - result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); + result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); result->index = 0; - - assert(l); } - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, result->length); pa_source_post(s->monitor_source, result); r = 0; @@ -256,9 +287,14 @@ finish: int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; - assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -268,27 +304,27 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; + pa_cvolume volume; - l = target->length; - if (l > info[0].chunk.length) - l = info[0].chunk.length; + if (target->length > info[0].chunk.length) + target->length = info[0].chunk.length; - memcpy((uint8_t*) target->memblock->data+target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, l); - target->length = l; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + target->length); - if (volume != PA_VOLUME_NORM) - pa_volume_memchunk(target, &s->sample_spec, volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); } else - target->length = l = pa_mix(info, n, (uint8_t*) target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + target->length = pa_mix(info, n, + (uint8_t*) target->memblock->data + target->index, + target->length, + &s->sample_spec, + &s->sw_volume); - assert(l); - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, target->length); pa_source_post(s->monitor_source, target); r = 0; @@ -302,7 +338,13 @@ finish: void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; - assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -331,7 +373,10 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { } void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s && s->ref >= 1 && length && result); + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); /*** This needs optimization ***/ @@ -342,7 +387,8 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { } pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!s->get_latency) return 0; @@ -351,7 +397,8 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { } void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); s->owner = m; @@ -359,11 +406,40 @@ void pa_sink_set_owner(pa_sink *s, pa_module *m) { pa_source_set_owner(s->monitor_source, m); } -void pa_sink_set_volume(pa_sink *s, pa_volume_t volume) { - assert(s && s->ref >= 1); +void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; - if (s->volume != volume) { - s->volume = volume; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - } + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; } -- cgit