Fix crash due to reentrancy in AudioStreamPlayer* finished signal.

This crash occurred when an audio stream finished playing in NOTIFICATION_INTERNAL_PROCESS,
during which it would iterate through a loop of playbacks,
leading to a "finished" signal, which removed the audio player from the tree
which led to a NOTIFICATION_EXIT_TREE,
which would mutate the array of playbacks while within the above loop.

This moves the signal callback outside of the loop which avoids the crash.
Note: previously, the signal was called multiple times if the same player finishes multiple times in one frame. Now it is at most once per frame.

Affects AudioStreamPlayer, AudioStreamPlayer2D and AudioStreamPlayer3D
This commit is contained in:
Lyuma 2021-10-28 19:45:29 -07:00
parent d3547be9ae
commit c088a2dd89
3 changed files with 9 additions and 3 deletions

View file

@ -78,7 +78,6 @@ void AudioStreamPlayer2D::_notification(int p_what) {
Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
emit_signal(SNAME("finished"));
playbacks_to_remove.push_back(playback);
}
}
@ -91,6 +90,9 @@ void AudioStreamPlayer2D::_notification(int p_what) {
active.clear();
set_physics_process_internal(false);
}
if (!playbacks_to_remove.is_empty()) {
emit_signal(SNAME("finished"));
}
}
while (stream_playbacks.size() > max_polyphony) {

View file

@ -292,7 +292,6 @@ void AudioStreamPlayer3D::_notification(int p_what) {
Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
emit_signal(SNAME("finished"));
playbacks_to_remove.push_back(playback);
}
}
@ -305,6 +304,9 @@ void AudioStreamPlayer3D::_notification(int p_what) {
active.clear();
set_physics_process_internal(false);
}
if (!playbacks_to_remove.is_empty()) {
emit_signal(SNAME("finished"));
}
}
while (stream_playbacks.size() > max_polyphony) {

View file

@ -45,7 +45,6 @@ void AudioStreamPlayer::_notification(int p_what) {
Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
emit_signal(SNAME("finished"));
playbacks_to_remove.push_back(playback);
}
}
@ -58,6 +57,9 @@ void AudioStreamPlayer::_notification(int p_what) {
active.clear();
set_process_internal(false);
}
if (!playbacks_to_remove.is_empty()) {
emit_signal(SNAME("finished"));
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {