From 7cfcbf26cc988e2b8ca63c0de87ab1c941970e38 Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Tue, 28 Jul 2026 00:19:30 -0400 Subject: [PATCH] Fixed loading multiple songs issue. --- Harmonia.Core/Engine/BassAudioEngine.cs | 48 ++++++++++++++++++------- Harmonia.Core/Player/AudioPlayer.cs | 9 +++++ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/Harmonia.Core/Engine/BassAudioEngine.cs b/Harmonia.Core/Engine/BassAudioEngine.cs index 7e161b6..6955fa3 100644 --- a/Harmonia.Core/Engine/BassAudioEngine.cs +++ b/Harmonia.Core/Engine/BassAudioEngine.cs @@ -6,6 +6,7 @@ namespace Harmonia.Core.Engine; public class BassAudioEngine : IAudioEngine, IDisposable { private readonly BaseMediaPlayer _mediaPlayer; + private readonly SemaphoreSlim _loadLock = new(1, 1); private CancellationTokenSource? _cancellationTokenSource; @@ -136,27 +137,48 @@ public class BassAudioEngine : IAudioEngine, IDisposable private async Task LoadWaveSourceAsync(string fileName) { _cancellationTokenSource?.Cancel(); - _cancellationTokenSource = new CancellationTokenSource(); - CancellationToken token = _cancellationTokenSource.Token; + CancellationTokenSource cancellationTokenSource = new(); + _cancellationTokenSource = cancellationTokenSource; + + CancellationToken token = cancellationTokenSource.Token; + + // Serialize loads so overlapping MediaPlayer.LoadAsync calls can't + // race and leave orphaned streams playing. + await _loadLock.WaitAsync(CancellationToken.None); try - { - await _mediaPlayer.LoadAsync(fileName); - } - catch (Exception ex) { if (token.IsCancellationRequested) return false; - //return new Result(State.Exception, ex.Message); - throw new Exception("An error occurred - " + fileName, ex); + try + { + await _mediaPlayer.LoadAsync(fileName); + } + catch (Exception ex) + { + if (token.IsCancellationRequested) + return false; + + //return new Result(State.Exception, ex.Message); + throw new Exception("An error occurred - " + fileName, ex); + } + + if (token.IsCancellationRequested) + { + // A newer load superseded this one; make sure this stream + // doesn't keep playing in the background. + _mediaPlayer.Stop(); + return false; + } + + return true; + } + finally + { + _loadLock.Release(); } - - if (token.IsCancellationRequested) - return false; - - return true; } private void UpdateSource(string fileName) diff --git a/Harmonia.Core/Player/AudioPlayer.cs b/Harmonia.Core/Player/AudioPlayer.cs index 0ce870c..0643310 100644 --- a/Harmonia.Core/Player/AudioPlayer.cs +++ b/Harmonia.Core/Player/AudioPlayer.cs @@ -9,6 +9,8 @@ public class AudioPlayer : IAudioPlayer private readonly IAudioEngine _audioEngine; private readonly IPlaylistManager _playlistManager; + private int _loadVersion; + private Playlist? _playlist; public Playlist? Playlist { @@ -241,8 +243,15 @@ public class AudioPlayer : IAudioPlayer CurrentPlaylistSong = song; + int loadVersion = Interlocked.Increment(ref _loadVersion); + bool isLoaded = await TryLoadAsync(song); + // A newer load request was started while this one was in flight; + // abandon this one so only the latest request controls playback. + if (loadVersion != Volatile.Read(ref _loadVersion)) + return false; + if (isLoaded == false) { if (mode == PlaybackMode.LoadAndPlay)