From 498d0d25af212569a5b77d3e5d1bbf37011f7592 Mon Sep 17 00:00:00 2001 From: Tarasov Aleksandr <55220741+arabianq@users.noreply.github.com> Date: Sun, 8 Mar 2026 00:36:08 +0300 Subject: [PATCH] perf: optimize `AudioPlayer::update` to avoid blocking the Tokio executor thread (#32) Offload synchronous `fs::File::open` and `Decoder::try_from` operations to `tokio::task::spawn_blocking` in `AudioPlayer::update`. This allows the Tokio runtime to process other asynchronous tasks concurrently without being blocked by file I/O operations and audio header decoding during looped playback. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- src/types/audio_player.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/types/audio_player.rs b/src/types/audio_player.rs index 3484cbe..143e648 100644 --- a/src/types/audio_player.rs +++ b/src/types/audio_player.rs @@ -374,13 +374,28 @@ impl AudioPlayer { } } + let mut restart_futures = vec![]; + for id in restarts { - if let Some(sound) = self.tracks.get_mut(&id) { - if let Ok(file) = fs::File::open(&sound.path) { - if let Ok(source) = Decoder::try_from(file) { - sound.sink.append(source); - sound.sink.play(); + if let Some(sound) = self.tracks.get(&id) { + let path = sound.path.clone(); + let handle = tokio::task::spawn_blocking(move || { + if let Ok(file) = fs::File::open(&path) { + if let Ok(source) = Decoder::try_from(file) { + return Some((id, source)); + } } + None + }); + restart_futures.push(handle); + } + } + + for handle in restart_futures { + if let Ok(Some((id, source))) = handle.await { + if let Some(sound) = self.tracks.get_mut(&id) { + sound.sink.append(source); + sound.sink.play(); } } }