我正在編寫一個應用程序來播放來自遠程服務器的音頻。我嘗試了幾種實現流音頻的方式,但對我來說它們都不夠好。 這就是我已經試過:音頻流的最佳做法
樸素使用的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平板電腦播放。不知道,爲什麼如此。我問過question這個問題,但沒有收到答案。
使用兩個MediaPlayers
我已經創建了兩個實例的MediaPlayer,並試圖讓他們改變對方。所述邏輯被以下:
- 啓動下載初始一段媒體
- 當被下載,經由currentMediaPlayer開始播放。媒體的其餘部分繼續 下載
- 當下載件幾乎播放(結束前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;
}
};
再次 - 的聲音,像一個計劃,但工作不完美。切換MediaPlayers的時刻非常可靠。在這裏我有相反的情況:在4.1平板電腦上沒問題,但在HTC Sensation上有明顯的滯後。
我也嘗試實現不同的下載技術。我已經實現了10Kb塊和MP3幀的下載。我不完全知道,但似乎在MP3幀seekTo的情況下,並開始工作更好。但這只是一種感覺,我不知道解釋。
StreamingMediaPlayer
我看到這個詞幾次,而谷歌搜索,發現這個實現:https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18
它是一個解決方案大家使用?
如果是的話,那很傷心,因爲它對我也不好。我沒有看到任何新的想法在實施。
因此,問題
你們如何在你的應用程序中實現音頻流?我不相信我是唯一遇到這種問題的人。應該有一些好的做法。
非常好的問題...它也在過去的2個星期裏困擾着我......但我需要它從一個設備到另一個設備的視頻流...... – 2013-05-11 08:26:46
音頻流你應該使用你自己的定製播放器與Android服務 – 2013-07-12 14:28:55
很好的問題......不幸的是,Android的MediaPlayer是有史以來最糟糕的軟件之一。 – StackOverflowed 2013-11-04 04:46:18