我有一个Xamarin应用程序,它使用 MediaPlayer 通过以下设置播放远程(互联网)音频文件:
_mediaPlayer.SetDataSource(mediaUri);
_mediaPlayer.PrepareAsync();
现在,我想将实现更改为还缓存文件。对于缓存部分,我找到了一个非常好的库MonkeyCache,该库以JSON格式保存文件:
{"$type":"System.Byte[], mscorlib","$value":"UklGRhAoAgBXQVZFZm10IBAAAAABAAIARKwAABCxAgAEABAAZGF0YdAnAgAAAAAAAAAAAAAAAAAA+P/4/+z/7P8KAAoA7//v//L/8v8JAAkA6f/p//j/+P8FAAUA6P/o/wEAAQD+//7/5//n ................."}
所以我的MediaPlayer设置现在已更改为:
if (Barrel.Current.Exists(mediaUri)){
var audio = Barrel.Current.Get<byte[]>(mediaUri);
_mediaPlayer.SetDataSource(???);
}else{
using (var webClient = new WebClient()){
var downloadDataBytes = webClient.DownloadData(mediaUri);
if (downloadDataBytes != null && downloadDataBytes.Length > 0)
{
Barrel.Current.Add(mediaUri, downloadDataBytes, TimeSpan.FromDays(1));
_mediaPlayer.SetDataSource(???);
}
}
}
我想从byte []而不是mediaUri播放音频。 有什么办法可以实际播放内存字节[]?
我唯一能找到的解决方案是使用文件路径从文件中创建 FileInputStream ,但是实现了 MonkeyCache >在添加文件名称之前实际上对其进行哈希处理:
static string Hash(string input){
var md5Hasher = MD5.Create();
var data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
return BitConverter.ToString(data);
}
因此,下载的字节将保存在以下位置:
/data/data/com.package.name.example/cache/com.package.name.example/MonkeyCacheFS/81-D6-E8-62-F3-4D-F1-64-A6-A1-53-46-34-1E-FE-D1
即使我自己使用相同的散列逻辑实际计算文件路径并使用 FileInputStream (可能已按我所读的内容工作),也会破坏使用MonkeyCache的var audio = Barrel.Current.Get<byte[]>(mediaUri);
功能。
但是,如果那是唯一的方法,我会做到的。
编辑:即使使用我描述的方法,它也可能无法立即运行,因为即使我计算出正确的文件名,它仍然是JSON格式。
Edit2:可行的解决方案是:
var audio = Barrel.Current.Get<byte[]>(mediaUri);
var url = "data:audio/mp3;base64," + Convert.ToBase64String(audio);
_mediaPlayer.SetDataSource(url);
答案 0 :(得分:0)
最后想通了:
MediaPlayer.SetDataSource 方法具有一个重载,该重载需要一个MediaDataSource对象。
MediaDataSource
用于向框架提供媒体数据。实行 如果您的应用对媒体数据的处理方式有特殊要求,则为 获得
因此,您可以使用MediaDataSource的实现并将其提供给您的字节数组。
public class StreamMediaDataSource : MediaDataSource
{
private byte[] _data;
public StreamMediaDataSource(byte[] data)
{
_data = data;
}
public override long Size
=> _data.Length;
public override void Close()
{
_data = null;
}
public override int ReadAt(long position, byte[] buffer, int offset, int size)
{
if (position >= _data.Length)
{
return -1;
}
if (position + size > _data.Length)
{
size -= (Convert.ToInt32(position) + size) - _data.Length;
}
Array.Copy(_data, position, buffer, offset, size);
return size;
}
}
这将导致MediaPlayer数据源成为
_mediaPlayer.SetDataSource(new StreamMediaDataSource(downloadedDataBytes));
编辑:这仅适用于API> =23。我仍然必须找到API <23(我仍然没有)的解决方案。
Edit2:对于API <23支持,我使用了
var url = $"data:audio;base64,{Convert.ToBase64String(downloadedDataBytes)}";
_mediaPlayer.SetDataSource(url);
方法。