Skip to content

Commit

Permalink
chg - Optimized radio support
Browse files Browse the repository at this point in the history
---

Type: chg
Breaking: False
Doc Required: False
Part: 1/1
  • Loading branch information
AptiviCEO committed May 28, 2024
1 parent 1902bd0 commit dc93b26
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 41 deletions.
7 changes: 4 additions & 3 deletions BassBoom.Basolia/File/FileTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static void OpenFile(string path)
throw new BasoliaException("Can't open file", mpg123_errors.MPG123_ERR);
isOpened = true;
}
currentFile = new(false, path);
currentFile = new(false, path, null, null, "");
}

/// <summary>
Expand All @@ -123,7 +123,9 @@ public static async Task OpenUrlAsync(string path)
throw new BasoliaException("Provide a path to a music file or a radio station", mpg123_errors.MPG123_BAD_FILE);

// Check to see if the radio station exists
ShoutcastServer.client.DefaultRequestHeaders.Add("Icy-MetaData", "1");
var reply = await ShoutcastServer.client.GetAsync(path, HttpCompletionOption.ResponseHeadersRead);
ShoutcastServer.client.DefaultRequestHeaders.Remove("Icy-MetaData");
if (!reply.IsSuccessStatusCode)
throw new BasoliaException($"This radio station doesn't exist. Error code: {(int)reply.StatusCode} ({reply.StatusCode}).", mpg123_errors.MPG123_BAD_FILE);

Expand All @@ -142,7 +144,7 @@ public static async Task OpenUrlAsync(string path)
isOpened = true;
isRadioStation = true;
}
currentFile = new(true, path);
currentFile = new(true, path, reply.Content.ReadAsStreamAsync().Result, reply.Headers, reply.Headers.GetValues("icy-name").First());

// If necessary, feed.
PlaybackTools.FeedRadio();
Expand Down Expand Up @@ -174,7 +176,6 @@ public static void CloseFile()
isOpened = false;
isRadioStation = false;
currentFile = null;
PlaybackTools.radioStream = null;
}
}
}
Expand Down
28 changes: 27 additions & 1 deletion BassBoom.Basolia/File/FileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
//

using System;
using System.IO;
using System.Net.Http.Headers;

namespace BassBoom.Basolia.File
{
Expand All @@ -28,6 +30,9 @@ public class FileType
{
private bool isLink;
private string path;
private Stream stream;
private HttpResponseHeaders headers;
private string stationName;

/// <summary>
/// Is this file type a link?
Expand All @@ -41,10 +46,31 @@ public class FileType
public string Path =>
path;

internal FileType(bool isLink, string path)
/// <summary>
/// Radio station stream
/// </summary>
public Stream Stream =>
stream;

/// <summary>
/// Radio station ICY headers
/// </summary>
public HttpResponseHeaders Headers =>
headers;

/// <summary>
/// Radio station name
/// </summary>
public string StationName =>
stationName;

internal FileType(bool isLink, string path, Stream stream, HttpResponseHeaders headers, string stationName)
{
this.isLink = isLink;
this.path = path ?? throw new ArgumentNullException(nameof(path));
this.stream = stream;
this.headers = headers;
this.stationName = stationName;
}
}
}
75 changes: 49 additions & 26 deletions BassBoom.Basolia/Playback/PlaybackTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
using BassBoom.Basolia.Radio;
using System.Net.Http;
using System.IO;
using System.Linq;
using System.Text;

namespace BassBoom.Basolia.Playback
{
Expand All @@ -43,7 +45,7 @@ public static class PlaybackTools
{
internal static bool bufferPlaying = false;
internal static bool holding = false;
internal static Stream radioStream = null;
internal static string radioIcy = "";
private static PlaybackState state = PlaybackState.Stopped;

/// <summary>
Expand All @@ -58,6 +60,12 @@ public static class PlaybackTools
public static PlaybackState State =>
state;

/// <summary>
/// Current radio ICY metadata
/// </summary>
public static string RadioIcy =>
radioIcy;

/// <summary>
/// Plays the currently open file (synchronous)
/// </summary>
Expand Down Expand Up @@ -166,7 +174,8 @@ public static void Stop()

// Stop the music and seek to the beginning
state = PlaybackState.Stopped;
PlaybackPositioningTools.SeekToTheBeginning();
if (!FileTools.IsRadioStation)
PlaybackPositioningTools.SeekToTheBeginning();
}

/// <summary>
Expand Down Expand Up @@ -323,34 +332,48 @@ public static (long, double) GetNativeState(mpg123_state state)
}
}

