访问媒体播放器caching

一旦完全加载,我想将渐进stream式传输的mp3文件移动到SD卡上。 有什么办法可以达到这个目的吗?

我已经看到, MediaPlayer完全下载整个文件,而渐进式stream媒体,然后我们可以寻求文件的任何部分。 我想将完整的stream文件移动到外部存储器,以便将来的播放不会浪费数据和电池。

原帖的评论指出你的方向是正确的,但是我认为可能有助于阐述一下。

我所做的是使用Naga和Apache HTTP库构build一个轻量级代理服务器。 应该有大量的例子来获得这部分的基础知识。 向MediaPlayer提供适当的本地主机URL,以便它打开代理的套接字。 当MediaPlayer发出请求时,使用代理向实际的媒体主机发送一个等效的请求。 您将在代理的packetReceived方法中接收byte []数据,该方法用于构build一个HttpGet并使用AndroidHttpClient发送它。

你将得到一个HttpResponse,你可以使用里面的HttpEntity来访问stream式字节数据。 我正在使用一个ReadableByteChannel,如下所示:

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

在读取数据时,随心所欲地处理数据(如将其caching在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的专有实现,因此行为可能会有所不同。 希望有所帮助。

这个想法是创build一个代理媒体播放器可以读取,而不是直接从网上读取数据。

我使用了非常简单的构build/使用的danikula / AndroidVideoCache 。 我用它的audio不是video,但它是一样的。

它的晚,但我发现大多数人仍然需要一个解决scheme。 我的解决scheme基于JakeWharton的DiskLruCache 。 我们需要两件事

  • AsyncTask读取文件或从networking下载并caching它

  • callback从caching中获取InputStram / FileDescriptor

步骤1:

 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); 

注意:

这是testing,但audio文件caching粗略的样品,如果你发现任何东西,可能会有一些问题,请通知我:)