gpt4 book ai didi

android - 音频流的最佳实践

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:02:07 28 4
gpt4 key购买 nike

我正在编写一个应用程序来播放来自远程服务器的音频。我尝试了几种实现流式音频的方法,但它们对我来说都不够好。这就是我尝试过的:

MediaPlayer 的简单使用

类似于:

MediaPlayer player = new MediaPlayer(); 
player.setDataSource(context, Uri.parse("http://whatever.com/track.mp3"));
player.prepare();
player.start();

(或prepareAsync,无所谓)

但标准 MediaPlayer 在播放远程内容时非常不稳定。它经常跌倒或停止播放,我无法处理。另一方面,我想实现媒体缓存。但我还没有找到任何方法从 MediaPlayer 获取缓冲内容以将其保存在设备上的某个位置。

实现自定义缓冲

然后就有了一个想法,就是分块下载媒体文件,将它们组合成一个本地文件并播放这个文件。由于连接不良,下载整个文件可能会很慢,所以最初下载足够的片断就可以了,然后开始播放并继续下载和附加本地文件。此外,我们还获得了缓存功能。

听起来像是一个计划,但并不总是奏效。它在 HTC Sensation XE 上完美运行,但在 4.1 平板电脑上播放完这个初始 fragment 后没有停止播放。不知道,为什么会这样。我问过question关于这个,但没有收到任何答复。

使用两个 MediaPlayer

我创建了两个 MediaPlayer 实例并试图让它们相互改变。逻辑如下:

  • 开始下载初始媒体
  • 下载完成后,通过 currentMediaPlayer 开始播放。其余媒体继续下载
  • 当下载的 fragment 快要播放时(完成前 1 秒),使用相同的源文件准备 secondaryMediaPlayer(因为它是在播放期间附加的)
  • currentMediaPlayer 结束前 261 毫秒 - 暂停它,启动辅助播放器,将辅助播放器设置为当前播放器,安排准备下一个辅助播放器。

来源:

private static final String FILE_NAME="local.mp3";
private static final String URL = ...;
private static final long FILE_SIZE = 7084032;

private static final long PREPARE_NEXT_PLAYER_OFFSET = 1000;
private static final int START_NEXT_OFFSET = 261;

private static final int INIT_PERCENTAGE = 3;

private MediaPlayer mPlayer;
private MediaPlayer mSecondaryPlayer;

private Handler mHandler = new Handler();

public void startDownload() {
mDownloader = new Mp3Downloader(FILE_NAME, URL, getExternalCacheDir());
mDownloader.setDownloadListener(mInitDownloadListener);
mDownloader.startDownload();
}


private Mp3Downloader.DownloadListener mInitDownloadListener = new Mp3Downloader.DownloadListener() {
public void onDownloaded(long bytes) {
int percentage = Math.round(bytes * 100f / FILE_SIZE);

// Start playback when appropriate piece of media downloaded
if (percentage >= INIT_PERCENTAGE) {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mPlayer.prepare();
mPlayer.start();

mHandler.postDelayed(prepareSecondaryPlayerRunnable, mPlayer.getDuration() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mPlayer.getDuration() - START_NEXT_OFFSET);

} catch (IOException e) {
Log.e(e);
}

mDownloader.setDownloadListener(null);
}
}
};

// Starting to prepare secondary MediaPlayer
private Runnable prepareSecondaryPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer = new MediaPlayer();
try {
mSecondaryPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mSecondaryPlayer.prepare();
mSecondaryPlayer.seekTo(mPlayer.getDuration() - START_NEXT_OFFSET);

} catch (IOException e) {
Log.e(e);
}
}
};

// Starting secondary MediaPlayer playback, scheduling creating next MediaPlayer
private Runnable startNextPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer.start();

mHandler.postDelayed(prepareSecondaryPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - START_NEXT_OFFSET);

mPlayer.pause();
mPlayer.release();

mPlayer = mSecondaryPlayer;

}
};

同样——听起来像是一个计划,但效果并不完美。切换 MediaPlayer 的时刻非常好听。我这里有相反的情况:在 4.1 平板电脑上还可以,但在 HTC Sensation 上有明显的滞后。

我还尝试实现不同的下载技术。我已经通过 10Kb block 和 MP3 帧实现了下载。我不太清楚,但似乎在 MP3 帧的情况下 seekTo 和 start 工作得更好。但这只是一种感觉,我不知道解释。

流媒体播放器

我在谷歌搜索时多次看到这个词,并找到了这个实现:https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18

这是每个人都使用的解决方案吗?

如果是,那很可悲,因为它对我也不好。而且我在实现中没有看到任何新的想法。

所以,问题

你们如何在您的应用程序中实现音频流?我不相信我是唯一遇到过此类问题的人。应该有一些好的做法。

最佳答案

在我的例子中,我将 FFMPEG 与 OpenSL ES 结合使用。缺点是复杂。你必须熟悉很多东西:JNI、OpenSL、FFMPEG。它也很难调试(与纯 java android 应用程序相比)。在你的情况下,我建议你尝试低级别 Media API .唯一的问题是缺乏例子。但是有一个unit test它显示了如何处理音频(您需要更改 InputStream 引用 - 第 82 行)。

关于android - 音频流的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16405017/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com