internal static int FeedRadio()
internal static void FeedRadio()
{
if (FileTools.IsOpened && FileTools.IsRadioStation)
if (!FileTools.IsOpened || !FileTools.IsRadioStation)
return;

unsafe
{
unsafe
var handle = Mpg123Instance._mpg123Handle;

// Get the MP3 frame length first
string metaIntStr = FileTools.CurrentFile.Headers.GetValues("icy-metaint").First();
int metaInt = int.Parse(metaIntStr);

// Now, get the MP3 frame
byte[] buffer = new byte[metaInt];
int numBytesRead = 0;
int numBytesToRead = metaInt;
do
{
var handle = Mpg123Instance._mpg123Handle;
if (radioStream is null)
{
ShoutcastServer.client.DefaultRequestHeaders.Add("Icy-MetaData", "1");
var reply = ShoutcastServer.client.GetAsync(FileTools.CurrentFile.Path, HttpCompletionOption.ResponseHeadersRead).Result;
ShoutcastServer.client.DefaultRequestHeaders.Remove("Icy-MetaData");
if (!reply.IsSuccessStatusCode)
throw new BasoliaException($"This radio station doesn't exist. Error code: {(int)reply.StatusCode} ({reply.StatusCode}).", mpg123_errors.MPG123_BAD_FILE);
radioStream = reply.Content.ReadAsStreamAsync().Result;
}
byte[] buffer = new byte[8192];
radioStream.Read(buffer, 0, buffer.Length);
IntPtr data = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, data, buffer.Length);
int feedResult = NativeInput.mpg123_feed(handle, data, buffer.Length);
if (feedResult != (int)mpg123_errors.MPG123_OK)
throw new BasoliaException("Can't feed.", mpg123_errors.MPG123_ERR);
return buffer.Length;
}
int n = FileTools.CurrentFile.Stream.Read(buffer, numBytesRead, 1);
numBytesRead += n;
numBytesToRead -= n;
} while (numBytesToRead > 0);

// Fetch the metadata.
int lengthOfMetaData = FileTools.CurrentFile.Stream.ReadByte();
int metaBytesToRead = lengthOfMetaData * 16;
Debug.WriteLine($"Buffer: {lengthOfMetaData} [{metaBytesToRead}]");
byte[] metadataBytes = new byte[metaBytesToRead];
FileTools.CurrentFile.Stream.Read(metadataBytes, 0, metaBytesToRead);
string icy = Encoding.UTF8.GetString(metadataBytes).Replace("\0", "").Trim();
if (!string.IsNullOrEmpty(icy))
radioIcy = icy;
Debug.WriteLine($"{radioIcy}\n");

// Copy the data to MPG123
IntPtr data = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, data, buffer.Length);
int feedResult = NativeInput.mpg123_feed(handle, data, buffer.Length);
if (feedResult != (int)mpg123_errors.MPG123_OK)
throw new BasoliaException("Can't feed.", mpg123_errors.MPG123_ERR);
}
else
return 0;
}

internal static int PlayBuffer(byte[] buffer)
Expand Down
14 changes: 10 additions & 4 deletions BassBoom.Cli/CliBase/Radio.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ internal static class Radio
internal static bool populate = true;
internal static bool paused = false;
internal static bool failedToPlay = false;
internal static string icyMetadata = "";
internal static readonly List<string> stationUrls = [];
internal static readonly List<CachedSongInfo> cachedInfos = [];
internal static Version mpgVer;
Expand Down Expand Up @@ -82,13 +81,20 @@ public static void RadioLoop()
// Handle drawing
screenPart.AddDynamicText(HandleDraw);

