2012-11-02 6 views
12

公開URLで入手できるMP3ファイルを再生しているアプリケーションがあります。残念ながら、サーバーはストリーミングをサポートしていませんが、Androidはユーザーエクスペリエンスをかなり受け入れます。Android JellyBeanネットワークメディアの問題

JellyBeanを除くすべてのプラットフォームで問題なく動作します。 MP3を要求するとき、JBはRange-Headerを10回要求する。 10回目の試みの後でさえ、それは古い振る舞いに戻っているようです。 Looks like this already reported issue

もう1つ見つけたSO thread推奨ソリューションは、Tranfer-Encoding:chunkedヘッダーを使用することをお勧めします。しかし、すぐ下には、これがうまくいかないというコメントがあります。

現時点では、私は上記のレスポンスヘッダーを提供することは何もできませんが、私がそれを実行できるようになるまで、私はクライアント側で代替手段を探すことを考えました。 (それでも、0からContent-Length-1までのインデックスを含むContent-Rangeのみを返すことができます。例Content-Range:0-3123456/3123457バイト)。

私は何をしようとしたことにより、擬似ストリーミングクライアント側でを実装することです:

  1. はMP3への入力ストリームを開きます。
  2. JLayerを使用して受信バイトをデコードします。私はthis linkでデコードを見つけました。
  3. デコードされた配列バイトを既に再生可能なstream_mode AudioTrackに送信します。私は時間のチャンクで復号バイトを要求してい

    public byte[] decode(InputStream inputStream, int startMs, int maxMs) throws IOException { 
         ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024); 
    
         float totalMs = 0; 
         boolean seeking = true; 
    
         try { 
          Bitstream bitstream = new Bitstream(inputStream); 
          Decoder decoder = new Decoder(); 
    
          boolean done = false; 
          while (!done) { 
           Header frameHeader = bitstream.readFrame(); 
           if (frameHeader == null) { 
            done = true; 
           } else { 
            totalMs += frameHeader.ms_per_frame(); 
    
            if (totalMs >= startMs) { 
             seeking = false; 
            } 
    
            if (!seeking) { 
             // logger.debug("Handling header: " + frameHeader.layer_string()); 
             SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream); 
    
             if (output.getSampleFrequency() != 44100 || output.getChannelCount() != 2) { 
              throw new IllegalArgumentException("mono or non-44100 MP3 not supported"); 
             } 
    
             short[] pcm = output.getBuffer(); 
             for (short s : pcm) { 
              outStream.write(s & 0xff); 
              outStream.write((s >> 8) & 0xff); 
             } 
            } 
    
            if (totalMs >= (startMs + maxMs)) { 
             done = true; 
            } 
           } 
           bitstream.closeFrame(); 
          } 
    
          return outStream.toByteArray(); 
         } catch (BitstreamException e) { 
          throw new IOException("Bitstream error: " + e); 
         } catch (DecoderException e) { 
          throw new IOException("Decoder error: " + e); 
         } 
        } 
    

    :始まるそれは入力ストリームを受信するよう

復号化を行うコードの部分が見つけることができ、私はそれを変更しました(5000、1000)、(6000、1000)、(7000、1000)、などの次のバイト配列を要求しています。 。

デコードが速く、別のスレッドで実行され、デコードされたバイト配列が利用可能になると、ブロックキューを使用して別のスレッドで再生中のAudioTrackに書き込みます。

問題は、チャンクがトラック内で連続していないためです(各チャンクは連続していますが、AudioTrackに追加すると不自然な再生になります)。

締めくくりには:

  1. あなたはこのJellyBean問題にぶつかっている場合は、どのようにあなたがそれを解決しましたか?
  2. 私のアプローチを試した人は、上記のコードで何が間違っていますか?これがあなたが使用したソリューションであれば、残りのコードを公開することができます。

ありがとう!

答えて

2

独自のストリーミングタイプを開発しようとしているようです。読み込みのためにバイトを使い切って連続した情報パイプ処理を試みなければならないため、ブロック再生や中断再生が発生する可能性があります。

基本的に、通常のストリーミングクライアントが処理するすべての状況を考慮する必要があります。例えば、いくつかのブロックが送信時にドロップされたり失われたりすることがあります。オーディオの再生がダウンロードに追いつくことがあります。再生に影響を与えるCPUの遅れが始まります。

このパスを続行したい場合は、Sliding Windowの実装と同じように、何かを研究する必要があります。本質的には、ネットワークの接続性を常に有効に維持しています。 http://en.wikipedia.org/wiki/Sliding_window_protocol

編集:これが修正されるまで、SDK < 16からMediaPlayer.javaAudioManager.javaのソースコードが含まれるようになり、あなたを助けるかもしれない一つの回避策は、Googleを通していくつかの例を見つけることができる必要があり、ここで開始する場所ですそれが問題を解決するかどうかを確認してください。ソースコードがない場合は、SDKマネージャを使用してソースコードをダウンロードできます。

+0

答えてくれてありがとう...私が必要としていたプロジェクトではこのアプローチに従いたいとは思っていませんが、いつか私は余裕を持っています。オープンな質問がまだ残っています(JellyBeanを除くすべてのプラットフォームでうまくいきます)MP3をリクエストすると、JBはRange-Headerを10回要求します.10回目の試行の後でのみ、古い動作に戻ります。 )これにぶつかったら、どうやってこれを修正しましたか?それはサーバー側からのものか、それともクライアント側のものでしたか? – gunar

+0

この行にコードを含めることができますか: "MP3を要求するとき、JBはRange-Headerを10回要求します.10回目の試行の後でさえ、以前の動作に戻っているようです。 – Matt

+0

JBossでRange-Headerをリクエストするためのコードを追加していないので、[添付のAndroidの問題](https://code.google.com/p/android/issues/detail?id=35790)をご覧ください。それはすべてそれに関連しています。 – gunar

1

AudioTrackは本来docs(Will block until all data has been written to the audio mixer.)からブロックしています。あなたがファイルから読み込んで、AudioTrackに同じスレッドで書き込んでいるかどうかはわかりません。もしそうなら、あなたはAudioTrack用のスレッドをスピンアップすることをお勧めします。