mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-31 07:11:14 -04:00
modules: implement mixing in combine stream
When the combine-stream module is used as a source and the input streams are overlapping, mix the samples instead of overwriting the previous samples. See #3710
This commit is contained in:
parent
b46673b475
commit
fc3d7cf7c7
1 changed files with 45 additions and 2 deletions
|
|
@ -391,6 +391,40 @@ static void ringbuffer_memcpy(struct ringbuffer *r, void *dst, void *src, uint32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mix_f32(float *dst, float *src, uint32_t size)
|
||||||
|
{
|
||||||
|
uint32_t i, s = size / sizeof(float);
|
||||||
|
for (i = 0; i < s; i++)
|
||||||
|
dst[i] += src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ringbuffer_mix(struct ringbuffer *r, void *dst, void *src, uint32_t size)
|
||||||
|
{
|
||||||
|
uint32_t avail;
|
||||||
|
|
||||||
|
avail = SPA_MIN(size, r->size);
|
||||||
|
|
||||||
|
/* buf to dst */
|
||||||
|
if (dst && avail > 0) {
|
||||||
|
uint32_t l0 = SPA_MIN(avail, r->size - r->idx), l1 = avail - l0;
|
||||||
|
mix_f32(dst, SPA_PTROFF(r->buf, r->idx, void), l0);
|
||||||
|
if (SPA_UNLIKELY(l1 > 0))
|
||||||
|
mix_f32(SPA_PTROFF(dst, l0, void), r->buf, l1);
|
||||||
|
dst = SPA_PTROFF(dst, avail, void);
|
||||||
|
}
|
||||||
|
/* src to dst */
|
||||||
|
if (size > avail) {
|
||||||
|
if (dst)
|
||||||
|
mix_f32(dst, src, size - avail);
|
||||||
|
src = SPA_PTROFF(src, size - avail, void);
|
||||||
|
}
|
||||||
|
/* src to buf */
|
||||||
|
if (avail > 0) {
|
||||||
|
spa_ringbuffer_write_data(NULL, r->buf, r->size, r->idx, src, avail);
|
||||||
|
r->idx = (r->idx + avail) % r->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ringbuffer_copy(struct ringbuffer *dst, struct ringbuffer *src)
|
static void ringbuffer_copy(struct ringbuffer *dst, struct ringbuffer *src)
|
||||||
{
|
{
|
||||||
uint32_t l0, l1;
|
uint32_t l0, l1;
|
||||||
|
|
@ -1172,11 +1206,14 @@ static void combine_output_process(void *d)
|
||||||
struct pw_buffer *in, *out;
|
struct pw_buffer *in, *out;
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
bool delay_changed = false;
|
bool delay_changed = false;
|
||||||
|
bool mix[SPA_AUDIO_MAX_CHANNELS];
|
||||||
|
|
||||||
if ((out = pw_stream_dequeue_buffer(impl->combine)) == NULL) {
|
if ((out = pw_stream_dequeue_buffer(impl->combine)) == NULL) {
|
||||||
pw_log_debug("%p: out of output buffers: %m", impl);
|
pw_log_debug("%p: out of output buffers: %m", impl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
for (uint32_t i = 0; i < out->buffer->n_datas; i++)
|
||||||
|
mix[i] = false;
|
||||||
|
|
||||||
spa_list_for_each(s, &impl->streams, link) {
|
spa_list_for_each(s, &impl->streams, link) {
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
|
|
@ -1220,8 +1257,14 @@ static void combine_output_process(void *d)
|
||||||
size = SPA_MIN(ds->chunk->size, ds->maxsize - offs);
|
size = SPA_MIN(ds->chunk->size, ds->maxsize - offs);
|
||||||
size = SPA_MIN(size, dd->maxsize);
|
size = SPA_MIN(size, dd->maxsize);
|
||||||
|
|
||||||
ringbuffer_memcpy(&s->delay[j],
|
if (mix[remap]) {
|
||||||
dd->data, SPA_PTROFF(ds->data, offs, void), size);
|
ringbuffer_mix(&s->delay[j],
|
||||||
|
dd->data, SPA_PTROFF(ds->data, offs, void), size);
|
||||||
|
} else {
|
||||||
|
ringbuffer_memcpy(&s->delay[j],
|
||||||
|
dd->data, SPA_PTROFF(ds->data, offs, void), size);
|
||||||
|
mix[remap] = true;
|
||||||
|
}
|
||||||
|
|
||||||
outsize = SPA_MAX(outsize, size);
|
outsize = SPA_MAX(outsize, size);
|
||||||
stride = SPA_MAX(stride, ds->chunk->stride);
|
stride = SPA_MAX(stride, ds->chunk->stride);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue