2012-10-03 99 views
14

我想在逐漸流式傳輸的mp3文件完全加載後移動到SD卡上。有什麼辦法可以實現這一點。訪問媒體播放器緩存

我見過的MediaPlayer完全下載,而漸進式流整個文件,然後我們可以尋求文件的任何部分。我想將完整的流文件移動到外部存儲器,以便將來的播放不會浪費數據和電池。

+2

最佳答案她e,如果有人仍然在尋找解決方案: http://stackoverflow.com/a/12044709/1548464 – Taras

回答

10

在原來的崗位點你在正確的方向上的評論,但我認爲這可能有助於闡明有點...

我所做的是使用娜迦和建立一個輕量級的代理服務器Apache HTTP庫。應該有大量的例子來了解這部分的基礎知識。爲MediaPlayer提供適當的本地主機URL,以便它打開代理的套接字。當MediaPlayer發出請求時,使用代理向實際媒體主機發送等效請求。您將在代理的packetReceived方法中接收byte []數據,該方法用於構建HttpGet並使用AndroidHttpClient發送它。

你會得到一個HttpResponse,你可以使用HttpEntity內訪問流字節數據。我使用的ReadableByteChannel,像這樣:

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

無論你想與數據類的東西,你(在SD卡上的文件就像它緩存)讀取它。爲了將正確的內容傳遞給MediaPlayer,從客戶端Socket獲取SocketChannel,首先將響應頭直接寫入該通道,然後繼續寫入實體的字節數據。我在while循環中使用NIO ByteBuffer(客戶端是Socket,緩衝區是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

我們如何攔截mediaplayer請求? – anz

14

的想法是創建一個媒體播放器可以讀取的,而不是直接從網絡讀取數據,一個代理。

我用danikula/AndroidVideoCache這是非常簡單的建立/使用。 我用它作爲音頻而不是視頻,但它是一樣的。

+1

這應該是正確的答案。直接和易於使用。我希望我能給10票。 – MetaSnarf

+0

如何加密緩存文件? –

3

它的後期,但我發現大多數人仍然需要一個解決方案。我的解決方案基於JakeWharton's DiskLruCache。 我們需要兩樣東西

  • 的AsyncTask讀取文件或從網絡上下載並緩存它

  • 回調從緩存

第1步得到InputStram /的FileDescriptor:

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