Initial commit
This commit is contained in:
14
TechMedia.Core/Backend/IAudioBackend.cs
Normal file
14
TechMedia.Core/Backend/IAudioBackend.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using TechMedia.Core.Model;
|
||||
|
||||
namespace TechMedia.Core.Backend;
|
||||
|
||||
public interface IAudioBackend
|
||||
{
|
||||
public void JustPlay();
|
||||
public void PlayFile(string filename);
|
||||
public void StopPlayback();
|
||||
public Task<Track?> GetFileMetadata(string filename);
|
||||
public void RegisterTrackEndHandler(EventHandler<EventArgs> onEndReached);
|
||||
void RegisterProgressWatcher(IProgress<float> reporter);
|
||||
void RemoveProgressWatcher(IProgress<float> reporter);
|
||||
}
|
||||
10
TechMedia.Core/Backend/ProgressListener.cs
Normal file
10
TechMedia.Core/Backend/ProgressListener.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace TechMedia.Core.Backend;
|
||||
|
||||
public class ProgressListener
|
||||
{
|
||||
private readonly IProgress<float> _reporter;
|
||||
public ProgressListener(IProgress<float> reporter)
|
||||
{
|
||||
_reporter = reporter;
|
||||
}
|
||||
}
|
||||
22
TechMedia.Core/ITechMediaCore.cs
Normal file
22
TechMedia.Core/ITechMediaCore.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using TechMedia.Core.Model;
|
||||
|
||||
namespace TechMedia.Core;
|
||||
|
||||
public interface ITechMediaCore
|
||||
{
|
||||
public void Play();
|
||||
public void StartPlaylistPlayback(IProgress<Track>? trackReporter = null, IProgress<float>? progressReporter = null);
|
||||
public void Stop();
|
||||
public void Pause();
|
||||
public void NextTrack();
|
||||
public void PreviousTrack();
|
||||
public void GetNextTrackInfo();
|
||||
public void GetCurrentTrackInfo();
|
||||
public void OpenMediaFile(string filename);
|
||||
public void OpenPlaylistFile();
|
||||
public Task<int> LoadFiles(List<string> files, IProgress<int>? progress = null);
|
||||
public List<Track> ShuffleCurrentPlaylist();
|
||||
public List<Track> GetCurrentPlaylist();
|
||||
public void RegisterPlaylistChangeListener(IProgress<List<Track>> playlistWatcher);
|
||||
public Track? SubmitRequest(string filename);
|
||||
}
|
||||
11
TechMedia.Core/Model/Track.cs
Normal file
11
TechMedia.Core/Model/Track.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace TechMedia.Core.Model;
|
||||
|
||||
public class Track
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public string? Album { get; set; }
|
||||
public string? AlbumArt { get; set; }
|
||||
public long Duration { get; set; }
|
||||
public string Filename { get; set; } = "";
|
||||
public override string ToString() => $"{Title ?? "?"} - {Album ?? "?"}";
|
||||
}
|
||||
9
TechMedia.Core/TechMedia.Core.csproj
Normal file
9
TechMedia.Core/TechMedia.Core.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
158
TechMedia.Core/TechMediaCore.cs
Normal file
158
TechMedia.Core/TechMediaCore.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using TechMedia.Core.Backend;
|
||||
using TechMedia.Core.Model;
|
||||
|
||||
namespace TechMedia.Core
|
||||
{
|
||||
public class TechMediaCore : ITechMediaCore
|
||||
{
|
||||
private readonly IAudioBackend _backend;
|
||||
private List<Track> _currentPlaylist = new();
|
||||
private Queue<Track> _requestQueue = new();
|
||||
|
||||
private IProgress<Track>? _trackReporter;
|
||||
private IProgress<float>? _progressReporter;
|
||||
private IProgress<List<Track>>? _playlistWatcher;
|
||||
private int _playbackIndex = 0;
|
||||
|
||||
public TechMediaCore(IAudioBackend backend)
|
||||
{
|
||||
_backend = backend;
|
||||
_backend.RegisterTrackEndHandler(TrackEndHandler);
|
||||
}
|
||||
|
||||
public void StartPlaylistPlayback(IProgress<Track>? trackReporter = null, IProgress<float>? progressReporter = null)
|
||||
{
|
||||
if (trackReporter != null)
|
||||
_trackReporter = trackReporter;
|
||||
|
||||
if (progressReporter != null)
|
||||
{
|
||||
if (_progressReporter != null)
|
||||
{
|
||||
_backend.RemoveProgressWatcher(_progressReporter);
|
||||
}
|
||||
_progressReporter = progressReporter;
|
||||
_backend.RegisterProgressWatcher(progressReporter);
|
||||
}
|
||||
|
||||
var firstTrack = _currentPlaylist[_playbackIndex++];
|
||||
_backend.PlayFile(firstTrack.Filename);
|
||||
_trackReporter?.Report(firstTrack);
|
||||
}
|
||||
|
||||
private void QueueFilePlayback(string filename)
|
||||
{
|
||||
// LibVLC has a famous bug when calling LibVLC from a LibVLC callback (which is what this method is) that results in a deadlock.
|
||||
// Workaround is to queue the action on another thread.
|
||||
ThreadPool.QueueUserWorkItem(_ => _backend.PlayFile(filename));
|
||||
}
|
||||
|
||||
public void TrackEndHandler(object? sender, EventArgs args)
|
||||
{
|
||||
if (_requestQueue.Count > 0)
|
||||
{
|
||||
var requestTrack = _requestQueue.Dequeue();
|
||||
_trackReporter?.Report(requestTrack);
|
||||
QueueFilePlayback(requestTrack.Filename);
|
||||
}
|
||||
else if (_playbackIndex < _currentPlaylist.Count)
|
||||
{
|
||||
var nextTrack = _currentPlaylist[_playbackIndex++];
|
||||
_trackReporter?.Report(nextTrack);
|
||||
QueueFilePlayback(nextTrack.Filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
ShuffleCurrentPlaylist();
|
||||
StartPlaylistPlayback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_backend.StopPlayback();
|
||||
_playbackIndex = 0;
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void NextTrack()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PreviousTrack()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void GetNextTrackInfo()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void GetCurrentTrackInfo()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OpenMediaFile(string filename)
|
||||
{
|
||||
_backend.PlayFile(filename);
|
||||
}
|
||||
|
||||
public void OpenPlaylistFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<int> LoadFiles(List<string> files, IProgress<int>? progress = null)
|
||||
{
|
||||
_currentPlaylist = new List<Track>();
|
||||
foreach (var (file, index) in files.Select((filename, index) => (filename, index)))
|
||||
{
|
||||
var track = await _backend.GetFileMetadata(file);
|
||||
progress?.Report(index);
|
||||
if (track != null)
|
||||
_currentPlaylist.Add(track);
|
||||
}
|
||||
return _currentPlaylist.Count;
|
||||
}
|
||||
|
||||
public List<Track> ShuffleCurrentPlaylist()
|
||||
{
|
||||
_backend.StopPlayback();
|
||||
_playbackIndex = 0;
|
||||
var random = new Random();
|
||||
_currentPlaylist = _currentPlaylist.OrderBy(t => random.Next()).ToList();
|
||||
_playlistWatcher?.Report(_currentPlaylist);
|
||||
return _currentPlaylist;
|
||||
}
|
||||
|
||||
public List<Track> GetCurrentPlaylist() => _currentPlaylist;
|
||||
public void RegisterPlaylistChangeListener(IProgress<List<Track>> playlistWatcher)
|
||||
{
|
||||
_playlistWatcher = playlistWatcher;
|
||||
}
|
||||
|
||||
public Track? SubmitRequest(string filename)
|
||||
{
|
||||
var requestedTrack = _currentPlaylist.FirstOrDefault(t => t.Filename.Equals(filename, StringComparison.OrdinalIgnoreCase));
|
||||
if (requestedTrack != null)
|
||||
_requestQueue.Enqueue(requestedTrack);
|
||||
|
||||
return requestedTrack;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user