Browse Source

Merge pull request #55846 from ellenhp/fix_ogg_edge_cases

Fix ogg edge cases
Rémi Verschelde 3 years ago
parent
commit
d1dac8427a

+ 3 - 1
modules/minimp3/audio_stream_mp3.cpp

@@ -38,7 +38,9 @@
 #include "core/io/file_access.h"
 #include "core/io/file_access.h"
 
 
 int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
-	ERR_FAIL_COND_V(!active, 0);
+	if (!active) {
+		return 0;
+	}
 
 
 	int todo = p_frames;
 	int todo = p_frames;
 
 

+ 7 - 10
modules/vorbis/audio_stream_ogg_vorbis.cpp

@@ -36,23 +36,22 @@
 
 
 int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
 	ERR_FAIL_COND_V(!ready, 0);
 	ERR_FAIL_COND_V(!ready, 0);
-	ERR_FAIL_COND_V(!active, 0);
+
+	if (!active) {
+		return 0;
+	}
 
 
 	int todo = p_frames;
 	int todo = p_frames;
 
 
 	int start_buffer = 0;
 	int start_buffer = 0;
 
 
-	int frames_mixed_this_step = p_frames;
-
-	while (todo && active) {
+	while (todo > 0 && active) {
 		AudioFrame *buffer = p_buffer;
 		AudioFrame *buffer = p_buffer;
 		if (start_buffer > 0) {
 		if (start_buffer > 0) {
 			buffer = buffer + start_buffer;
 			buffer = buffer + start_buffer;
 		}
 		}
 		int mixed = _mix_frames_vorbis(buffer, todo);
 		int mixed = _mix_frames_vorbis(buffer, todo);
-		if (mixed < 0) {
-			return 0;
-		}
+		ERR_FAIL_COND_V(mixed < 0, 0);
 		todo -= mixed;
 		todo -= mixed;
 		frames_mixed += mixed;
 		frames_mixed += mixed;
 		start_buffer += mixed;
 		start_buffer += mixed;
@@ -67,16 +66,14 @@ int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram
 				// we still have buffer to fill, start from this element in the next iteration.
 				// we still have buffer to fill, start from this element in the next iteration.
 				start_buffer = p_frames - todo;
 				start_buffer = p_frames - todo;
 			} else {
 			} else {
-				frames_mixed_this_step = p_frames - todo;
 				for (int i = p_frames - todo; i < p_frames; i++) {
 				for (int i = p_frames - todo; i < p_frames; i++) {
 					p_buffer[i] = AudioFrame(0, 0);
 					p_buffer[i] = AudioFrame(0, 0);
 				}
 				}
 				active = false;
 				active = false;
-				todo = 0;
 			}
 			}
 		}
 		}
 	}
 	}
-	return frames_mixed_this_step;
+	return p_frames - todo;
 }
 }
 
 
 int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) {
 int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) {

+ 13 - 16
servers/audio/audio_stream.cpp

@@ -135,9 +135,10 @@ int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 
 
 	uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale * playback_speed_scale) / double(target_rate)) * double(FP_LEN));
 	uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale * playback_speed_scale) / double(target_rate)) * double(FP_LEN));
 
 
-	int mixed_frames_total = p_frames;
+	int mixed_frames_total = -1;
 
 
-	for (int i = 0; i < p_frames; i++) {
+	int i;
+	for (i = 0; i < p_frames; i++) {
 		uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
 		uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
 		//standard cubic interpolation (great quality/performance ratio)
 		//standard cubic interpolation (great quality/performance ratio)
 		//this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory.
 		//this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory.
@@ -147,7 +148,7 @@ int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 		AudioFrame y2 = internal_buffer[idx - 1];
 		AudioFrame y2 = internal_buffer[idx - 1];
 		AudioFrame y3 = internal_buffer[idx - 0];
 		AudioFrame y3 = internal_buffer[idx - 0];
 
 
-		if (idx <= internal_buffer_end && idx >= internal_buffer_end && mixed_frames_total == p_frames) {
+		if (idx >= internal_buffer_end && mixed_frames_total == -1) {
 			// The internal buffer ends somewhere in this range, and we haven't yet recorded the number of good frames we have.
 			// The internal buffer ends somewhere in this range, and we haven't yet recorded the number of good frames we have.
 			mixed_frames_total = i;
 			mixed_frames_total = i;
 		}
 		}
@@ -167,24 +168,20 @@ int AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
 			internal_buffer[1] = internal_buffer[INTERNAL_BUFFER_LEN + 1];
 			internal_buffer[1] = internal_buffer[INTERNAL_BUFFER_LEN + 1];
 			internal_buffer[2] = internal_buffer[INTERNAL_BUFFER_LEN + 2];
 			internal_buffer[2] = internal_buffer[INTERNAL_BUFFER_LEN + 2];
 			internal_buffer[3] = internal_buffer[INTERNAL_BUFFER_LEN + 3];
 			internal_buffer[3] = internal_buffer[INTERNAL_BUFFER_LEN + 3];
-			if (is_playing()) {
-				int mixed_frames = _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
-				if (mixed_frames != INTERNAL_BUFFER_LEN) {
-					// internal_buffer[mixed_frames] is the first frame of silence.
-					internal_buffer_end = mixed_frames;
-				} else {
-					// The internal buffer does not contain the first frame of silence.
-					internal_buffer_end = -1;
-				}
+			int mixed_frames = _mix_internal(internal_buffer + 4, INTERNAL_BUFFER_LEN);
+			if (mixed_frames != INTERNAL_BUFFER_LEN) {
+				// internal_buffer[mixed_frames] is the first frame of silence.
+				internal_buffer_end = mixed_frames;
 			} else {
 			} else {
-				//fill with silence, not playing
-				for (int j = 0; j < INTERNAL_BUFFER_LEN; ++j) {
-					internal_buffer[j + 4] = AudioFrame(0, 0);
-				}
+				// The internal buffer does not contain the first frame of silence.
+				internal_buffer_end = -1;
 			}
 			}
 			mix_offset -= (INTERNAL_BUFFER_LEN << FP_BITS);
 			mix_offset -= (INTERNAL_BUFFER_LEN << FP_BITS);
 		}
 		}
 	}
 	}
+	if (mixed_frames_total == -1 && i == p_frames) {
+		mixed_frames_total = p_frames;
+	}
 	return mixed_frames_total;
 	return mixed_frames_total;
 }
 }