From 4eb5be4903008c7f1b0bb1e67bbb84bbee6aa7ae Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 22 Jan 2018 16:44:22 -0800 Subject: [PATCH] obs-filters: Fix hard cross-lock when using ducking --- plugins/obs-filters/compressor-filter.c | 163 ++++++++++++++---------- 1 file changed, 99 insertions(+), 64 deletions(-) diff --git a/plugins/obs-filters/compressor-filter.c b/plugins/obs-filters/compressor-filter.c index 234c80b13..821016b8c 100644 --- a/plugins/obs-filters/compressor-filter.c +++ b/plugins/obs-filters/compressor-filter.c @@ -72,14 +72,15 @@ struct compressor_data { float envelope; float slope; - char *sidechain_name; + pthread_mutex_t sidechain_update_mutex; + uint64_t sidechain_check_time; obs_weak_source_t *weak_sidechain; + char *sidechain_name; + pthread_mutex_t sidechain_mutex; struct circlebuf sidechain_data[MAX_AUDIO_CHANNELS]; float *sidechain_buf[MAX_AUDIO_CHANNELS]; size_t max_sidechain_frames; - - uint64_t sidechain_check_time; }; /* -------------------------------------------------------- */ @@ -181,55 +182,6 @@ unlock: pthread_mutex_unlock(&cd->sidechain_mutex); } -static inline void swap_sidechain(struct compressor_data *cd, const char *name) -{ - obs_source_t *sidechain = name && *name ? - obs_get_source_by_name(name) : NULL; - obs_weak_source_t *weak_sidechain = sidechain ? - obs_source_get_weak_source(sidechain) : NULL; - - obs_weak_source_t *cur_weak_sidechain = cd->weak_sidechain; - - if (cur_weak_sidechain != weak_sidechain) { - if (cur_weak_sidechain) { - obs_source_t *cur_sidechain = - obs_weak_source_get_source(cd->weak_sidechain); - - if (cur_sidechain) { - obs_source_remove_audio_capture_callback( - cur_sidechain, - sidechain_capture, cd); - obs_source_release(cur_sidechain); - } - - cd->weak_sidechain = NULL; - obs_weak_source_release(cur_weak_sidechain); - } - - if (weak_sidechain) { - obs_source_add_audio_capture_callback(sidechain, - sidechain_capture, cd); - cd->weak_sidechain = weak_sidechain; - - obs_source_t *parent = obs_filter_get_parent( - cd->context); - const char *parent_name = obs_source_get_name(parent); - - blog(LOG_INFO, "Source '%s' now has sidechain " - "compression from source '%s'", - parent_name, cd->sidechain_name); - } - } else if (weak_sidechain) { - obs_weak_source_release(weak_sidechain); - } - - cd->max_sidechain_frames = - cd->sample_rate * DEFAULT_AUDIO_BUF_MS / MS_IN_S; - - if (sidechain) - obs_source_release(sidechain); -} - static void compressor_update(void *data, obs_data_t *s) { struct compressor_data *cd = data; @@ -260,15 +212,51 @@ static void compressor_update(void *data, obs_data_t *s) bool valid_sidechain = *sidechain_name && strcmp(sidechain_name, "none") != 0; + obs_weak_source_t *old_weak_sidechain = NULL; - bfree(cd->sidechain_name); - cd->sidechain_name = valid_sidechain ? bstrdup(sidechain_name) : NULL; + pthread_mutex_lock(&cd->sidechain_update_mutex); + + if (!valid_sidechain) { + if (cd->weak_sidechain) { + old_weak_sidechain = cd->weak_sidechain; + cd->weak_sidechain = NULL; + } + + bfree(cd->sidechain_name); + cd->sidechain_name = NULL; + + } else { + if (!cd->sidechain_name || + strcmp(cd->sidechain_name, sidechain_name) != 0) { + if (cd->weak_sidechain) { + old_weak_sidechain = cd->weak_sidechain; + cd->weak_sidechain = NULL; + } + + bfree(cd->sidechain_name); + cd->sidechain_name = bstrdup(sidechain_name); + cd->sidechain_check_time = os_gettime_ns() - 3000000000; + } + } + + pthread_mutex_unlock(&cd->sidechain_update_mutex); + + if (old_weak_sidechain) { + obs_source_t *old_sidechain = + obs_weak_source_get_source(old_weak_sidechain); + + if (old_sidechain) { + obs_source_remove_audio_capture_callback(old_sidechain, + sidechain_capture, cd); + obs_source_release(old_sidechain); + } + + obs_weak_source_release(old_weak_sidechain); + } size_t sample_len = sample_rate * DEFAULT_AUDIO_BUF_MS / MS_IN_S; if (cd->envelope_buf_len == 0) resize_env_buffer(cd, sample_len); - - swap_sidechain(cd, sidechain_name); } static void *compressor_create(obs_data_t *settings, obs_source_t *filter) @@ -282,6 +270,13 @@ static void *compressor_create(obs_data_t *settings, obs_source_t *filter) return NULL; } + if (pthread_mutex_init(&cd->sidechain_update_mutex, NULL) != 0) { + pthread_mutex_destroy(&cd->sidechain_mutex); + blog(LOG_ERROR, "Failed to create mutex"); + bfree(cd); + return NULL; + } + compressor_update(cd, settings); return cd; } @@ -306,6 +301,7 @@ static void compressor_destroy(void *data) bfree(cd->sidechain_buf[i]); } pthread_mutex_destroy(&cd->sidechain_mutex); + pthread_mutex_destroy(&cd->sidechain_update_mutex); bfree(cd->sidechain_name); bfree(cd->envelope_buf); @@ -392,27 +388,65 @@ static inline void process_compression(const struct compressor_data *cd, } } -static struct obs_audio_data *compressor_filter_audio(void *data, - struct obs_audio_data *audio) +static void compressor_tick(void *data, float seconds) { struct compressor_data *cd = data; + char *new_name = NULL; - const uint32_t num_samples = audio->frames; - float **samples = (float**)audio->data; + pthread_mutex_lock(&cd->sidechain_update_mutex); if (cd->sidechain_name && !cd->weak_sidechain) { uint64_t t = os_gettime_ns(); if (t - cd->sidechain_check_time > 3000000000) { - swap_sidechain(cd, cd->sidechain_name); + new_name = bstrdup(cd->sidechain_name); cd->sidechain_check_time = t; } + } + + pthread_mutex_unlock(&cd->sidechain_update_mutex); + + if (new_name) { + obs_source_t *sidechain = new_name && *new_name ? + obs_get_source_by_name(new_name) : NULL; + obs_weak_source_t *weak_sidechain = sidechain ? + obs_source_get_weak_source(sidechain) : NULL; + + pthread_mutex_lock(&cd->sidechain_update_mutex); + + if (cd->sidechain_name && + strcmp(cd->sidechain_name, new_name) == 0) { + cd->weak_sidechain = weak_sidechain; + weak_sidechain = NULL; + } - if (!cd->weak_sidechain) - return audio; + pthread_mutex_unlock(&cd->sidechain_update_mutex); + + if (sidechain) { + obs_source_add_audio_capture_callback(sidechain, + sidechain_capture, cd); + + obs_weak_source_release(weak_sidechain); + obs_source_release(sidechain); + } + + bfree(new_name); } +} - if (cd->weak_sidechain) +static struct obs_audio_data *compressor_filter_audio(void *data, + struct obs_audio_data *audio) +{ + struct compressor_data *cd = data; + + const uint32_t num_samples = audio->frames; + float **samples = (float**)audio->data; + + pthread_mutex_lock(&cd->sidechain_update_mutex); + obs_weak_source_t *weak_sidechain = cd->weak_sidechain; + pthread_mutex_unlock(&cd->sidechain_update_mutex); + + if (weak_sidechain) analyze_sidechain(cd, num_samples); else analyze_envelope(cd, samples, num_samples); @@ -493,6 +527,7 @@ struct obs_source_info compressor_filter = { .destroy = compressor_destroy, .update = compressor_update, .filter_audio = compressor_filter_audio, + .video_tick = compressor_tick, .get_defaults = compressor_defaults, .get_properties = compressor_properties, }; -- GitLab