// Current duration
// Current volume
int hue = 0;
screenPart.AddDynamicText(() =>
{
var buffer = new StringBuilder();
string indicator = $"Volume: {volume:0.00}";
if (PlaybackTools.Playing)
{
hue++;
if (hue >= 360)
hue = 0;
}
buffer.Append(
BoxFrameColor.RenderBoxFrame(2, ConsoleWrapper.WindowHeight - 8, ConsoleWrapper.WindowWidth - 6, 1) +
BoxFrameColor.RenderBoxFrame(2, ConsoleWrapper.WindowHeight - 8, ConsoleWrapper.WindowWidth - 6, 1, PlaybackTools.Playing ? new Color($"hsl:{hue};50;50") : new Color(ConsoleColors.White)) +
TextWriterWhereColor.RenderWhere(indicator, ConsoleWrapper.WindowWidth - indicator.Length - 3, ConsoleWrapper.WindowHeight - 9, ConsoleColors.White, ConsoleColors.Black)
);
return buffer.ToString();
Expand Down Expand Up @@ -341,7 +347,7 @@ private static string HandleDraw()
for (int i = 0; i < stationUrls.Count; i++)
{
// Populate the first pane
string stationName = "Station name";
string stationName = cachedInfos[i].MetadataIcy;
string duration = cachedInfos[i].DurationSpan;
string stationPreview = $"[{duration}] {stationName}";
choices.Add(new($"{i + 1}", stationPreview));
Expand Down
16 changes: 9 additions & 7 deletions BassBoom.Cli/CliBase/RadioControls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Terminaux.Base;
using Terminaux.Colors.Data;
Expand Down Expand Up @@ -149,27 +150,25 @@ internal static void PopulateRadioStationInfo(string musicPath)
if (PlaybackTools.Playing || !Radio.populate)
return;
Radio.populate = false;
if (!TryOpenStation(musicPath))
return;
FileTools.OpenUrl(musicPath);
if (Radio.cachedInfos.Any((csi) => csi.MusicPath == musicPath))
{
var instance = Radio.cachedInfos.Single((csi) => csi.MusicPath == musicPath);
Radio.formatInfo = instance.FormatInfo;
Radio.frameInfo = instance.FrameInfo;
Radio.icyMetadata = instance.MetadataIcy;
if (!Radio.stationUrls.Contains(musicPath))
Radio.stationUrls.Add(musicPath);
}
else
{
if (!TryOpenStation(musicPath))
return;
InfoBoxColor.WriteInfoBox($"Loading BassBoom to open {musicPath}...", false);
FileTools.OpenUrl(musicPath);
Radio.formatInfo = FormatTools.GetFormatInfo();
Radio.frameInfo = AudioInfoTools.GetFrameInfo();
Radio.icyMetadata = AudioInfoTools.GetIcyMetadata();

// Try to open the lyrics
var instance = new CachedSongInfo(musicPath, null, null, -1, Radio.formatInfo, Radio.frameInfo, null, Radio.icyMetadata);
var instance = new CachedSongInfo(musicPath, null, null, -1, Radio.formatInfo, Radio.frameInfo, null, FileTools.CurrentFile.StationName);
Radio.cachedInfos.Add(instance);
}
TextWriterWhereColor.WriteWhere(new string(' ', ConsoleWrapper.WindowWidth), 0, 1);
Expand All @@ -180,7 +179,10 @@ internal static void PopulateRadioStationInfo(string musicPath)
internal static string RenderStationName()
{
// Render the station name
string icy = Radio.icyMetadata;
string icy = PlaybackTools.RadioIcy;
if (icy.Length == 0)
return "";
icy = Regex.Match(icy, @"StreamTitle='((?:[^']|\\')*)'").Groups[1].Value.Trim().Replace("\\'", "'");

// Print the music name
return CenteredTextColor.RenderCentered(1, "Now playing: {0}", ConsoleColors.White, ConsoleColors.Black, icy);
Expand Down

0 comments on commit dc93b26

Please sign in to comment.