diff --git a/BassBoom.Basolia/File/FileTools.cs b/BassBoom.Basolia/File/FileTools.cs
index 4c2922c..77b87e8 100644
--- a/BassBoom.Basolia/File/FileTools.cs
+++ b/BassBoom.Basolia/File/FileTools.cs
@@ -24,6 +24,7 @@
using BassBoom.Native.Interop.Init;
using BassBoom.Native.Interop.Play;
using SpecProbe.Software.Platform;
+using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
@@ -184,6 +185,50 @@ public static async Task OpenUrlAsync(BasoliaMedia? basolia, string path)
PlaybackTools.FeedRadio(basolia);
}
+ ///
+ /// Opens a stream
+ ///
+ /// Basolia instance that contains a valid handle
+ /// MPEG audio stream
+ public static void OpenFrom(BasoliaMedia? basolia, Stream? audioStream) =>
+ Task.Run(() => OpenFromAsync(basolia, audioStream)).Wait();
+
+ ///
+ /// Opens a stream
+ ///
+ /// Basolia instance that contains a valid handle
+ /// MPEG audio stream
+ public static async Task OpenFromAsync(BasoliaMedia? basolia, Stream? audioStream)
+ {
+ InitBasolia.CheckInited();
+ if (basolia is null)
+ throw new BasoliaException("Basolia instance is not provided", mpg123_errors.MPG123_BAD_HANDLE);
+
+ // Check to see if the file is open
+ if (IsOpened(basolia))
+ throw new BasoliaException("Can't open this URL while the current file or a radio station is still open", mpg123_errors.MPG123_BAD_FILE);
+
+ // Check to see if we provided a stream
+ if (audioStream is null)
+ throw new BasoliaException("Audio stream is not provided", mpg123_errors.MPG123_BAD_FILE);
+
+ // We're now entering the dangerous zone
+ unsafe
+ {
+ // Open the stream
+ var handle = basolia._mpg123Handle;
+ var @delegate = MpgNative.GetDelegate(MpgNative.libManagerMpg, nameof(NativeInput.mpg123_open_feed));
+ int openStatus = @delegate.Invoke(handle);
+ if (openStatus == (int)mpg123_errors.MPG123_ERR)
+ throw new BasoliaException("Can't open stream", mpg123_errors.MPG123_ERR);
+ basolia.isOpened = true;
+ }
+ basolia.currentFile = new(false, "", audioStream, null, "");
+
+ // If necessary, feed.
+ await PlaybackTools.FeedStream(basolia);
+ }
+
///
/// Closes a currently opened media file
///
@@ -214,6 +259,7 @@ public static void CloseFile(BasoliaMedia? basolia)
throw new BasoliaException("Can't close file", mpg123_errors.MPG123_ERR);
basolia.isOpened = false;
basolia.isRadioStation = false;
+ basolia.currentFile?.Stream?.Close();
basolia.currentFile = null;
}
}
diff --git a/BassBoom.Basolia/Playback/PlaybackTools.cs b/BassBoom.Basolia/Playback/PlaybackTools.cs
index c694dd2..7367034 100644
--- a/BassBoom.Basolia/Playback/PlaybackTools.cs
+++ b/BassBoom.Basolia/Playback/PlaybackTools.cs
@@ -110,9 +110,6 @@ public static void Play(BasoliaMedia? basolia)
// We're now entering the dangerous zone
unsafe
{
- var handle = basolia._mpg123Handle;
- var outHandle = basolia._out123Handle;
-
// Reset the format. Orders here matter.
var (rate, channels, encoding) = FormatTools.GetFormatInfo(basolia);
FormatTools.NoFormat(basolia);
@@ -487,8 +484,6 @@ internal static void FeedRadio(BasoliaMedia? basolia)
unsafe
{
- var handle = basolia._mpg123Handle;
-
// Get the MP3 frame length first
string metaIntStr = currentRadio.Headers.GetValues("icy-metaint").First();
int metaInt = int.Parse(metaIntStr);
@@ -515,6 +510,41 @@ internal static void FeedRadio(BasoliaMedia? basolia)
basolia.radioIcy = icy;
Debug.WriteLine($"{basolia.radioIcy}");
+ // Copy the data to MPG123
+ CopyBuffer(basolia, buffer);
+ }
+ }
+
+ internal static async Task FeedStream(BasoliaMedia? basolia)
+ {
+ if (!FileTools.IsOpened(basolia) || FileTools.IsRadioStation(basolia))
+ return;
+ var currentStream = FileTools.CurrentFile(basolia);
+ if (currentStream is null)
+ return;
+ if (currentStream.Stream is null)
+ return;
+ if (basolia is null)
+ throw new BasoliaException("Basolia instance is not provided", mpg123_errors.MPG123_BAD_HANDLE);
+
+ // Now, get the MP3 frame
+ byte[] buffer = new byte[currentStream.Stream.Length];
+ await currentStream.Stream.ReadAsync(buffer, 0, (int)currentStream.Stream.Length);
+
+ // Copy the data to MPG123
+ CopyBuffer(basolia, buffer);
+ }
+
+ internal static void CopyBuffer(BasoliaMedia? basolia, byte[]? buffer)
+ {
+ if (buffer is null)
+ return;
+ if (basolia is null)
+ throw new BasoliaException("Basolia instance is not provided", mpg123_errors.MPG123_BAD_HANDLE);
+ unsafe
+ {
+ var handle = basolia._mpg123Handle;
+
// Copy the data to MPG123
IntPtr data = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, data, buffer.Length);
diff --git a/BassBoom.Cli/CliBase/PlayerControls.cs b/BassBoom.Cli/CliBase/PlayerControls.cs
index b48bbf8..4f85d10 100644
--- a/BassBoom.Cli/CliBase/PlayerControls.cs
+++ b/BassBoom.Cli/CliBase/PlayerControls.cs
@@ -439,19 +439,13 @@ internal static void PlayTest()
InfoBoxNonModalColor.WriteInfoBox("Playing test sound...", false);
// Extract the test sound asset to a temporary file
- string path = PlatformHelper.IsOnWindows() ? $"{Environment.GetEnvironmentVariable("TEMP")}" : $"/tmp/";
- string fullPath = $"{path}/{DateTime.Now:ddMMyyyyHHmmssfff}.mp3";
var stream = typeof(PlayerControls).Assembly.GetManifestResourceStream("BassBoom.Cli.sample.mp3") ??
throw new Exception("Missing test sound data.");
- var target = File.OpenWrite(fullPath);
- stream.CopyTo(target);
// Now, close the file and play it
- target.Close();
- FileTools.OpenFile(BassBoomCli.basolia, fullPath);
+ FileTools.OpenFrom(BassBoomCli.basolia, stream);
PlaybackTools.Play(BassBoomCli.basolia);
FileTools.CloseFile(BassBoomCli.basolia);
- File.Delete(fullPath);
// Ask the user if everything is OK.
int answer = InfoBoxButtonsColor.WriteInfoBoxButtons("Sound test", [new InputChoiceInfo("Yes", "Yes"), new InputChoiceInfo("No", "No")], "Is everything OK in this current configuration?");