Audio stream buffering

前端 未结 5 1307
情歌与酒
情歌与酒 2020-12-04 14:18

I need to play live audio stream, actually it is radio. The problem is that I also need to manage 20 minute buffer for streaming. As far as I understand it\'s not easy to im

相关标签:
5条回答
  • 2020-12-04 14:28

    I use the same StreamProxy that guys used for NPR project - https://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java

    So it gets original audio stream:

      String url = request.getRequestLine().getUri();
      HttpResponse realResponse = download(url);
      ...
      InputStream data = realResponse.getEntity().getContent();
    

    And writes from this stream to client socket:

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

    (You can get whole code from the link above.)

    And finally how they initialize the player (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();
    

    So they check SDK version. But if I omit this check and use proxy for SDK 8 as well I get an exception. It is strange that MediaPlayer even doesn't try to read the stream:

    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)
    

    It seems that MediaPlayer became more clever. And If i pass such url "http://127.0.0.1:%d/%s" it wants to get not only bytes but "full" http responce.

    Also I wonder if there any other ways implement buffering? As I know the MediaPlayer consumes only files and urls. Solution with files doesn't work. So I have to use socket for stream transmitting.

    Thanks

    0 讨论(0)
  • 2020-12-04 14:29

    I realise this Question is like 5 years old but in case some one else is wandering: ExoPlayer is library from Google that gives you much more control over options like buffer size.

        //DefaultUriDataSource – For playing media that can be either local or loaded over the network.
        DefaultUriDataSource dataSource = new DefaultUriDataSource(WgtechApplication.getAppContext(),
                Util.getUserAgent(WgtechApplication.getAppContext(), WgtechApplication.class.getSimpleName()));
        Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
    
        //ExtractorSampleSource – For formats such as MP3, M4A, MP4, WebM, MPEG-TS and AAC.
        ExtractorSampleSource sampleSource = new ExtractorSampleSource(Uri.parse(RADIO_STREAMING_URL),
                dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
        player.prepare(new MediaCodecAudioTrackRenderer(sampleSource));
    

    Here's a small project I created to learn how to use it. https://github.com/feresr/MyMediaPlayer

    http://developer.android.com/guide/topics/media/exoplayer.html https://github.com/google/ExoPlayer

    0 讨论(0)
  • 2020-12-04 14:37

    When you seek or skip or the connection is lost and MediaPlayer keeps reconnecting to the proxy server, you must send this response with Status 206 after you get the request and range(int) from the client.

    String headers += "HTTP/1.1 206 Partial Content\r\n";
    headers += "Content-Type: audio/mpeg\r\n";
    headers += "Accept-Ranges: bytes\r\n";
    headers += "Content-Length: " + (fileSize-range) + "\r\n";
    headers += "Content-Range: bytes "+range + "-" + fileSize + "/*\r\n";
    headers += "\r\n";
    

    And when you receive a request from MediaPlayer that does not contain Range in the HTTP header , then it is requesting a new stream file, in this case your response header should look like this:

    String headers = "HTTP/1.1 200 OK\r\n";
    headers += "Content-Type: audio/mpeg\r\n";
    headers += "Accept-Ranges: bytes\r\n";
    headers += "Content-Length: " + fileSize + "\r\n";
    headers += "\r\n";
    

    Enjoy!

    0 讨论(0)
  • 2020-12-04 14:41

    I just tested the following fix, and it works. This issue is caused by the "\n" used in the headers in the processRequest() method of StreamProxy. Changing this to "\r\n" should make the error go away.

    As for implementing custom streaming, I've used this in the past, though it seems to be mainly for infinitely streaming radio. http://blog.pocketjourney.com/2009/12/27/android-streaming-mediaplayer-tutorial-updated-to-v1-5-cupcake/

    0 讨论(0)
  • 2020-12-04 14:42

    The Mediaplayer from SDK 8 would not be able to read a proxy url. But based on my current work, this is differing from device to device. In my Samsung ACE (SDK 8) the proxy connection works fine, but in my HTC Incredible S, the proxy connection would give the same issue as you have. A direct connection to the audio stream works fine but this causes blips and boops in some devices like EVO on sprint.

    Did you get a resolution for this issue? How did you handle this?

    -Hari

    0 讨论(0)
提交回复
热议问题