2013-05-06 4 views
8

リモートサーバーからオーディオを再生するアプリケーションを作成しています。私はストリーミングオーディオを実装するいくつかの方法を試しましたが、それらはすべて私にとって十分ではありません。オーディオストリーミングのベストプラクティス

ナイーブMediaPlayerの

のような何か使用して:私が試したものだ リモートプレイするとき

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

(またはprepareAsync、関係なく)

しかし、標準MediaPlayerは非常に不安定であり、コンテンツ。それは頻繁に落ちるか再生を停止し、私はこれを処理することができません。一方、私はメディアキャッシングを実装したいと思います。しかし、MediaPlayerからバッファされたコンテンツを取得して、デバイスのどこかに保存する方法は見つけていません。カスタムバッファリング

を実装

はその後、チャンクでメディアファイルをダウンロードする1つのローカルファイルにそれらを組み合わせて、このファイルを再生するという考えがありました。完全なファイルのダウンロードは、接続不良のために遅くなる可能性があります。最初の部分を十分にダウンロードしてから、再生を開始して、ローカルファイルのダウンロードと追加を続けてください。さらに、我々はキャッシュ機能を得る。

音が計画のようですが、必ずしもうまくいかない場合があります。これはHTC Sensation XEで完全に機能しますが、この最初の部分を終えた後は4.1タブレットの再生を停止しませんでした。わからない、なぜそうだ。私はこのことについてquestionに尋ねましたが、回答はありませんでした。 2 MediaPlayers

私は2つのMediaPlayerのインスタンスを作成し、それらがお互いを変更するために試してみたを使用し

。ロジックは以下の通りです:

  • スタート
  • それがダウンロードされ
  • 、currentMediaPlayerを経由して再生を開始メディアの初期作品をダウンロードします。メディアの残り(これは再生中に添付されたように)、同じソースファイルとcurrentMediaPlayerの仕上げ前
  • 261ミリ秒secondaryMediaPlayerを調製
  • ダウンロード片がほぼ再生さ
  • (仕上げ前に1秒)をダウンロード を継続 - それを一時停止しますセカンダリを開始し、現在のセカンダリとして設定し、次のセカンダリプレーヤーの準備をスケジュールする。

ソース:

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週間私を悩ましています...しかし、私は1つのデバイスから別のデバイスへのビデオストリーミングのために必要... –

+0

オーディオストリーミングのためにあなたはAndroidサービス –

+0

大きな質問...残念ながら、AndroidのMediaPlayerはこれまでに書かれたソフトウェアの中で最悪のものです。 – StackOverflowed

答えて

1

私の場合は、OpenSL ESでFFMPEGを使用します。欠点は複雑です。 JNI、OpenSL、FFMPEGなど、多くのことに慣れている必要があります。デバッグするのも難しいです(純粋なJava android appと比較して)。あなたの場合、私はあなたに低レベルMedia APIを試してみることをお勧めします。唯一の例は、例がないことです。しかし、unit testには、オーディオを扱う方法が示されています(InputStreamリファレンス - 82行を変更する必要があります)。

+1

私はFFMPEGについて考えましたが、使用するのが非常に難しいので、私が試してみる最後のものになります。 Media APIを私に指摘してくれてありがとう、私はこれを試してみましょう。 – darja

関連する問題