2012-10-03 11 views
14

完全にロードされると、徐々にストリーミングされたmp3ファイルをsdカードに移動したいと思います。それを達成する方法はありますか?メディアプレーヤーキャッシュへのアクセスを取得する

私は、MediaPlayerがプログレッシブストリーミング中にファイル全体を完全にダウンロードしてから、ファイルの任意の部分にシークできることを確認しました。完全にストリーミングされたファイルを外部ストレージに移動して、将来の再生でデータやバッテリーを浪費しないようにしたい。私がやった何

はナガを使用した軽量プロキシサーバーを構築している

+2

誰かがまだ解決策を探している場合は、 http://stackoverflow.com/a/12044709/1548464 – Taras

答えて

10

右方向へのオリジナルポストポイントにコメントしますが、私は少しを言えば、役立つかもしれないと思いました... Apache HTTPライブラリー。この部分の基本を理解するための例がたくさんあるはずです。適切なローカルホストURLをMediaPlayerに提供し、プロキシへのソケットを開きます。 MediaPlayerが要求すると、プロキシを使用して、同等の要求を実際のメディアホストに送信します。私は、HttpGetを構築し、AndroidHttpClientで途中で送信するために使用する、プロキシのpacketReceivedメソッドでbyte []データを受け取ります。

HttpResponseが返され、内部でHttpEntityを使用してストリーミングバイトデータにアクセスできます。私はそうのように、ReadableByteChannelを使用しています:あなたは(SDカード上のファイルにキャッシュそれのように)戻ってそれを読んで

HttpEntityWrapper entity = (HttpEntityWrapper)response.getEntity(); 
ReadableByteChannel src = Channels.newChannel(entity.getContent()); 

はあなたがデータでみたいドゥ何でも。正しいものをMediaPlayerに渡すには、クライアントソケットからSocketChannelを取得し、まずレスポンスヘッダーをそのチャネルに直接書き込んだ後、エンティティのバイトデータを書き出します。 whileループでNIO ByteBufferを使用しています(クライアントはソケットで、バッファはByteBufferです)。

int read, written; 
SocketChannel dst = client.getChannel(); 
while (dst.isConnected() && 
    dst.isOpen() && 
    src.isOpen() && 
    (read = src.read(buffer)) >= 0) { 
    try { 
     buffer.flip(); 
     // This is one point where you can access the stream data. 
     // Just remember to reset the buffer position before trying 
     // to write to the destination. 
     if (buffer.hasRemaining()) { 
      written = dst.write(buffer); 
      // If the player isn't reading, wait a bit. 
      if (written == 0) Thread.sleep(15); 
      buffer.compact(); 
     } 
    } 
    catch (IOException ex) { 
     // handle error 
    } 
} 

ので行動プロキシが送信者であるように見えるようにするには、プレイヤーに沿って、それを渡す前に応答して、ホストヘッダーを変更する必要があるかもしれませんが、私はMediaPlayerのの独自の実装を扱っていますちょっと違うかもしれません。希望が役立ちます。

+2

プロキシの作成方法とデータのインターセプトに関するコードをいくつか共有できますか? – anz

+0

メディアプレーヤーのリクエストを傍受するにはどうすればよいですか? – anz

14

ウェブから直接データを読み込む代わりに、メディアプレーヤーが読むことができるプロキシを作成することです。

私はdanikula/AndroidVideoCacheを使用しましたが、これは構築/使用が非常に簡単です。 私はオーディオではないビデオのためにそれを使用しましたが、まったく同じです。

+1

これは正解です。直接かつ使いやすい。私は10票を与えることができたらいいと思う。 – MetaSnarf

+0

キャッシュファイルはどのように暗号化できますか? –

3

その後半でしたが、ほとんどの人が解決策を必要としていることがわかりました。私の解決策はJakeWharton's DiskLruCacheに基づいています。

: 我々はキャッシュ

