diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index 9b51956ae..82cbd9659 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -239,6 +239,7 @@ static void scene_destroy(void *data) pthread_mutex_destroy(&scene->video_mutex); pthread_mutex_destroy(&scene->audio_mutex); + da_free(scene->mix_sources); bfree(scene); } @@ -1527,9 +1528,11 @@ static bool scene_audio_render(void *data, uint64_t *ts_out, item = scene->first_item; while (item) { uint64_t source_ts; - size_t pos, count; + size_t pos; bool apply_buf; struct obs_source *source; + struct scene_source_mix *source_mix = NULL; + if (item->visible && transition_active(item->show_transition)) source = item->show_transition; else if (!item->visible && @@ -1560,15 +1563,64 @@ static bool scene_audio_render(void *data, uint64_t *ts_out, continue; } - count = AUDIO_OUTPUT_FRAMES - pos; - if (!apply_buf && !item->visible && !transition_active(item->hide_transition)) { item = item->next; continue; } - obs_source_get_audio_mix(source, &child_audio); + for (size_t i = 0; i < scene->mix_sources.num; i++) { + struct scene_source_mix *mix = + &scene->mix_sources.array[i]; + if (mix->source == item->source) { + source_mix = mix; + break; + } + } + + if (!source_mix) { + source_mix = da_push_back_new(scene->mix_sources); + source_mix->source = item->source; + source_mix->transition = source != item->source ? source + : NULL; + source_mix->apply_buf = apply_buf; + source_mix->pos = pos; + source_mix->count = AUDIO_OUTPUT_FRAMES - pos; + if (apply_buf) { + memcpy(source_mix->buf, buf, + sizeof(float) * source_mix->count); + } + } else { + /* Only transition audio if there are no + * non-transitioning scene items. */ + if (source_mix->transition && source == item->source) + source_mix->transition = NULL; + /* Only apply buf to mix if all scene items for this + * source require it. */ + source_mix->apply_buf = source_mix->apply_buf && + apply_buf; + /* Update buf so that only highest value across all + * items is used. */ + if (source_mix->apply_buf && + memcmp(source_mix->buf, buf, + source_mix->count * sizeof(float)) != 0) { + for (size_t i = 0; i < source_mix->count; i++) { + if (buf[i] > source_mix->buf[i]) + source_mix->buf[i] = buf[i]; + } + } + } + + item = item->next; + } + + for (size_t i = 0; i < scene->mix_sources.num; i++) { + struct scene_source_mix *source_mix = + &scene->mix_sources.array[i]; + obs_source_get_audio_mix(source_mix->transition + ? source_mix->transition + : source_mix->source, + &child_audio); for (size_t mix = 0; mix < MAX_AUDIO_MIXES; mix++) { if ((mixers & (1 << mix)) == 0) @@ -1578,17 +1630,20 @@ static bool scene_audio_render(void *data, uint64_t *ts_out, float *out = audio_output->output[mix].data[ch]; float *in = child_audio.output[mix].data[ch]; - if (apply_buf) - mix_audio_with_buf(out, in, buf, pos, - count); + if (source_mix->apply_buf) + mix_audio_with_buf(out, in, + source_mix->buf, + source_mix->pos, + source_mix->count); else - mix_audio(out, in, pos, count); + mix_audio(out, in, source_mix->pos, + source_mix->count); } } - - item = item->next; } + da_clear(scene->mix_sources); + *ts_out = timestamp; audio_unlock(scene); diff --git a/libobs/obs-scene.h b/libobs/obs-scene.h index 1efdfc08a..d78e96ad7 100644 --- a/libobs/obs-scene.h +++ b/libobs/obs-scene.h @@ -93,6 +93,15 @@ struct obs_scene_item { struct obs_scene_item *next; }; +struct scene_source_mix { + obs_source_t *source; + obs_source_t *transition; + size_t pos; + size_t count; + bool apply_buf; + float buf[AUDIO_OUTPUT_FRAMES]; +}; + struct obs_scene { struct obs_source *source; @@ -106,4 +115,6 @@ struct obs_scene { pthread_mutex_t video_mutex; pthread_mutex_t audio_mutex; struct obs_scene_item *first_item; + + DARRAY(struct scene_source_mix) mix_sources; };