summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/sink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore/sink.c')
-rw-r--r--src/pulsecore/sink.c106
1 files changed, 28 insertions, 78 deletions
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 48c50b0b..bda92fcc 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -778,7 +778,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns
/* Called from IO thread context */
static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
pa_sink_input *i;
- void *state = NULL;
+ void *state;
unsigned p = 0;
unsigned n_unreffed = 0;
@@ -790,7 +790,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *
/* We optimize for the case where the order of the inputs has not changed */
- while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
+ PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
unsigned j;
pa_mix_info* m = NULL;
@@ -884,8 +884,6 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
pa_assert(pa_frame_aligned(length, &s->sample_spec));
pa_assert(result);
- pa_sink_ref(s);
-
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
@@ -896,6 +894,8 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
return;
}
+ pa_sink_ref(s);
+
if (length <= 0)
length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
@@ -973,8 +973,6 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_assert(target->length > 0);
pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
- pa_sink_ref(s);
-
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
@@ -983,6 +981,8 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
return;
}
+ pa_sink_ref(s);
+
length = target->length;
block_size_max = pa_mempool_block_size_max(s->core->mempool);
if (length > block_size_max)
@@ -1057,11 +1057,16 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
pa_assert(target->length > 0);
pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
- pa_sink_ref(s);
-
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
+ if (s->thread_info.state == PA_SINK_SUSPENDED) {
+ pa_silence_memchunk(target, &s->sample_spec);
+ return;
+ }
+
+ pa_sink_ref(s);
+
l = target->length;
d = 0;
while (l > 0) {
@@ -1080,10 +1085,6 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
/* Called from IO thread context */
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
- pa_mix_info info[MAX_MIX_CHANNELS];
- size_t length1st = length;
- unsigned n;
-
pa_sink_assert_ref(s);
pa_sink_assert_io_context(s);
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
@@ -1091,81 +1092,24 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
pa_assert(pa_frame_aligned(length, &s->sample_spec));
pa_assert(result);
- pa_sink_ref(s);
-
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
- pa_assert(length > 0);
-
- n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS);
-
- if (n == 0) {
- pa_silence_memchunk_get(&s->core->silence_cache,
- s->core->mempool,
- result,
- &s->sample_spec,
- length1st);
- } else if (n == 1) {
- pa_cvolume volume;
-
- *result = info[0].chunk;
- pa_memblock_ref(result->memblock);
-
- if (result->length > length)
- result->length = length;
-
- pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
-
- if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
- if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
- pa_memblock_unref(result->memblock);
- pa_silence_memchunk_get(&s->core->silence_cache,
- s->core->mempool,
- result,
- &s->sample_spec,
- result->length);
- } else {
- pa_memchunk_make_writable(result, length);
- pa_volume_memchunk(result, &s->sample_spec, &volume);
- }
- }
- } else {
- void *ptr;
-
- result->index = 0;
- result->memblock = pa_memblock_new(s->core->mempool, length);
-
- ptr = pa_memblock_acquire(result->memblock);
-
- result->length = pa_mix(info, n,
- (uint8_t*) ptr + result->index, length1st,
- &s->sample_spec,
- &s->thread_info.soft_volume,
- s->thread_info.soft_muted);
-
- pa_memblock_release(result->memblock);
- }
+ pa_sink_ref(s);
- inputs_drop(s, info, n, result);
+ pa_sink_render(s, length, result);
if (result->length < length) {
pa_memchunk chunk;
- size_t l, d;
+
pa_memchunk_make_writable(result, length);
- l = length - result->length;
- d = result->index + result->length;
- while (l > 0) {
- chunk = *result;
- chunk.index = d;
- chunk.length = l;
+ chunk.memblock = result->memblock;
+ chunk.index = result->index + result->length;
+ chunk.length = length - result->length;
- pa_sink_render_into(s, &chunk);
+ pa_sink_render_into_full(s, &chunk);
- d += chunk.length;
- l -= chunk.length;
- }
result->length = length;
}
@@ -1408,8 +1352,11 @@ void pa_sink_set_volume(
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(!volume || pa_cvolume_valid(volume));
- pa_assert(!volume || pa_cvolume_compatible(volume, &s->sample_spec));
pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME));
+ pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
+
+ /* As a special exception we accept mono volumes on all sinks --
+ * even on those with more complex channel maps */
/* If volume is NULL we synchronize the sink's real and reference
* volumes with the stream volumes. If it is not NULL we update
@@ -1419,7 +1366,10 @@ void pa_sink_set_volume(
if (volume) {
- s->reference_volume = *volume;
+ if (pa_cvolume_compatible(volume, &s->sample_spec))
+ s->reference_volume = *volume;
+ else
+ pa_cvolume_scale(&s->reference_volume, pa_cvolume_max(volume));
if (s->flags & PA_SINK_FLAT_VOLUME) {
/* OK, propagate this volume change back to the inputs */