音频流缓冲

Eug*_*ous 21 proxy android stream buffering media-player

我需要播放实时音频流,实际上它是无线电.问题是我还需要管理20分钟的流量缓冲区.据我所知,用android实现起来并不容易.

首先我检查了MediaPlayer,但它没有提供任何缓冲区管理方法.实际上你甚至无法直接设置缓冲区大小.

其次,我尝试使用本地文件管理缓冲区:逐步将流下载到临时文件并切换它们.但是当您想切换到以下文件(在MediaPlayer中更改数据源)时,音频不会连续播放.你可以听到短暂的中断.

最后一个想法是使用流代理.通常它用于在8以下的Android版本中播放流.在流代理中,您创建ServerSocket,从音频流中读取并写入播放器.所以实际上我可以在那里管理缓冲.我可以缓存流并写入MediaPlayer,无论我想要什么.但.它不适用于Android 8.

我得到异常:通过对等java.net.SocketException重置连接:由peer重置连接.MediaPlayer 8不想从套接字读取数据.

因此,我有两个问题:1)实现流缓冲的其他方法是什么?2)如何为Android 8改编StreamProxy?

任何想法都表示赞赏.

谢谢

Eug*_*ous 8

我使用与NPR项目相同的StreamProxy - https://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java

所以它获得原始音频流:

  String url = request.getRequestLine().getUri();
  HttpResponse realResponse = download(url);
  ...
  InputStream data = realResponse.getEntity().getContent();
Run Code Online (Sandbox Code Playgroud)

并从此流写入客户端套接字:

  byte[] buff = new byte[1024 * 50];
  while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
    client.getOutputStream().write(buff, 0, readBytes);
  }
Run Code Online (Sandbox Code Playgroud)

(您可以从上面的链接获取完整的代码.)

最后他们如何初始化播放器(PlaybackService):

  if (stream && sdkVersion < 8) {
    if (proxy == null) {
      proxy = new StreamProxy();
      proxy.init();
      proxy.start();
    }
    String proxyUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
    playUrl = proxyUrl;
   }
  ...
  mediaPlayer.setDataSource(playUrl);
  mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  mediaPlayer.prepareAsync();
Run Code Online (Sandbox Code Playgroud)

所以他们检查SDK版本.但是,如果我省略此检查并使用SDK 8的代理,我会得到一个例外.奇怪的是MediaPlayer甚至没有尝试读取流:

12-30 15:09:41.576: DEBUG/StreamProxy(266): downloading...
12-30 15:09:41.597: DEBUG/StreamProxy(266): reading headers
12-30 15:09:41.597: DEBUG/StreamProxy(266): headers done
12-30 15:09:41.647: DEBUG/StreamProxy(266): writing to client
12-30 15:09:41.857: INFO/AwesomePlayer(34): mConnectingDataSource->connect() returned -    1007
12-30 15:09:41.857: ERROR/MediaPlayer(266): error (1, -1007)
12-30 15:09:41.867: ERROR/MediaPlayer(266): Error (1,-1007)
12-30 15:09:41.867: WARN/AudioService(266): onError(1, -1007)
12-30 15:09:41.867: WARN/AudioService(266): MediaPlayer refused to play current item.  Bailing on prepare.
12-30 15:09:41.867: WARN/AudioService(266): onComplete()
12-30 15:09:42.097: ERROR/StreamProxy(266): Connection reset by peer
        java.net.SocketException: Connection reset by peer
        at org.apache.harmony.luni.platform.OSNetworkSystem.writeSocketImpl(Native Method)
        at org.apache.harmony.luni.platform.OSNetworkSystem.write(OSNetworkSystem.java:723)
        at org.apache.harmony.luni.net.PlainSocketImpl.write(PlainSocketImpl.java:578)
        at org.apache.harmony.luni.net.SocketOutputStream.write(SocketOutputStream.java:59)
        at com.skyblue.service.media.StreamProxy.processRequest(StreamProxy.java:204)
        at com.skyblue.service.media.StreamProxy.run(StreamProxy.java:103)
        at java.lang.Thread.run(Thread.java:1096)
Run Code Online (Sandbox Code Playgroud)

似乎MediaPlayer变得更加聪明.如果我通过这样的网址,"http://127.0.0.1:%d/%s"它不仅要获得字节,还要获得"完整"的http响应.

另外我想知道是否有其他方法实现缓冲?据我所知,MediaPlayer只使用文件和网址.文件解决方案不起作用.所以我必须使用socket进行流传输.

谢谢

  • 您好Eugenious,您发布的NPR项目链接不再退出,您可以发布有效链接吗? (2认同)

bra*_*ack 5

我刚刚测试了以下修复程序,它可以工作.此问题是由方法中的标头中使用的"\n"引起processRequest()StreamProxy.将其更改为"\ r \n"应该会使错误消失.

至于实现自定义流媒体,我过去曾经使用过它,虽然它似乎主要用于无限流媒体广播. http://blog.pocketjourney.com/2009/12/27/android-streaming-mediaplayer-tutorial-updated-to-v1-5-cupcake/