Android - 播放一首仍在下载的歌曲

Android - Play a song that is still downloading

我正在创建一个应用程序,其中多个设备可以在 LAN 中相互连接并播放彼此设备中的歌曲。

现在,当设备 A 从设备 B 请求歌曲时,B 通过套接字将歌曲文件发送回 A。歌曲下载完成后,A 开始播放 MediaPlayer

现在的问题是,即使在高速 LAN 上,也可能需要几秒钟才能完成提取歌曲,因此在选择歌曲和实际开始播放之间存在明显的延迟。

我想找到一种方法来播放正在下载的歌曲。以下是我找到的一些可能的解决方案,但由于某些原因无法探索:

  1. MediaPlayer 文档中,我注意到一个采用 MediaDataSource 实现的构造函数允许我在 MediaPlayer 需要时手动 return 部分媒体文件这样我就可以推迟 returning 一个字节,直到它完成下载(如果它还没有完成下载的话),实际上就像一个“缓冲”动作。这似乎是一个解决方案,但不幸的是,我的应用程序的 minSdk 设置为 16,MediaDataSource 仅适用于 23 及以上,所以我无法尝试。

  2. 一个选择是使用MediaPlayersetDataSource(FileDescriptor fd, long offset, long length)方法。这将允许我告诉 MediaPlayer 只播放歌曲的特定字节。这样,我可以等待文件的更多部分(或整个文件)变得可用,然后使用 setNextMediaPlayer() 并传入一个新的 MediaPlayer 对象,该对象准备整首歌曲并查找到之前的媒体播放器对象将停止播放的点,以便进行无缝过渡。 但这还有另一个问题。我需要能够计算在第一个不完整的媒体播放器对象的最后指定字节到达的毫秒位置。否则我将不知道要将下一个媒体播放器对象定位到什么位置才能实现无缝过渡。对于有损格式,这种计算似乎是不可能的。

  3. 我真的不知道这个选项是否有效,我只是在做假设。我注意到 setDataSource() 需要一个 Uri。如果该 Uri 指向 phone 上的文件,媒体播放器只会加载整个文件。但是,如果 Uri 指向互联网上需要流式传输的音频文件,它会自行计算出来并处理下载和缓冲的所有细节。所以我想知道的是,是否可以将设备 B 上的歌曲作为 Uri 公开给设备 A,以便媒体播放器将其视为互联网上的歌曲?这段时间我一直在使用套接字并手动将文件从一台设备复制到另一台设备,所以我不知道这将如何工作。谁能解释一下这是否可能?

    我一直没有探索将歌曲从一台设备“流式传输”到另一台设备的方法实际上是有原因的。那是因为我想将歌曲缓存在设备 B 上,这样以后如果我切换到另一首歌曲,然后从设备 A 返回之前播放的歌曲,就不必再次播放它。它应该只播放缓存的副本。

  4. 终于遇到了ExoPlayer。它似乎提供了大量的定制。看来我可以自定义实现它的 类 来处理所有缓冲。但是文档和示例很少,而且对我来说太复杂了。我不知道如何完成它。这个解决方案对于我想要实现的目标来说是否太复杂了?

希望有人能在这里为我指明正确的方向。

最终使用了此处的答案:

MediaPlayer stutters at start of mp3 playback

此解决方案设置一个本地服务器,MediaPlayer 可使用该服务器流式传输文件。当这些字节可用时,服务器仅向 MediaPlayer 发送字节。否则,它将阻塞直到有更多字节可用。因此 MediaPlayer 对其进行缓冲,就好像它是来自网络服务器的文件一样。

我采用了该答案中提供的相同 class,只是对其进行了调整以适应我的情况。