516 lines
13 KiB
C#
516 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Security;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text.RegularExpressions;
|
|
using Crosstales.Radio.Model;
|
|
using Crosstales.Radio.Model.Enum;
|
|
using UnityEngine;
|
|
|
|
namespace Crosstales.Radio.Util
|
|
{
|
|
public static class Helper
|
|
{
|
|
private static readonly Regex lineEndingsRegex = new Regex("\\r\\n|\\r|\\n");
|
|
|
|
private static readonly int[] mp3Bitrates = new int[14]
|
|
{
|
|
32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
|
|
192, 224, 256, 320
|
|
};
|
|
|
|
private static readonly int[] oggBitrates = new int[14]
|
|
{
|
|
32, 45, 48, 64, 80, 96, 112, 128, 160, 192,
|
|
224, 256, 320, 500
|
|
};
|
|
|
|
private const string file_prefix = "file://";
|
|
|
|
public static bool isInternetAvailable
|
|
{
|
|
get
|
|
{
|
|
return Application.internetReachability != NetworkReachability.NotReachable;
|
|
}
|
|
}
|
|
|
|
public static bool isWindowsPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor;
|
|
}
|
|
}
|
|
|
|
public static bool isMacOSPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor;
|
|
}
|
|
}
|
|
|
|
public static bool isLinuxPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.LinuxPlayer || Application.platform == RuntimePlatform.LinuxEditor;
|
|
}
|
|
}
|
|
|
|
public static bool isStandalonePlatform
|
|
{
|
|
get
|
|
{
|
|
return isWindowsPlatform || isMacOSPlatform || isLinuxPlatform;
|
|
}
|
|
}
|
|
|
|
public static bool isAndroidPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.Android;
|
|
}
|
|
}
|
|
|
|
public static bool isIOSPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.tvOS;
|
|
}
|
|
}
|
|
|
|
public static bool isWSAPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.MetroPlayerARM || Application.platform == RuntimePlatform.MetroPlayerX86 || Application.platform == RuntimePlatform.MetroPlayerX64 || Application.platform == RuntimePlatform.XboxOne;
|
|
}
|
|
}
|
|
|
|
public static bool isWebGLPlatform
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.WebGLPlayer;
|
|
}
|
|
}
|
|
|
|
public static bool isWebPlayerPlatform
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool isWebPlatform
|
|
{
|
|
get
|
|
{
|
|
return isWebPlayerPlatform || isWebGLPlatform;
|
|
}
|
|
}
|
|
|
|
public static bool isWindowsBasedPlatform
|
|
{
|
|
get
|
|
{
|
|
return isWindowsPlatform || isWSAPlatform;
|
|
}
|
|
}
|
|
|
|
public static bool isAppleBasedPlatform
|
|
{
|
|
get
|
|
{
|
|
return isMacOSPlatform || isIOSPlatform;
|
|
}
|
|
}
|
|
|
|
public static bool isEditor
|
|
{
|
|
get
|
|
{
|
|
return Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.LinuxEditor;
|
|
}
|
|
}
|
|
|
|
public static bool isEditorMode
|
|
{
|
|
get
|
|
{
|
|
return isEditor && !Application.isPlaying;
|
|
}
|
|
}
|
|
|
|
public static bool isSupportedPlatform
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
|
{
|
|
bool result = true;
|
|
if (sslPolicyErrors != SslPolicyErrors.None)
|
|
{
|
|
for (int i = 0; i < chain.ChainStatus.Length; i++)
|
|
{
|
|
if (chain.ChainStatus[i].Status != X509ChainStatusFlags.RevocationStatusUnknown)
|
|
{
|
|
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
|
|
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
|
|
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
|
|
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
|
|
result = chain.Build((X509Certificate2)certificate);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool isSane(ref RadioStation station)
|
|
{
|
|
if (station == null)
|
|
{
|
|
Debug.LogError("'Station' is null!" + Environment.NewLine + "Add a valid station to the player.");
|
|
return false;
|
|
}
|
|
if (string.IsNullOrEmpty(station.Url))
|
|
{
|
|
Debug.LogError(string.Concat(station, Environment.NewLine, "'Url' is null or empty!", Environment.NewLine, "Cannot start playback -> please add a valid url of a radio station (see 'Radios.txt' for some examples)."));
|
|
return false;
|
|
}
|
|
if (!isValidURL(station.Url))
|
|
{
|
|
Debug.LogError(string.Concat(station, Environment.NewLine, "'Url' is not valid!", Environment.NewLine, "Cannot start playback -> please add a valid url of a radio station (see 'Radios.txt' for some examples)."));
|
|
return false;
|
|
}
|
|
if (!isValidFormat(station.Format))
|
|
{
|
|
Debug.LogError(string.Concat(station, Environment.NewLine, "'Format' is invalid: '", station.Format, "'", Environment.NewLine, "Cannot start playback -> please add a valid audio format for a radio station (see 'Radios.txt' for some examples)."));
|
|
return false;
|
|
}
|
|
if (!isValidBitrate(station.Bitrate, station.Format))
|
|
{
|
|
Debug.LogWarning(string.Concat(station, Environment.NewLine, "'Bitrate' is invalid: ", station.Bitrate, Environment.NewLine, "Autmatically using ", Config.DEFAULT_BITRATE, " kbit/s for playback."));
|
|
station.Bitrate = Config.DEFAULT_BITRATE;
|
|
}
|
|
if (station.ChunkSize < 1)
|
|
{
|
|
Debug.LogWarning(string.Concat(station, Environment.NewLine, "'ChunkSize' is smaller than 1KB!", Environment.NewLine, "Autmatically using ", Config.DEFAULT_CHUNKSIZE, "KB for playback."));
|
|
station.ChunkSize = Config.DEFAULT_CHUNKSIZE;
|
|
}
|
|
if (station.Format == AudioFormat.MP3)
|
|
{
|
|
if (station.BufferSize < Config.DEFAULT_BUFFERSIZE / 4)
|
|
{
|
|
Debug.LogWarning(string.Concat(station, Environment.NewLine, "'BufferSize' is smaller than DEFAULT_BUFFERSIZE/4!", Environment.NewLine, "Autmatically using ", Config.DEFAULT_BUFFERSIZE / 4, "KB for playback."));
|
|
station.BufferSize = Config.DEFAULT_BUFFERSIZE / 4;
|
|
}
|
|
}
|
|
else if (station.BufferSize < 64)
|
|
{
|
|
station.BufferSize = 64;
|
|
}
|
|
if (station.BufferSize < station.ChunkSize)
|
|
{
|
|
Debug.LogWarning(string.Concat(station, Environment.NewLine, "'BufferSize' is smaller than 'ChunkSize'!", Environment.NewLine, "Autmatically using ", station.ChunkSize, "KB for playback."));
|
|
station.BufferSize = station.ChunkSize;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static string ValidatePath(string path)
|
|
{
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
string text = path.Trim();
|
|
string text2 = null;
|
|
if (isWindowsPlatform)
|
|
{
|
|
text2 = text.Replace('/', '\\');
|
|
if (!text2.EndsWith("\\"))
|
|
{
|
|
text2 += "\\";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
text2 = text.Replace('\\', '/');
|
|
if (!text2.EndsWith("/"))
|
|
{
|
|
text2 += "/";
|
|
}
|
|
}
|
|
return string.Join("_", text2.Split(Path.GetInvalidPathChars()));
|
|
}
|
|
return path;
|
|
}
|
|
|
|
public static string ValidateFile(string path)
|
|
{
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
string text = ValidatePath(path);
|
|
if (text.EndsWith("\\") || text.EndsWith("/"))
|
|
{
|
|
text = text.Substring(0, text.Length - 1);
|
|
}
|
|
string text2 = text.Substring((!isWindowsBasedPlatform) ? (text.LastIndexOf("/") + 1) : (text.LastIndexOf("\\") + 1));
|
|
string text3 = string.Join(string.Empty, text2.Split(Path.GetInvalidFileNameChars()));
|
|
return text.Substring(0, text.Length - text2.Length) + text3;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
public static string CleanUrl(string url, bool removeProtocol = true, bool removeWWW = true, bool removeSlash = true)
|
|
{
|
|
string text = url.Trim();
|
|
if (!string.IsNullOrEmpty(url))
|
|
{
|
|
if (removeProtocol)
|
|
{
|
|
text = text.Substring(text.IndexOf("//") + 2);
|
|
}
|
|
if (removeProtocol)
|
|
{
|
|
text = text.CTReplace("www.", string.Empty);
|
|
}
|
|
if (removeSlash && text.EndsWith("/"))
|
|
{
|
|
text = text.Substring(0, text.Length - 1);
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
|
|
public static List<string> SplitStringToLines(string text, bool ignoreCommentedLines = true, int skipHeaderLines = 0, int skipFooterLines = 0)
|
|
{
|
|
List<string> list = new List<string>(100);
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
Debug.LogWarning("Parameter 'text' is null or empty!" + Environment.NewLine + "=> 'SplitStringToLines()' will return an empty string list.");
|
|
}
|
|
else
|
|
{
|
|
string[] array = lineEndingsRegex.Split(text);
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
if (i + 1 <= skipHeaderLines || i >= array.Length - skipFooterLines || string.IsNullOrEmpty(array[i]))
|
|
{
|
|
continue;
|
|
}
|
|
if (ignoreCommentedLines)
|
|
{
|
|
if (!array[i].StartsWith("#", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
list.Add(array[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
list.Add(array[i]);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static string FormatBytesToHRF(long bytes)
|
|
{
|
|
string[] array = new string[5] { "B", "KB", "MB", "GB", "TB" };
|
|
double num = bytes;
|
|
int num2 = 0;
|
|
while (num >= 1024.0 && num2 < array.Length - 1)
|
|
{
|
|
num2++;
|
|
num /= 1024.0;
|
|
}
|
|
return string.Format("{0:0.##} {1}", num, array[num2]);
|
|
}
|
|
|
|
public static string FormatSecondsToHourMinSec(double seconds)
|
|
{
|
|
int num = (int)seconds;
|
|
int num2 = num % 60;
|
|
if (seconds >= 3600.0)
|
|
{
|
|
int num3 = num / 3600;
|
|
int num4 = (num - num3 * 3600) / 60;
|
|
return num3 + ":" + ((num4 >= 10) ? num4.ToString() : ("0" + num4)) + ":" + ((num2 >= 10) ? num2.ToString() : ("0" + num2));
|
|
}
|
|
int num5 = num / 60;
|
|
return num5 + ":" + ((num2 >= 10) ? num2.ToString() : ("0" + num2));
|
|
}
|
|
|
|
public static float[] ConvertByteArrayToFloatArray(byte[] bytes, int count)
|
|
{
|
|
float[] array = new float[count / 2];
|
|
int num = 0;
|
|
for (int i = 0; i < count; i += 2)
|
|
{
|
|
array[num] = bytesToFloat(bytes[i], bytes[i + 1]);
|
|
num++;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public static byte[] ConvertFloatArrayToByteArray(float[] floats, int count)
|
|
{
|
|
byte[] array = new byte[count * 2];
|
|
int num = 0;
|
|
int num2 = 0;
|
|
while (num < count)
|
|
{
|
|
short num3 = (short)(floats[num] * 32767f);
|
|
array[num2] = (byte)(num3 & 0xFF);
|
|
array[num2 + 1] = (byte)((num3 >> 8) & 0xFF);
|
|
num++;
|
|
num2 += 2;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
public static Color HSVToRGB(float h, float s, float v, float a = 1f)
|
|
{
|
|
if (s == 0f)
|
|
{
|
|
return new Color(v, v, v, a);
|
|
}
|
|
h /= 60f;
|
|
int num = Mathf.FloorToInt(h);
|
|
float num2 = h - (float)num;
|
|
float num3 = v * (1f - s);
|
|
float num4 = v * (1f - s * num2);
|
|
float num5 = v * (1f - s * (1f - num2));
|
|
switch (num)
|
|
{
|
|
case 0:
|
|
return new Color(v, num5, num3, a);
|
|
case 1:
|
|
return new Color(num4, v, num3, a);
|
|
case 2:
|
|
return new Color(num3, v, num5, a);
|
|
case 3:
|
|
return new Color(num3, num4, v, a);
|
|
case 4:
|
|
return new Color(num5, num3, v, a);
|
|
default:
|
|
return new Color(v, num3, num4, a);
|
|
}
|
|
}
|
|
|
|
public static AudioFormat AudioFormatFromString(string format)
|
|
{
|
|
AudioFormat result = AudioFormat.MP3;
|
|
if (!string.IsNullOrEmpty(format) && format.CTEquals("ogg"))
|
|
{
|
|
result = AudioFormat.OGG;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static AudioCodec AudioCodecFromString(string codec)
|
|
{
|
|
AudioCodec result = AudioCodec.None;
|
|
if (!string.IsNullOrEmpty(codec))
|
|
{
|
|
if (codec.CTEquals("MP3_NLayer"))
|
|
{
|
|
result = AudioCodec.MP3_NLayer;
|
|
}
|
|
else if (codec.CTEquals("MP3_NAudio"))
|
|
{
|
|
result = AudioCodec.MP3_NAudio;
|
|
}
|
|
else if (codec.CTEquals("OGG_NVorbis"))
|
|
{
|
|
result = AudioCodec.OGG_NVorbis;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static AudioCodec AudioCodecForAudioFormat(AudioFormat format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case AudioFormat.MP3:
|
|
if (isWindowsPlatform)
|
|
{
|
|
return Constants.DEFAULT_CODEC_MP3_WINDOWS;
|
|
}
|
|
return Constants.DEFAULT_CODEC_MP3;
|
|
case AudioFormat.OGG:
|
|
return AudioCodec.OGG_NVorbis;
|
|
default:
|
|
return AudioCodec.None;
|
|
}
|
|
}
|
|
|
|
public static bool isValidFormat(AudioFormat format)
|
|
{
|
|
return format == AudioFormat.MP3 || format == AudioFormat.OGG;
|
|
}
|
|
|
|
public static int NearestBitrate(int bitrate, AudioFormat format)
|
|
{
|
|
int num = 128;
|
|
if (format == AudioFormat.MP3)
|
|
{
|
|
return NearestMP3Bitrate(bitrate);
|
|
}
|
|
return NearestOGGBitrate(bitrate);
|
|
}
|
|
|
|
public static int NearestMP3Bitrate(int bitrate)
|
|
{
|
|
return mp3Bitrates.Aggregate((int x, int y) => (Math.Abs(x - bitrate) >= Math.Abs(y - bitrate)) ? y : x);
|
|
}
|
|
|
|
public static int NearestOGGBitrate(int bitrate)
|
|
{
|
|
return oggBitrates.Aggregate((int x, int y) => (Math.Abs(x - bitrate) >= Math.Abs(y - bitrate)) ? y : x);
|
|
}
|
|
|
|
public static bool isValidBitrate(int bitrate, AudioFormat format)
|
|
{
|
|
bool flag = false;
|
|
if (format == AudioFormat.MP3)
|
|
{
|
|
return isValidMP3Bitrate(bitrate);
|
|
}
|
|
return isValidOGGBitrate(bitrate);
|
|
}
|
|
|
|
public static bool isValidMP3Bitrate(int bitrate)
|
|
{
|
|
return mp3Bitrates.Contains(bitrate);
|
|
}
|
|
|
|
public static bool isValidOGGBitrate(int bitrate)
|
|
{
|
|
return oggBitrates.Contains(bitrate);
|
|
}
|
|
|
|
public static bool isValidURL(string url)
|
|
{
|
|
return !string.IsNullOrEmpty(url) && (url.StartsWith("file://", StringComparison.OrdinalIgnoreCase) || url.StartsWith(Constants.PREFIX_HTTP, StringComparison.OrdinalIgnoreCase) || url.StartsWith(Constants.PREFIX_HTTPS, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private static float bytesToFloat(byte firstByte, byte secondByte)
|
|
{
|
|
return (float)(short)((secondByte << 8) | firstByte) / 32768f;
|
|
}
|
|
}
|
|
}
|