diff --git a/Harmonia.Core/Player/AudioPlayer.cs b/Harmonia.Core/Player/AudioPlayer.cs index afb6918..3820ec6 100644 --- a/Harmonia.Core/Player/AudioPlayer.cs +++ b/Harmonia.Core/Player/AudioPlayer.cs @@ -1,8 +1,6 @@ using Harmonia.Core.Engine; using Harmonia.Core.Playlists; -using System; using System.ComponentModel; -using System.Reflection; namespace Harmonia.Core.Player; @@ -18,13 +16,15 @@ public class AudioPlayer : IAudioPlayer { return _playlist; } - private set + protected set { _playlist = value; NotifyPropertyChanged(nameof(Playlist)); } } + protected PlaylistSong? CurrentPlaylistSong { get; set; } + private PlaylistSong? _playingSong; public PlaylistSong? PlayingSong { @@ -32,7 +32,7 @@ public class AudioPlayer : IAudioPlayer { return _playingSong; } - private set + protected set { _playingSong = value; NotifyPropertyChanged(nameof(PlayingSong)); @@ -126,16 +126,13 @@ public class AudioPlayer : IAudioPlayer { if (RepeatState == RepeatState.RepeatOne) { - // Alternative: Set the position to 0 and play again - if (PlayingSong != null) - { - await LoadAsync(PlayingSong, PlaybackMode.LoadAndPlay); - } - - return; + Position = 0; + Play(); + } + else + { + await NextAsync(); } - - await NextAsync(); } private void OnMusicEngineStateChanged(object? sender, PlaybackStateChangedEventArgs e) @@ -160,7 +157,7 @@ public class AudioPlayer : IAudioPlayer public async Task NextAsync() { - if (Playlist == null || PlayingSong == null || Playlist.Songs.Count == 0) + if (Playlist == null || CurrentPlaylistSong == null || Playlist.Songs.Count == 0) return; if (IsRandom) @@ -170,7 +167,7 @@ public class AudioPlayer : IAudioPlayer return; } - int currentIndex = Playlist.Songs.IndexOf(PlayingSong); + int currentIndex = Playlist.Songs.IndexOf(CurrentPlaylistSong); int nextIndex = currentIndex + 1; if (nextIndex > Playlist.Songs.Count - 1) @@ -188,7 +185,7 @@ public class AudioPlayer : IAudioPlayer public async Task PreviousAsync() { - if (Playlist == null || PlayingSong == null) + if (Playlist == null || CurrentPlaylistSong == null || Playlist.Songs.Count == 0) return; if (Position > PreviousSongSecondsThreshold) @@ -197,12 +194,12 @@ public class AudioPlayer : IAudioPlayer return; } - int currentIndex = Playlist.Songs.IndexOf(PlayingSong); + int currentIndex = Playlist.Songs.IndexOf(CurrentPlaylistSong); int nextIndex = currentIndex - 1; if (nextIndex < 0) { - if (RepeatState == RepeatState.RepeatAll && Playlist.Songs.Count > 0) + if (RepeatState == RepeatState.RepeatAll) { await LoadAsync(Playlist.Songs.Count - 1); return; @@ -241,6 +238,8 @@ public class AudioPlayer : IAudioPlayer Playlist = newPlaylist; } + CurrentPlaylistSong = song; + bool isLoaded = await TryLoadAsync(song); if (isLoaded == false) diff --git a/Harmonia.Tests/AudioPlayerTests.cs b/Harmonia.Tests/AudioPlayerTests.cs index f108b60..e462b22 100644 --- a/Harmonia.Tests/AudioPlayerTests.cs +++ b/Harmonia.Tests/AudioPlayerTests.cs @@ -8,12 +8,32 @@ using Shouldly; namespace Harmonia.Tests; +public class TestAudioPlayer(IAudioEngine audioEngine, IPlaylistRepository playlistRepository) + : AudioPlayer(audioEngine, playlistRepository) +{ + internal void SetPlaylist(Playlist playlist) + { + Playlist = playlist; + } + + internal int GetPlayingSongIndex() + { + if (Playlist == null) + return -1; + + if (PlayingSong == null) + return -1; + + return Playlist.Songs.IndexOf(PlayingSong); + } +} + public class AudioPlayerTests { private readonly IAudioEngine _audioEngine; private readonly IPlaylistRepository _playlistRepository; private readonly PlaylistSong[] _playlistSongs; - private readonly IAudioPlayer _audioPlayer; + private readonly TestAudioPlayer _audioPlayer; public AudioPlayerTests() { @@ -50,57 +70,76 @@ public class AudioPlayerTests _playlistRepository.Get().Returns([playlist]); //_playlistRepository.GetPlaylist(_playlistSongs[0]).Returns(playlist); - _audioPlayer = new AudioPlayer(_audioEngine, _playlistRepository); + _audioPlayer = new TestAudioPlayer(_audioEngine, _playlistRepository); + _audioPlayer.SetPlaylist(playlist); + //await _audioPlayer.LoadAsync(_playlistSongs[0], PlaybackMode.LoadOnly); } - [Fact] - public async Task Load_Song_Success() + [Theory] + [InlineData(0, true)] + [InlineData(1, false)] + [InlineData(2, true)] + [InlineData(3, false)] + [InlineData(4, false)] + [InlineData(5, true)] + [InlineData(6, true)] + [InlineData(7, false)] + public async Task Load_Song(int index, bool expectedResult) { - (await _audioPlayer.LoadAsync(_playlistSongs[0], PlaybackMode.LoadAndPlay)).ShouldBe(true); + bool result = await _audioPlayer.LoadAsync(index); + result.ShouldBe(expectedResult); } - [Fact] - public async Task Load_Song_Failure() + [Theory] + [InlineData(0, 2)] + [InlineData(2, 5)] + [InlineData(5, 6)] + [InlineData(6, 0)] + public async Task Load_Next_Song(int index, int expectedResult) { - (await _audioPlayer.LoadAsync(_playlistSongs[1], PlaybackMode.LoadAndPlay)).ShouldBe(false); - } - - [Fact] - public async Task Load_Song_Failure_With_Exception() - { - (await _audioPlayer.LoadAsync(_playlistSongs[3], PlaybackMode.LoadAndPlay)).ShouldBe(false); - } - - [Fact] - public async Task Load_Next_Song_Success() - { - await _audioPlayer.LoadAsync(_playlistSongs[5], PlaybackMode.LoadAndPlay); + await _audioPlayer.LoadAsync(index); await _audioPlayer.NextAsync(); - _audioPlayer.PlayingSong.ShouldBe(_playlistSongs[6]); + int currentIndex = _audioPlayer.GetPlayingSongIndex(); + + currentIndex.ShouldBe(expectedResult); } - [Fact] - public async Task Load_Next_Song_Failure() + [Theory] + [InlineData(0, 0, RepeatState.Off, 0)] + [InlineData(0, 6, RepeatState.RepeatAll, 0)] + [InlineData(6, 5, RepeatState.Off, 0)] + [InlineData(6, 6, RepeatState.Off, 6)] + public async Task Load_Previous_Song(int index, int expectedResult, RepeatState repeatState = RepeatState.Off, double position = 0) { - await _audioPlayer.LoadAsync(_playlistSongs[0], PlaybackMode.LoadAndPlay); - await _audioPlayer.NextAsync(); + await _audioPlayer.LoadAsync(index, PlaybackMode.LoadAndPlay); + _audioPlayer.RepeatState = repeatState; + _audioPlayer.Position = position; - _audioPlayer.PlayingSong.ShouldBe(_playlistSongs[2]); + await _audioPlayer.PreviousAsync(); + + int currentIndex = _audioPlayer.GetPlayingSongIndex(); + + currentIndex.ShouldBe(expectedResult); } - [Fact] - public async Task Load_Next_Song_From_Last_Song() + [Theory] + [InlineData(0, 2, RepeatState.Off)] + [InlineData(0, 0, RepeatState.RepeatOne)] + public async Task Song_Finshed(int index, int expectedResult, RepeatState repeatState = RepeatState.Off) { - await _audioPlayer.LoadAsync(_playlistSongs[6], PlaybackMode.LoadAndPlay); - await _audioPlayer.NextAsync(); + await _audioPlayer.LoadAsync(index, PlaybackMode.LoadAndPlay); + _audioPlayer.RepeatState = repeatState; - _audioPlayer.PlayingSong.ShouldBe(_playlistSongs[0]); - } + TaskCompletionSource taskCompletionSource = new(); - [Fact] - public void Random_Test() - { - _audioPlayer.IsRandom.ShouldBeFalse(); + _audioEngine.StreamFinished += (sender, eventArgs) => { taskCompletionSource.SetResult(true); }; + _audioEngine.StreamFinished += Raise.EventWith(_audioEngine, new()); + + await taskCompletionSource.Task; + + int currentIndex = _audioPlayer.GetPlayingSongIndex(); + + currentIndex.ShouldBe(expectedResult); } } \ No newline at end of file