Selaa lähdekoodia

obs-filters: Fix hard cross-lock when using ducking

jp9000 7 vuotta sitten
vanhempi
sitoutus
4eb5be4903
1 muutettua tiedostoa jossa 99 lisäystä ja 64 poistoa
  1. 99 64
      plugins/obs-filters/compressor-filter.c

+ 99 - 64
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,
 };