2013-05-06 53 views
8

我正在編寫一個應用程序來播放來自遠程服務器的音頻。我嘗試了幾種實現流音頻的方式,但對我來說它們都不夠好。 這就是我已經試過:音頻流的最佳做法

樸素使用的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

它是一個解決方案大家使用?

如果是的話,那很傷心,因爲它對我也不好。我沒有看到任何新的想法在實施。

因此,問題

你們如何在你的應用程序中實現音頻流?我不相信我是唯一遇到這種問題的人。應該有一些好的做法。

+0

非常好的問題...它也在過去的2個星期裏困擾着我......但我需要它從一個設備到另一個設備的視頻流...... – 2013-05-11 08:26:46

+0

音頻流你應該使用你自己的定製播放器與Android服務 – 2013-07-12 14:28:55

+0

很好的問題......不幸的是,Android的MediaPlayer是有史以來最糟糕的軟件之一。 – StackOverflowed 2013-11-04 04:46:18

回答

1

在我的情況下,我使用FFMPEG與OpenSL ES。缺點是複雜性。你必須熟悉很多東西:JNI,OpenSL,FFMPEG。這也很難調試(與純java的android應用程序比較)。在你的情況下,我建議你嘗試低水平Media API。唯一的例子就是缺乏實例。但有一個unit test它顯示瞭如何處理音頻(您需要更改InputStream參考 - 第82行)。

+1

我曾想過FFMPEG,但這將是我將嘗試的最後一件事,因爲它非常難以使用。感謝您在Media API上指點我,我會試試這個。 – darja 2013-05-07 07:16:35