Android - MediaPlayer Buffer Size in ICS 4.0

15,443

Would it be possible to see the code where you're start()ing the MediaPlayer?

Are you using the STREAM_MUSIC audio stream type?

player.setAudioStreamType(AudioManager.STREAM_MUSIC);

Have you also experimented between player.prepareAsync(); and player.prepare();?

There was a similar issue last year I remember, where the solution was to: start, pause and then onPrepared to start():

player.setAudioStreamType(AudioManager.STREAM_MUSIC); 
player.setDataSource(src); 
player.prepare(); 
player.start(); 
player.pause(); 
player.setOnPreparedListener(new OnPreparedListener() {     
@Override
                public void onPrepared(MediaPlayer mp) {
                    player.start();                
                }
          });

Unlikely to be the fix in this case, but while you're spinning your wheels this might be worth a shot.

Share:
15,443
denizmveli
Author by

denizmveli

Head of Engineering @ Loup. Previously at iflix AU, Etsy... More from me at themodernink.com

Updated on July 16, 2022

Comments

  • denizmveli
    denizmveli almost 2 years

    I'm using a socket as a proxy to the MediaPlayer so I can download and decrypt mp3 audio before writing it to the socket. This is similar to the example shown in the NPR news app however I'm using this for all Android version 2.1 - 4 atm.

    NPR StreamProxy code - http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java

    My issue is that playback is fast for 2.1 - 2.3, but in Android 4.0 ICS the MediaPlayer buffers too much data before firing the onPrepared listener.

    An example amount of data written to the Socket OutputStream before onPrepared():

    On SGS2 with 2.3.4 - onPrepared() after ~ 133920 bytes

    On Nexus S with 4.0.4 - onPrepared() after ~ 961930 bytes

    This also occurs on the Galaxy Nexus.

    Weirdly the 4.0 emulator doesn't buffer as much data as 4.0 devices. Anyone experience a similar issue with the MediaPlayer on ICS?

    EDIT

    Here's how the proxy is writing to the socket. In this example it's from a CipherInputStream loaded from a file, but the same occurs when it's loaded from the HttpResponse.

    final Socket client = (setup above)
    
    // encrypted file input stream
    final CipherInputStream inputStream = getInputStream(file);
    
    // setup the socket output stream
    final OutputStream output =  client.getOutputStream();
    
    // Writing the header
    final String httpHeader = buildHttpHeader(file.length());
    final byte[] buffer = httpHeader.getBytes("UTF-8");
    output.write(buffer, 0, buffer.length);
    
    int writtenBytes = 0;
    int readBytes;
    final byte[] buff = new byte[1024 * 12]; // 12 KB
    
    while (mIsRunning && (readBytes = inputStream.read(buff)) != -1) {
        output.write(buff, 0, readBytes);
        writtenBytes += readBytes;
    }
    
    output.flush();
    output.close();
    

    The HTTP Headers that are written to the MediaPlayer before the audio..

    private String buildHttpHeader(final int contentLength) {
        final StringBuilder sb = new StringBuilder();
    
        sb.append("HTTP/1.1 200 OK\r\n");
        sb.append("Content-Length: ").append(contentLength).append("\r\n");
        sb.append("Accept-Ranges: bytes\r\n" );
        sb.append("Content-Type: audio/mpeg\r\n");
        sb.append("Connection: close\r\n" );
        sb.append("\r\n");
    
        return sb.toString();
    }
    

    I've looked around for alternate implementations but as I have encrypted audio and the MediaPlayer does not support InputStreams as a data source my only option (I think..) is to use a proxy such as this.

    Again, this is working fairly well Android 2.1 - 2.3 but in ICS the MediaPlayer is buffering a huge amount of this data before playing.

    EDIT 2 :

    Further testing is showing that this is also an issue on the SGS2 once upgraded to Android 4.0.3. So it seems like the MediaPlayer's buffering implementation has changed significantly in 4.0. This is frustrating as the API provides no way to alter the behaviour.

    EDIT 3 :

    Android bug created. Please add comments and star there as well http://code.google.com/p/android/issues/detail?id=29870

    EDIT 4 :

    My playback code is fairly standard.. I have the start() call on the MediaPlayer in my onPrepared() method.

    mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mCurrentPlayer.setDataSource(url);
    mCurrentPlayer.prepareAsync();
    

    Have tried it using just prepare() and also ajacian81's recommended way but to no avail.

    I should add that recently a Google employee got back to me about my question and confirmed that the buffer size was intentionally increased in ICS (for HD content). It has been requested to the API developers to add the ability to set a buffer size on MediaPlayer.

    Though I think this API change request had been around before I came along so I wouldn't advise anyone to hold their breath.

  • denizmveli
    denizmveli about 12 years
    Thank you for your answer. Unfortunately it didn't fix my issue. Incidentally what was the issue that you were having which required this implementation?
  • ajacian81
    ajacian81 about 12 years
    @TheModernInk Long gaps in buffering, even when on a very fast WIFI connection.