diff --git a/MusicX/MusicX.csproj b/MusicX/MusicX.csproj
index ac6ed4fc..b207a5ac 100644
--- a/MusicX/MusicX.csproj
+++ b/MusicX/MusicX.csproj
@@ -101,7 +101,7 @@
-
+
diff --git a/MusicX/Services/DownloaderService.cs b/MusicX/Services/DownloaderService.cs
index a3a44103..6d52b220 100644
--- a/MusicX/Services/DownloaderService.cs
+++ b/MusicX/Services/DownloaderService.cs
@@ -9,10 +9,13 @@
using Windows.Media.Transcoding;
using Windows.Storage;
using FFMediaToolkit;
+using FFMediaToolkit.Audio;
+using FFMediaToolkit.Decoding;
using FFmpegInteropX;
using MusicX.Core.Services;
using MusicX.Helpers;
using MusicX.Services.Player.Playlists;
+using MusicX.Services.Player.Sources;
using MusicX.Shared.Player;
using TagLib;
using TagLib.Id3v2;
@@ -55,8 +58,8 @@ public async Task DownloadAudioAsync(PlaylistTrack audio, IProgress<(TimeSpan Po
if (string.IsNullOrEmpty(audio.Data.Url))
return;
- var fileName = $"{audio.GetArtistsString()} - {audio.Title}.mp3";
- fileName = ReplaceSymbols(fileName);
+ var fileName = $"{audio.GetArtistsString()} - {audio.Title}";
+ fileName = ReplaceSymbols(fileName) + ".mp3";
string fileDownloadPath;
var musicFolder = GetDownloadDirectoryAsync();
@@ -98,13 +101,17 @@ public async Task DownloadAudioAsync(PlaylistTrack audio, IProgress<(TimeSpan Po
}
else
{
- using var ffmpegMediaSource = await FFmpegMediaSource.CreateFromUriAsync(audio.Data.Url, new()
- {
- FFmpegOptions =
- {
- ["http_persistent"] = "false"
- }
- }).AsTask(cancellationToken);
+ // blocked by FFmpegMediaSource working only with active media player
+ // using var ffmpegMediaSource = await FFmpegMediaSource.CreateFromUriAsync(audio.Data.Url, new()
+ // {
+ // FFmpegOptions =
+ // {
+ // ["http_persistent"] = "false"
+ // }
+ // }).AsTask(cancellationToken);
+ // var streamSource = ffmpegMediaSource.GetMediaStreamSource();
+
+ var streamSource = MediaSourceBase.CreateFFMediaStreamSource(audio.Data.Url);
var encodingProfile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.Auto);
@@ -114,7 +121,7 @@ public async Task DownloadAudioAsync(PlaylistTrack audio, IProgress<(TimeSpan Po
using var destinationStream = await destination.OpenAsync(FileAccessMode.ReadWrite).AsTask(cancellationToken);
var prepareOp =
- await _mediaTranscoder.PrepareMediaStreamSourceTranscodeAsync(ffmpegMediaSource.GetMediaStreamSource(),
+ await _mediaTranscoder.PrepareMediaStreamSourceTranscodeAsync(streamSource,
destinationStream, encodingProfile).AsTask(cancellationToken);
if (!prepareOp.CanTranscode)
@@ -128,9 +135,10 @@ await _mediaTranscoder.PrepareMediaStreamSourceTranscodeAsync(ffmpegMediaSource.
var transcodeOp = prepareOp.TranscodeAsync();
- transcodeOp.Progress += (sender, position) =>
+ var duration = streamSource.Duration;
+ transcodeOp.Progress += (_, position) =>
{
- progress?.Report((TimeSpan.FromSeconds(position), TimeSpan.FromSeconds(1)));
+ progress?.Report((TimeSpan.FromSeconds(position), duration));
};
await transcodeOp.AsTask(cancellationToken);
@@ -141,7 +149,7 @@ await _mediaTranscoder.PrepareMediaStreamSourceTranscodeAsync(ffmpegMediaSource.
private string ReplaceSymbols(string fileName)
{
- return string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));
+ return string.Join("_", fileName.Split(Path.GetInvalidFileNameChars())).Replace('.', '_');
}
private async Task AddMetadataAsync(PlaylistTrack audio, string filePath, CancellationToken cancellationToken)
diff --git a/MusicX/Services/Player/Sources/MediaSourceBase.cs b/MusicX/Services/Player/Sources/MediaSourceBase.cs
index 8f3f872d..21436c5a 100644
--- a/MusicX/Services/Player/Sources/MediaSourceBase.cs
+++ b/MusicX/Services/Player/Sources/MediaSourceBase.cs
@@ -23,7 +23,7 @@ public abstract class MediaSourceBase : ITrackMediaSource
{
private static readonly Semaphore FFmpegSemaphore = new(1, 1, "MusicX_FFmpegSemaphore");
- protected readonly MediaOptions MediaOptions = new()
+ protected static readonly MediaOptions MediaOptions = new()
{
StreamsToLoad = MediaMode.Audio,
AudioSampleFormat = SampleFormat.SignedWord,
@@ -38,7 +38,9 @@ public abstract class MediaSourceBase : ITrackMediaSource
["reconnect"] = "1",
["reconnect_streamed"] = "1",
["reconnect_delay_max"] = "5",
- ["stimeout"] = "10"
+ ["stimeout"] = "10",
+ ["timeout"] = "10",
+ ["rw_timeout"] = "10"
}
}
};
@@ -48,6 +50,18 @@ public abstract class MediaSourceBase : ITrackMediaSource
CancellationToken cancellationToken = default);
protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
+ {
+ var streamingSource = CreateFFMediaStreamSource(file);
+
+ return new (MediaSource.CreateFromMediaStreamSource(streamingSource));
+ }
+
+ public static MediaStreamSource CreateFFMediaStreamSource(string url)
+ {
+ return CreateFFMediaStreamSource(MediaFile.Open(url, MediaOptions));
+ }
+
+ public static MediaStreamSource CreateFFMediaStreamSource(MediaFile file)
{
var properties =
AudioEncodingProperties.CreatePcm((uint)file.Audio.Info.SampleRate, (uint)file.Audio.Info.NumChannels, 16);
@@ -72,7 +86,7 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
try
{
- FFmpegSemaphore.WaitOne();
+ FFmpegSemaphore.WaitOne(TimeSpan.FromSeconds(10));
file.Audio.GetFrame(position);
}
catch (FFmpegException)
@@ -84,9 +98,9 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
}
};
- streamingSource.Closed += async (_, _) =>
+ streamingSource.Closed += (_, _) =>
{
- await FFmpegSemaphore.WaitOneAsync();
+ FFmpegSemaphore.WaitOne(TimeSpan.FromSeconds(10));
try
{
file.Dispose();
@@ -99,10 +113,7 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
streamingSource.SampleRequested += (_, args) =>
{
- //var deferral = args.Request.GetDeferral();
-
- //await FFmpegSemaphore.WaitOneAsync();
- FFmpegSemaphore.WaitOne();
+ FFmpegSemaphore.WaitOne(TimeSpan.FromSeconds(10));
try
{
@@ -116,7 +127,6 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
finally
{
FFmpegSemaphore.Release();
- //deferral.Complete();
}
};
@@ -149,15 +159,11 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
return array;
}
- return new (MediaSource.CreateFromMediaStreamSource(streamingSource));
+ return streamingSource;
}
- private static FFmpegMediaSource? _source;
-
public static async Task CreateWinRtMediaPlaybackItem(MediaPlaybackSession playbackSession, TrackData data, IReadOnlyDictionary? customOptions = null)
{
- _source?.Dispose();
-
var options = new PropertySet
{
["reconnect"] = "1",
@@ -170,7 +176,7 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
foreach (var (key, value) in customOptions)
options[key] = value;
- _source = await FFmpegMediaSource.CreateFromUriAsync(data.Url, new()
+ var source = await FFmpegMediaSource.CreateFromUriAsync(data.Url, new()
{
FFmpegOptions = options,
General =
@@ -179,9 +185,9 @@ protected static MediaPlaybackItem CreateMediaPlaybackItem(MediaFile file)
}
});
- _source.PlaybackSession = playbackSession;
- _source.StartBuffering();
+ source.PlaybackSession = playbackSession;
+ source.StartBuffering();
- return _source.CreateMediaPlaybackItem();
+ return source.CreateMediaPlaybackItem();
}
}
\ No newline at end of file
diff --git a/MusicX/Views/DownloadsView.xaml b/MusicX/Views/DownloadsView.xaml
index 85db76e3..614e3056 100644
--- a/MusicX/Views/DownloadsView.xaml
+++ b/MusicX/Views/DownloadsView.xaml
@@ -154,7 +154,7 @@
-
+
diff --git a/MusicX/packages.lock.json b/MusicX/packages.lock.json
index b1198cd4..935ad6a2 100644
--- a/MusicX/packages.lock.json
+++ b/MusicX/packages.lock.json
@@ -140,9 +140,9 @@
},
"WPF-UI": {
"type": "Direct",
- "requested": "[3.0.3, )",
- "resolved": "3.0.3",
- "contentHash": "Nm6Q5StLWxs74eFcqTwNJTGpA6xbTF1BXLniy5HMwnowvjiEa6Wa26/eI3e4/KbD56YF4nZidn69G/lY7t+aNg=="
+ "requested": "[3.0.4, )",
+ "resolved": "3.0.4",
+ "contentHash": "Jbt8nJ4MSC/WBhqx6iXOW06Rt2UUNVxA8+23AOSM63jlOIhU6e6P4BIw8rL/UnRPycOdA2vntYl5i7k53E0AGg=="
},
"WpfScreenHelper": {
"type": "Direct",