From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 241 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/pulsecore/source-output.c (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c new file mode 100644 index 00000000..230b416d --- /dev/null +++ b/src/pulsecore/source-output.c @@ -0,0 +1,241 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "source-output.h" + +#define CHECK_VALIDITY_RETURN_NULL(condition) \ +do {\ +if (!(condition)) \ + return NULL; \ +} while (0) + +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { + + pa_source_output *o; + pa_resampler *resampler = NULL; + int r; + char st[256]; + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SOURCE_RUNNING); + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + + if (!map) + map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + + CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); + CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); + CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); + CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log(__FILE__": Failed to create source output: too many outputs per source."); + return NULL; + } + + if (resample_method == PA_RESAMPLER_INVALID) + resample_method = s->core->resample_method; + + if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) + return NULL; + + o = pa_xnew(pa_source_output, 1); + o->ref = 1; + o->state = PA_SOURCE_OUTPUT_RUNNING; + o->name = pa_xstrdup(name); + o->driver = pa_xstrdup(driver); + o->owner = NULL; + o->source = s; + o->client = NULL; + + o->sample_spec = *spec; + o->channel_map = *map; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + o->userdata = NULL; + + o->resampler = resampler; + + assert(s->core); + r = pa_idxset_put(s->core->source_outputs, o, &o->index); + assert(r == 0 && o->index != PA_IDXSET_INVALID); + r = pa_idxset_put(s->outputs, o, NULL); + assert(r == 0); + + pa_sample_spec_snprint(st, sizeof(st), spec); + pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + return o; +} + +void pa_source_output_disconnect(pa_source_output*o) { + assert(o); + assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); + assert(o->source); + assert(o->source->core); + + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); + pa_idxset_remove_by_data(o->source->outputs, o, NULL); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + o->source = NULL; + + o->push = NULL; + o->kill = NULL; + o->get_latency = NULL; + + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; +} + +static void source_output_free(pa_source_output* o) { + assert(o); + + if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) + pa_source_output_disconnect(o); + + pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); + + if (o->resampler) + pa_resampler_free(o->resampler); + + pa_xfree(o->name); + pa_xfree(o->driver); + pa_xfree(o); +} + +void pa_source_output_unref(pa_source_output* o) { + assert(o); + assert(o->ref >= 1); + + if (!(--o->ref)) + source_output_free(o); +} + +pa_source_output* pa_source_output_ref(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + o->ref++; + return o; +} + + +void pa_source_output_kill(pa_source_output*o) { + assert(o); + assert(o->ref >= 1); + + if (o->kill) + o->kill(o); +} + +void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { + pa_memchunk rchunk; + + assert(o); + assert(chunk); + assert(chunk->length); + assert(o->push); + + if (o->state == PA_SOURCE_OUTPUT_CORKED) + return; + + if (!o->resampler) { + o->push(o, chunk); + return; + } + + pa_resampler_run(o->resampler, chunk, &rchunk); + if (!rchunk.length) + return; + + assert(rchunk.memblock); + o->push(o, &rchunk); + pa_memblock_unref(rchunk.memblock); +} + +void pa_source_output_set_name(pa_source_output *o, const char *name) { + assert(o); + assert(o->ref >= 1); + + pa_xfree(o->name); + o->name = pa_xstrdup(name); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); +} + +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (o->get_latency) + return o->get_latency(o); + + return 0; +} + +void pa_source_output_cork(pa_source_output *o, int b) { + assert(o); + assert(o->ref >= 1); + + if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + return; + + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; +} + +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + + if (!o->resampler) + return PA_RESAMPLER_INVALID; + + return pa_resampler_get_method(o->resampler); +} -- cgit From 2d00de58513fa069d4a8aabca0aa0be33eb37ce9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Aug 2006 22:30:45 +0000 Subject: Implement pa_source_input_move_to() for moving record streams between sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1181 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 77 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 230b416d..1ffaedae 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -79,8 +79,10 @@ pa_source_output* pa_source_output_new( resample_method = s->core->resample_method; if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; + } o = pa_xnew(pa_source_output, 1); o->ref = 1; @@ -100,6 +102,7 @@ pa_source_output* pa_source_output_new( o->userdata = NULL; o->resampler = resampler; + o->resample_method = resample_method; assert(s->core); r = pa_idxset_put(s->core->source_outputs, o, &o->index); @@ -111,6 +114,9 @@ pa_source_output* pa_source_output_new( pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + /* We do not call pa_source_notify() here, because the virtual + * functions have not yet been initialized */ return o; } @@ -166,7 +172,6 @@ pa_source_output* pa_source_output_ref(pa_source_output *o) { return o; } - void pa_source_output_kill(pa_source_output*o) { assert(o); assert(o->ref >= 1); @@ -221,13 +226,20 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { } void pa_source_output_cork(pa_source_output *o, int b) { + int n; + assert(o); assert(o->ref >= 1); if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) return; + + n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; + + if (n) + pa_source_notify(o->source); } pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { @@ -235,7 +247,66 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { assert(o->ref >= 1); if (!o->resampler) - return PA_RESAMPLER_INVALID; + return o->resample_method; return pa_resampler_get_method(o->resampler); } + +int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { + pa_source *origin; + pa_resampler *new_resampler; + + assert(o); + assert(o->ref >= 1); + assert(dest); + + origin = o->source; + + if (dest == origin) + return 0; + + if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log_warn(__FILE__": Failed to move source output: too many outputs per source."); + return -1; + } + + if (o->resampler && + pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && + pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) + + /* Try to reuse the old resampler if possible */ + new_resampler = o->resampler; + + else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { + + /* Okey, we need a new resampler for the new sink */ + + if (!(new_resampler = pa_resampler_new( + &dest->sample_spec, &dest->channel_map, + &o->sample_spec, &o->channel_map, + dest->core->memblock_stat, + o->resample_method))) { + pa_log_warn(__FILE__": Unsupported resampling operation."); + return -1; + } + } + + /* Okey, let's move it */ + pa_idxset_remove_by_data(origin->outputs, o, NULL); + pa_idxset_put(dest->outputs, o, NULL); + o->source = dest; + + /* Replace resampler */ + if (new_resampler != o->resampler) { + if (o->resampler) + pa_resampler_free(o->resampler); + o->resampler = new_resampler; + } + + /* Notify everyone */ + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + pa_source_notify(o->source); + + return 0; +} -- cgit From 3aba099fc3e515db5c4b1f2990c48fdb4160ff52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 02:19:36 +0000 Subject: clean up event generation a little: suppress unnecessary events and generate new ones on owner change git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1212 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 1ffaedae..36ea420c 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -208,6 +208,12 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { void pa_source_output_set_name(pa_source_output *o, const char *name) { assert(o); assert(o->ref >= 1); + + if (!o->name && !name) + return; + + if (o->name && name && !strcmp(o->name, name)) + return; pa_xfree(o->name); o->name = pa_xstrdup(name); -- cgit From a75e1ed9ef483c4c08f0fc963c0ea1a980f0c0e9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:55:17 +0000 Subject: implement hook_source_ouput_new. For this I modified the pa_source_output_new constructor to take a struct similar to what I already did for pa_sink_input_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1250 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 119 ++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 39 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 36ea420c..7371474f 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -33,6 +33,7 @@ #include #include +#include #include "source-output.h" @@ -42,44 +43,82 @@ if (!(condition)) \ return NULL; \ } while (0) +pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { + assert(data); + + memset(data, 0, sizeof(*data)); + data->resample_method = PA_RESAMPLER_INVALID; + return data; +} + +void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) { + assert(data); + + if ((data->channel_map_is_set = !!map)) + data->channel_map = *map; +} + +void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) { + assert(data); + + if ((data->sample_spec_is_set = !!spec)) + data->sample_spec = *spec; +} + pa_source_output* pa_source_output_new( - pa_source *s, - const char *driver, - const char *name, - const pa_sample_spec *spec, - const pa_channel_map *map, - int resample_method) { + pa_core *core, + pa_source_output_new_data *data, + pa_source_output_flags_t flags) { pa_source_output *o; pa_resampler *resampler = NULL; int r; - char st[256]; - pa_channel_map tmap; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + assert(core); + assert(data); - assert(s); - assert(spec); - assert(s->state == PA_SOURCE_RUNNING); + if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS)) + if (pa_hook_fire(&core->hook_source_output_new, data) < 0) + return NULL; + + CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); + CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + + if (!data->source) + data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1); - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec)); + CHECK_VALIDITY_RETURN_NULL(data->source); + CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); + + if (!data->sample_spec_is_set) + data->sample_spec = data->source->sample_spec; + + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); - if (!map) - map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT); + if (!data->channel_map_is_set) + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map)); - CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels); - CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver)); - CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name)); + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); + CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); - if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + if (data->resample_method == PA_RESAMPLER_INVALID) + data->resample_method = core->resample_method; + + CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source."); return NULL; } - if (resample_method == PA_RESAMPLER_INVALID) - resample_method = s->core->resample_method; - - if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) - if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) { + if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || + !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) + if (!(resampler = pa_resampler_new( + &data->source->sample_spec, &data->source->channel_map, + &data->sample_spec, &data->channel_map, + core->memblock_stat, + data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; } @@ -87,14 +126,14 @@ pa_source_output* pa_source_output_new( o = pa_xnew(pa_source_output, 1); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; - o->name = pa_xstrdup(name); - o->driver = pa_xstrdup(driver); - o->owner = NULL; - o->source = s; - o->client = NULL; + o->name = pa_xstrdup(data->name); + o->driver = pa_xstrdup(data->driver); + o->module = data->module; + o->source = data->source; + o->client = data->client; - o->sample_spec = *spec; - o->channel_map = *map; + o->sample_spec = data->sample_spec; + o->channel_map = data->channel_map; o->push = NULL; o->kill = NULL; @@ -102,18 +141,20 @@ pa_source_output* pa_source_output_new( o->userdata = NULL; o->resampler = resampler; - o->resample_method = resample_method; + o->resample_method = data->resample_method; - assert(s->core); - r = pa_idxset_put(s->core->source_outputs, o, &o->index); - assert(r == 0 && o->index != PA_IDXSET_INVALID); - r = pa_idxset_put(s->outputs, o, NULL); + r = pa_idxset_put(core->source_outputs, o, &o->index); + assert(r == 0); + r = pa_idxset_put(o->source->outputs, o, NULL); assert(r == 0); - pa_sample_spec_snprint(st, sizeof(st), spec); - pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", o->index, o->name, s->index, st); + pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + o->index, + o->name, + o->source->name, + pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); /* We do not call pa_source_notify() here, because the virtual * functions have not yet been initialized */ -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 7371474f..f9d66f6d 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -115,9 +115,9 @@ pa_source_output* pa_source_output_new( if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) if (!(resampler = pa_resampler_new( + core->mempool, &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, - core->memblock_stat, data->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return NULL; @@ -330,9 +330,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { /* Okey, we need a new resampler for the new sink */ if (!(new_resampler = pa_resampler_new( + dest->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, - dest->core->memblock_stat, o->resample_method))) { pa_log_warn(__FILE__": Unsupported resampling operation."); return -1; -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index f9d66f6d..a2fc8519 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -108,7 +108,7 @@ pa_source_output* pa_source_output_new( CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log(__FILE__": Failed to create source output: too many outputs per source."); + pa_log("Failed to create source output: too many outputs per source."); return NULL; } @@ -119,7 +119,7 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -148,7 +148,7 @@ pa_source_output* pa_source_output_new( r = pa_idxset_put(o->source->outputs, o, NULL); assert(r == 0); - pa_log_info(__FILE__": created %u \"%s\" on %s with sample spec %s", + pa_log_info("created %u \"%s\" on %s with sample spec %s", o->index, o->name, o->source->name, @@ -187,7 +187,7 @@ static void source_output_free(pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); - pa_log_info(__FILE__": freed %u \"%s\"", o->index, o->name); + pa_log_info("freed %u \"%s\"", o->index, o->name); if (o->resampler) pa_resampler_free(o->resampler); @@ -313,7 +313,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { return 0; if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log_warn(__FILE__": Failed to move source output: too many outputs per source."); + pa_log_warn("Failed to move source output: too many outputs per source."); return -1; } @@ -334,7 +334,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method))) { - pa_log_warn(__FILE__": Unsupported resampling operation."); + pa_log_warn("Unsupported resampling operation."); return -1; } } -- cgit From bf62e77f71733cd458df6fc02c6d9eda82a8e0c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:04:04 +0000 Subject: fix a bad memory access git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1302 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index a2fc8519..352fce14 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -301,7 +301,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; - pa_resampler *new_resampler; + pa_resampler *new_resampler = NULL; assert(o); assert(o->ref >= 1); -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 352fce14..5783b44a 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -45,7 +45,7 @@ if (!(condition)) \ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { assert(data); - + memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; return data; @@ -69,7 +69,7 @@ pa_source_output* pa_source_output_new( pa_core *core, pa_source_output_new_data *data, pa_source_output_flags_t flags) { - + pa_source_output *o; pa_resampler *resampler = NULL; int r; @@ -90,15 +90,15 @@ pa_source_output* pa_source_output_new( CHECK_VALIDITY_RETURN_NULL(data->source); CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); - + if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; - + CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - + CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); @@ -106,7 +106,7 @@ pa_source_output* pa_source_output_new( data->resample_method = core->resample_method; CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); - + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; @@ -122,7 +122,7 @@ pa_source_output* pa_source_output_new( pa_log_warn("Unsupported resampling operation."); return NULL; } - + o = pa_xnew(pa_source_output, 1); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; @@ -131,7 +131,7 @@ pa_source_output* pa_source_output_new( o->module = data->module; o->source = data->source; o->client = data->client; - + o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; @@ -139,10 +139,10 @@ pa_source_output* pa_source_output_new( o->kill = NULL; o->get_latency = NULL; o->userdata = NULL; - + o->resampler = resampler; o->resample_method = data->resample_method; - + r = pa_idxset_put(core->source_outputs, o, &o->index); assert(r == 0); r = pa_idxset_put(o->source->outputs, o, NULL); @@ -153,13 +153,13 @@ pa_source_output* pa_source_output_new( o->name, o->source->name, pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); /* We do not call pa_source_notify() here, because the virtual * functions have not yet been initialized */ - - return o; + + return o; } void pa_source_output_disconnect(pa_source_output*o) { @@ -167,7 +167,7 @@ void pa_source_output_disconnect(pa_source_output*o) { assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); assert(o->source); assert(o->source->core); - + pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -177,7 +177,7 @@ void pa_source_output_disconnect(pa_source_output*o) { o->push = NULL; o->kill = NULL; o->get_latency = NULL; - + o->state = PA_SOURCE_OUTPUT_DISCONNECTED; } @@ -187,8 +187,8 @@ static void source_output_free(pa_source_output* o) { if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) pa_source_output_disconnect(o); - pa_log_info("freed %u \"%s\"", o->index, o->name); - + pa_log_info("freed %u \"%s\"", o->index, o->name); + if (o->resampler) pa_resampler_free(o->resampler); @@ -208,7 +208,7 @@ void pa_source_output_unref(pa_source_output* o) { pa_source_output* pa_source_output_ref(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + o->ref++; return o; } @@ -223,7 +223,7 @@ void pa_source_output_kill(pa_source_output*o) { void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - + assert(o); assert(chunk); assert(chunk->length); @@ -231,7 +231,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { if (o->state == PA_SOURCE_OUTPUT_CORKED) return; - + if (!o->resampler) { o->push(o, chunk); return; @@ -240,7 +240,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_resampler_run(o->resampler, chunk, &rchunk); if (!rchunk.length) return; - + assert(rchunk.memblock); o->push(o, &rchunk); pa_memblock_unref(rchunk.memblock); @@ -255,7 +255,7 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { if (o->name && name && !strcmp(o->name, name)) return; - + pa_xfree(o->name); o->name = pa_xstrdup(name); @@ -265,7 +265,7 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { pa_usec_t pa_source_output_get_latency(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + if (o->get_latency) return o->get_latency(o); @@ -274,7 +274,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { void pa_source_output_cork(pa_source_output *o, int b) { int n; - + assert(o); assert(o->ref >= 1); @@ -282,9 +282,9 @@ void pa_source_output_cork(pa_source_output *o, int b) { return; n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; - + o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; - + if (n) pa_source_notify(o->source); } @@ -292,7 +292,7 @@ void pa_source_output_cork(pa_source_output *o, int b) { pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { assert(o); assert(o->ref >= 1); - + if (!o->resampler) return o->resample_method; @@ -323,12 +323,12 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { /* Try to reuse the old resampler if possible */ new_resampler = o->resampler; - + else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { /* Okey, we need a new resampler for the new sink */ - + if (!(new_resampler = pa_resampler_new( dest->core->mempool, &dest->sample_spec, &dest->channel_map, -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5783b44a..c7a9858c 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit 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/source-output.c | 376 ++++++++++++++++++++++++++++-------------- 1 file changed, 250 insertions(+), 126 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index c7a9858c..2a902dc2 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -26,7 +26,6 @@ #endif #include -#include #include #include @@ -39,14 +38,12 @@ #include "source-output.h" -#define CHECK_VALIDITY_RETURN_NULL(condition) \ -do {\ -if (!(condition)) \ - return NULL; \ -} while (0) +static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject); + +static void source_output_free(pa_object* mo); pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { - assert(data); + pa_assert(data); memset(data, 0, sizeof(*data)); data->resample_method = PA_RESAMPLER_INVALID; @@ -54,14 +51,14 @@ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_d } void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) { - assert(data); + pa_assert(data); if ((data->channel_map_is_set = !!map)) data->channel_map = *map; } void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) { - assert(data); + pa_assert(data); if ((data->sample_spec_is_set = !!spec)) data->sample_spec = *spec; @@ -74,288 +71,415 @@ pa_source_output* pa_source_output_new( pa_source_output *o; pa_resampler *resampler = NULL; - int r; char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; - assert(core); - assert(data); + pa_assert(core); + pa_assert(data); - if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS)) - if (pa_hook_fire(&core->hook_source_output_new, data) < 0) - return NULL; + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0) + return NULL; - CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver)); - CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name)); + pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); + pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name)); if (!data->source) data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1); - CHECK_VALIDITY_RETURN_NULL(data->source); - CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING); + pa_return_null_if_fail(data->source); + pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED); if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; - CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec)); + pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); - if (!data->channel_map_is_set) - pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + if (!data->channel_map_is_set) { + if (data->source->channel_map.channels == data->sample_spec.channels) + data->channel_map = data->source->channel_map; + else + pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + } - CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map)); - CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); + pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; - CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX); + pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; } - if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || - !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) + if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || + !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || + !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) { + if (!(resampler = pa_resampler_new( core->mempool, &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, - data->resample_method))) { + data->resample_method, + !!(flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } - o = pa_xnew(pa_source_output, 1); - o->ref = 1; - o->state = PA_SOURCE_OUTPUT_RUNNING; + data->resample_method = pa_resampler_get_method(resampler); + } + + o = pa_msgobject_new(pa_source_output); + o->parent.parent.free = source_output_free; + o->parent.process_msg = pa_source_output_process_msg; + + o->core = core; + o->state = PA_SOURCE_OUTPUT_INIT; + o->flags = flags; o->name = pa_xstrdup(data->name); o->driver = pa_xstrdup(data->driver); o->module = data->module; o->source = data->source; o->client = data->client; + o->resample_method = data->resample_method; o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; o->push = NULL; o->kill = NULL; o->get_latency = NULL; + o->detach = NULL; + o->attach = NULL; + o->suspend = NULL; o->userdata = NULL; - o->resampler = resampler; - o->resample_method = data->resample_method; + o->thread_info.state = o->state; + o->thread_info.attached = FALSE; + o->thread_info.sample_spec = o->sample_spec; + o->thread_info.resampler = resampler; - r = pa_idxset_put(core->source_outputs, o, &o->index); - assert(r == 0); - r = pa_idxset_put(o->source->outputs, o, NULL); - assert(r == 0); + pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); + pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); - pa_log_info("created %u \"%s\" on %s with sample spec %s", + pa_log_info("Created output %u \"%s\" on %s with sample spec %s", o->index, o->name, o->source->name, pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); - pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); - - /* We do not call pa_source_notify() here, because the virtual - * functions have not yet been initialized */ + /* Don't forget to call pa_source_output_put! */ return o; } -void pa_source_output_disconnect(pa_source_output*o) { - assert(o); - assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); - assert(o->source); - assert(o->source->core); +static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { + pa_assert(o); + + if (o->state == state) + return 0; + + if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) + return -1; + + if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED) + pa_assert_se(o->source->n_corked -- >= 1); + else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + + pa_source_update_status(o->source); + + o->state = state; + + if (state != PA_SOURCE_OUTPUT_UNLINKED) + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o); + + return 0; +} + +void pa_source_output_unlink(pa_source_output*o) { + pa_bool_t linked; + pa_assert(o); + + /* See pa_sink_unlink() for a couple of comments how this function + * works */ + + pa_source_output_ref(o); + + linked = PA_SOURCE_OUTPUT_LINKED(o->state); + + if (linked) + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); - pa_idxset_remove_by_data(o->source->outputs, o, NULL); + if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) + pa_source_output_unref(o); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); - o->source = NULL; + if (linked) { + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + source_output_set_state(o, PA_SOURCE_OUTPUT_UNLINKED); + pa_source_update_status(o->source); + } else + o->state = PA_SOURCE_OUTPUT_UNLINKED; o->push = NULL; o->kill = NULL; o->get_latency = NULL; + o->attach = NULL; + o->detach = NULL; + o->suspend = NULL; + + if (linked) { + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o); + } - o->state = PA_SOURCE_OUTPUT_DISCONNECTED; + o->source = NULL; + pa_source_output_unref(o); } -static void source_output_free(pa_source_output* o) { - assert(o); +static void source_output_free(pa_object* mo) { + pa_source_output *o = PA_SOURCE_OUTPUT(mo); + + pa_assert(pa_source_output_refcnt(o) == 0); + + if (PA_SOURCE_OUTPUT_LINKED(o->state)) + pa_source_output_unlink(o); - if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) - pa_source_output_disconnect(o); + pa_log_info("Freeing output %u \"%s\"", o->index, o->name); - pa_log_info("freed %u \"%s\"", o->index, o->name); + pa_assert(!o->thread_info.attached); - if (o->resampler) - pa_resampler_free(o->resampler); + if (o->thread_info.resampler) + pa_resampler_free(o->thread_info.resampler); pa_xfree(o->name); pa_xfree(o->driver); pa_xfree(o); } -void pa_source_output_unref(pa_source_output* o) { - assert(o); - assert(o->ref >= 1); +void pa_source_output_put(pa_source_output *o) { + pa_source_output_assert_ref(o); - if (!(--o->ref)) - source_output_free(o); -} + pa_assert(o->state == PA_SOURCE_OUTPUT_INIT); + pa_assert(o->push); -pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + o->thread_info.state = o->state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; - o->ref++; - return o; + if (o->state == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + pa_source_update_status(o->source); + + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); + + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o); } void pa_source_output_kill(pa_source_output*o) { - assert(o); - assert(o->ref >= 1); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); if (o->kill) o->kill(o); } +pa_usec_t pa_source_output_get_latency(pa_source_output *o) { + pa_usec_t r = 0; + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + + if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0) + r = 0; + + if (o->get_latency) + r += o->get_latency(o); + + return r; +} + +/* Called from thread context */ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(o); - assert(chunk); - assert(chunk->length); - assert(o->push); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state)); + pa_assert(chunk); + pa_assert(chunk->length); - if (o->state == PA_SOURCE_OUTPUT_CORKED) + if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED) return; - if (!o->resampler) { + pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING); + + if (!o->thread_info.resampler) { o->push(o, chunk); return; } - pa_resampler_run(o->resampler, chunk, &rchunk); + pa_resampler_run(o->thread_info.resampler, chunk, &rchunk); if (!rchunk.length) return; - assert(rchunk.memblock); + pa_assert(rchunk.memblock); o->push(o, &rchunk); pa_memblock_unref(rchunk.memblock); } -void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o); - assert(o->ref >= 1); - - if (!o->name && !name) - return; +void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); - if (o->name && name && !strcmp(o->name, name)) - return; + source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING); +} - pa_xfree(o->name); - o->name = pa_xstrdup(name); +int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + pa_return_val_if_fail(o->thread_info.resampler, -1); - pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); -} + if (o->sample_spec.rate == rate) + return 0; -pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + o->sample_spec.rate = rate; - if (o->get_latency) - return o->get_latency(o); + pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL); + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); return 0; } -void pa_source_output_cork(pa_source_output *o, int b) { - int n; - - assert(o); - assert(o->ref >= 1); +void pa_source_output_set_name(pa_source_output *o, const char *name) { + pa_source_output_assert_ref(o); - if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) + if (!o->name && !name) return; - n = o->state == PA_SOURCE_OUTPUT_CORKED && !b; + if (o->name && name && !strcmp(o->name, name)) + return; - o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; + pa_xfree(o->name); + o->name = pa_xstrdup(name); - if (n) - pa_source_notify(o->source); + if (PA_SOURCE_OUTPUT_LINKED(o->state)) { + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED], o); + pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); + } } pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { - assert(o); - assert(o->ref >= 1); + pa_source_output_assert_ref(o); - if (!o->resampler) - return o->resample_method; - - return pa_resampler_get_method(o->resampler); + return o->resample_method; } int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; pa_resampler *new_resampler = NULL; - assert(o); - assert(o->ref >= 1); - assert(dest); + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); + pa_source_assert_ref(dest); origin = o->source; if (dest == origin) return 0; + if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) + return -1; + if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log_warn("Failed to move source output: too many outputs per source."); return -1; } - if (o->resampler && + if (o->thread_info.resampler && pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) /* Try to reuse the old resampler if possible */ - new_resampler = o->resampler; + new_resampler = o->thread_info.resampler; - else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || - !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { + else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || + !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || + !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { - /* Okey, we need a new resampler for the new sink */ + /* Okey, we need a new resampler for the new source */ if (!(new_resampler = pa_resampler_new( dest->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, - o->resample_method))) { + o->resample_method, + !!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { pa_log_warn("Unsupported resampling operation."); return -1; } } + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], o); + /* Okey, let's move it */ + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_idxset_remove_by_data(origin->outputs, o, NULL); pa_idxset_put(dest->outputs, o, NULL); o->source = dest; + if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) { + pa_assert_se(origin->n_corked-- >= 1); + dest->n_corked++; + } + /* Replace resampler */ - if (new_resampler != o->resampler) { - if (o->resampler) - pa_resampler_free(o->resampler); - o->resampler = new_resampler; + if (new_resampler != o->thread_info.resampler) { + if (o->thread_info.resampler) + pa_resampler_free(o->thread_info.resampler); + o->thread_info.resampler = new_resampler; } + pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + + pa_source_update_status(origin); + pa_source_update_status(dest); + + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o); + + pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name); + /* Notify everyone */ pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); - pa_source_notify(o->source); return 0; } + +/* Called from thread context */ +int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) { + pa_source_output *o = PA_SOURCE_OUTPUT(mo); + + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state)); + + switch (code) { + + case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: { + + o->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata); + pa_resampler_set_output_rate(o->thread_info.resampler, PA_PTR_TO_UINT(userdata)); + + return 0; + } + + case PA_SOURCE_OUTPUT_MESSAGE_SET_STATE: { + o->thread_info.state = PA_PTR_TO_UINT(userdata); + + return 0; + } + } + + return -1; +} -- cgit From f873a2a22441d5eaacc5cbb502cbde829ee30a73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 11 Nov 2007 02:30:59 +0000 Subject: add a simple fully-automatic fully-linearupmixer/downmixer and enable it by default git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2044 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 2a902dc2..5c52419e 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -122,7 +122,7 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, - !!(flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { + (flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -415,7 +415,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method, - !!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) { + (o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { pa_log_warn("Unsupported resampling operation."); return -1; } -- cgit From 14a9b80afbb0bddc216462b72156f14e032e1b5e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:30:40 +0000 Subject: - Check process name when dealing with PID files - Add new PA_STREAM_FIX_CHANNELS, FIX_RATE, FIX_FORMAT, DONT_MOVE, VARIABLE_RATES to pa_sream_flags_t adn implement it - Expose those flags in pacat - Add notifications about device suspend/resume to the protocol and expose them in libpulse - Allow changing of buffer_attr during playback - allow disabling for remixing globally - hookup polkit support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2067 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5c52419e..576ddcf2 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -71,7 +71,7 @@ pa_source_output* pa_source_output_new( pa_source_output *o; pa_resampler *resampler = NULL; - char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_assert(core); pa_assert(data); @@ -103,11 +103,28 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); + if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT) + data->sample_spec.format = data->source->sample_spec.format; + + if (flags & PA_SOURCE_OUTPUT_FIX_RATE) + data->sample_spec.rate = data->source->sample_spec.rate; + + if (flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) { + data->sample_spec.channels = data->source->sample_spec.channels; + data->channel_map = data->source->channel_map; + } + + pa_assert(pa_sample_spec_valid(&data->sample_spec)); + pa_assert(pa_channel_map_valid(&data->channel_map)); + if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0) + return NULL; + if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return NULL; @@ -122,7 +139,9 @@ pa_source_output* pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, - (flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -153,6 +172,7 @@ pa_source_output* pa_source_output_new( o->detach = NULL; o->attach = NULL; o->suspend = NULL; + o->moved = NULL; o->userdata = NULL; o->thread_info.state = o->state; @@ -163,11 +183,12 @@ pa_source_output* pa_source_output_new( pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); - pa_log_info("Created output %u \"%s\" on %s with sample spec %s", + pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s", o->index, o->name, o->source->name, - pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec)); + pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map)); /* Don't forget to call pa_source_output_put! */ @@ -229,6 +250,7 @@ void pa_source_output_unlink(pa_source_output*o) { o->attach = NULL; o->detach = NULL; o->suspend = NULL; + o->moved = NULL; if (linked) { pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); @@ -379,6 +401,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; pa_resampler *new_resampler = NULL; + pa_source_output_move_hook_data hook_data; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); @@ -415,13 +438,17 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->resample_method, - (o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0))) { + ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return -1; } } - pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], o); + hook_data.source_output = o; + hook_data.destination = dest; + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data); /* Okey, let's move it */ pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); @@ -447,6 +474,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source_update_status(origin); pa_source_update_status(dest); + if (o->moved) + o->moved(o); + pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o); pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name); -- cgit From 86b9ef8c961bed9d3a65f044741bb423c26d8005 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Feb 2008 22:13:44 +0000 Subject: deal with a possibly failing pa_channel_map_init_auto() correctly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2105 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/source-output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore/source-output.c') diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 576ddcf2..88c11469 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -97,7 +97,7 @@ pa_source_output* pa_source_output_new( if (data->source->channel_map.channels == data->sample_spec.channels) data->channel_map = data->source->channel_map; else - pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); + pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); } pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); -- cgit