ステップ1からInputStram /のFileDescriptorを取得するには、ファイルを読み取りまたはネットワークからダウンロードし、それが

  • コールバックをキャッシュする二つのこと

    • AsyncTaskを必要とします

      import android.content.Context; 
      import android.os.AsyncTask; 
      import org.apache.commons.io.IOUtils; 
      import java.io.FileInputStream; 
      import java.io.IOException; 
      import java.io.InputStream; 
      import java.io.OutputStream; 
      import java.net.HttpURLConnection; 
      import java.net.URL; 
      
      // you can use FileDescriptor as 
      // extends AsyncTask<String, Void, FileDescriptor> 
      
      public class AudioStreamWorkerTask extends AsyncTask<String, Void, FileInputStream> { 
      
          private OnCacheCallback callback = null; 
          private Context context = null; 
      
          public AudioStreamWorkerTask(Context context, OnCacheCallback callback) { 
           this.context = context; 
           this.callback = callback; 
          } 
      
          @Override 
          protected FileInputStream doInBackground(String... params) { 
           String data = params[0]; 
           // Application class where i did open DiskLruCache 
           DiskLruCache cache = MyApplication.getDiskCache(context); 
           if (cache == null) 
            return null; 
           String key = hashKeyForDisk(data); 
           final int DISK_CACHE_INDEX = 0; 
           long currentMaxSize = cache.getMaxSize(); 
           float percentageSize = Math.round((cache.size() * 100.0f)/currentMaxSize); 
           if (percentageSize >= 90) // cache size reaches 90% 
            cache.setMaxSize(currentMaxSize + (10 * 1024 * 1024)); // increase size to 10MB 
           try { 
            DiskLruCache.Snapshot snapshot = cache.get(key); 
            if (snapshot == null) { 
             Log.i(getTag(), "Snapshot is not available downloading..."); 
             DiskLruCache.Editor editor = cache.edit(key); 
             if (editor != null) { 
              if (downloadUrlToStream(data, editor.newOutputStream(DISK_CACHE_INDEX))) 
               editor.commit(); 
              else 
               editor.abort(); 
             } 
             snapshot = cache.get(key); 
            } else 
             Log.i(getTag(), "Snapshot found sending"); 
            if (snapshot != null) 
             return (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX); 
           } catch (IOException e) { 
            e.printStackTrace(); 
           } 
           Log.i(getTag(), "File stream is null"); 
           return null; 
          } 
      
          @Override 
          protected void onPostExecute(FileInputStream fileInputStream) { 
           super.onPostExecute(fileInputStream); 
           if (callback != null) { 
            if (fileInputStream != null) 
             callback.onSuccess(fileInputStream); 
            else 
             callback.onError(); 
           } 
           callback = null; 
           context = null; 
          } 
      
          public boolean downloadUrlToStream(String urlString, OutputStream outputStream) { 
           HttpURLConnection urlConnection = null; 
           try { 
            final URL url = new URL(urlString); 
            urlConnection = (HttpURLConnection) url.openConnection(); 
            InputStream stream = urlConnection.getInputStream(); 
            // you can use BufferedInputStream and BufferOuInputStream 
            IOUtils.copy(stream, outputStream); 
            IOUtils.closeQuietly(outputStream); 
            IOUtils.closeQuietly(stream); 
            Log.i(getTag(), "Stream closed all done"); 
            return true; 
           } catch (final IOException e) { 
            e.printStackTrace(); 
           } finally { 
            if (urlConnection != null) 
             IOUtils.close(urlConnection); 
           } 
           return false; 
          } 
      
          private String getTag() { 
           return getClass().getSimpleName(); 
          } 
      
          private String hashKeyForDisk(String key) { 
           String cacheKey; 
           try { 
            final MessageDigest mDigest = MessageDigest.getInstance("MD5"); 
            mDigest.update(key.getBytes()); 
            cacheKey = bytesToHexString(mDigest.digest()); 
           } catch (NoSuchAlgorithmException e) { 
            cacheKey = String.valueOf(key.hashCode()); 
           } 
           return cacheKey; 
          } 
      
          private String bytesToHexString(byte[] bytes) { 
           // http://stackoverflow.com/questions/332079 
           StringBuilder sb = new StringBuilder(); 
           for (byte aByte : bytes) { 
            String hex = Integer.toHexString(0xFF & aByte); 
            if (hex.length() == 1) 
             sb.append('0'); 
            sb.append(hex); 
           } 
           return sb.toString(); 
          } 
      } 
      

      ステップ2:

      public interface OnCacheCallback { 
      
          void onSuccess(FileInputStream stream); 
      
          void onError(); 
      } 
      

      final String path = "http://www.example.com/test.mp3"; 
      new AudioStreamWorkerTask (TestActivity.this, new OnCacheCallback() { 
      
      @Override 
      public void onSuccess(FileInputStream fileInputStream) { 
          Log.i(getClass().getSimpleName() + ".MediaPlayer", "now playing..."); 
          if (fileInputStream != null) { 
           // reset media player here if necessary 
           mediaPlayer = new MediaPlayer(); 
           try { 
            mediaPlayer.setDataSource(fileInputStream.getFD()); 
            mediaPlayer.prepare(); 
            mediaPlayer.setVolume(1f, 1f); 
            mediaPlayer.setLooping(false); 
            mediaPlayer.start(); 
            fileInputStream.close(); 
           } catch (IOException | IllegalStateException e) { 
            e.printStackTrace(); 
           } 
          } else { 
           Log.e(getClass().getSimpleName() + ".MediaPlayer", "fileDescriptor is not valid"); 
          } 
      } 
      
      @Override 
      public void onError() { 
          Log.e(getClass().getSimpleName() + ".MediaPlayer", "Can't play audio file"); 
      } 
      }).execute(path); 
      

      注:

      これはテストされていますが、発見した場合、オーディオファイルキャッシングの大まかなサンプルは、いくつかの問題があるかもしれません何でもお知らせください:)

  • +0

    このアプリケーションが意味することは何ですか?DiskLruCacheを開いたアプリケーションクラス – Naz141

    +0

    アプリケーションクラスでDiskLruCacheを初期化しますか(アプリケーションで拡張しますか)、またはいつでもどこでも好きです。 –

    +0

    DiskLruCacheの初期化を書きました。ありがとうございます – Naz141

    関連する問題