diff options
author | Lyuma <xn.lyuma@gmail.com> | 2021-10-28 19:45:29 -0700 |
---|---|---|
committer | Lyuma <xn.lyuma@gmail.com> | 2021-10-28 19:45:29 -0700 |
commit | c088a2dd897de6c20ac8f5563700f3e455aa818b (patch) | |
tree | 2e334fbb2524374db3858fd23036c025fd4e1550 /scene/audio | |
parent | d3547be9ae8ae8bfbbece4757fc0759b712354a7 (diff) |
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
Diffstat (limited to 'scene/audio')
-rw-r--r-- | scene/audio/audio_stream_player.cpp | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 5065f21604..43c4ce4c82 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -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) { |