如何在Android

时间:2019-01-15 07:58:35

标签: android xamarin xamarin.android android-mediaplayer

我有一个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);

1 个答案:

答案 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);

方法。