Category Archives: Audio

Nexus Lollipop soundpool.load() not so sweet

When I got my first taste of the Android L pre-release I noticed something rather disturbing when running some games.  I was using a Nexus 5 and every now and again a long pause where an app would become non-responsive. Sometimes it was a couple of seconds and other times it was 10, 20 or more seconds without response, then it would finally burst back to life. After doing a little digging and I tracked it to an issue with the Nexus family using the SoundPool.load() function.  This issue lives on with the latest Android 5.0.2 build.

Issue Description

The Android SoundPool class allows developers to pre-load several short sound clips so the may be played at any time without the lag of decompressing on the fly.  This is perfect for game developers where sounds may be played many times. On the Nexus family of devices, the execution of the SoundPool.load() function may take several seconds to load a very small audio file, instead of the few milliseconds as has been the case with the same files on previous Android versions, or with other devices running Lollipop.  The issue relates to the ‘AwesomePlayer’ media engine. There is a way to confirm if this is an issue in your code.  Go to the media section of the developer options and check the ‘Use NuPlayer (experimental)’ checkbox.  Run your app again and you should see none of the unresponsiveness that has lead you to this post. If the delay remains it is likely not being caused by the SoundPool.load() issue.

Issue Status

As of Android 5.0.2 this is an unresolved issue in the Android Open Source Project (AOSP) issue tracker. It’s can be reproduced on most of the Nexus devices that have support for 5.0, from the Nexus 4 through to 5, 7 (2012 & 2013) and 9.  I have not been lucky enough to get my hands on a Nexus 6 to confirm if it suffers the same affliction.

Poor app design exposed

The Android media engine requiring seconds to load a small sound file is clearly not acceptable, but what it does is exposes apps that are executing the sound pool loading code from the UI thread. For a few small audio files that were taking a few milliseconds each, this was never noticed. But best practice dictates load functions like this should be happening on a background thread. Structure you app so the thread has maximum time to load all it needs to load without needing to hold up the user.  Once this change is made chances are this issue will no longer be a problem in your app and you won’t be waiting for the AOSP fix.

Changes to SoundPool in API 21

While on the subject of the SoundPool class, Android 5.0 (API 21) also brings some recommended usage changes.  So read on if you have not changed the way you create your SoundPool on Lollipop devices. If you take a look at the SoundPool interface the constructor public SoundPool(int maxStreams, int streamType, int srcQuality) is now deprecated. The recommended usage is to create and configure the SoundPool instance using the SoundPool builder class (SoundPool.Builder) The SoundPool Builder is only available on API 21+, so you will need to create your SoundPool differently based on the SDK version of the device your app is running on. When your code is executed on devices running 5.0+ create the SoundPool using the builder, as follows:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void createSoundPoolWithBuilder(){
    AudioAttributes attributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build();

    mSoundPool = new SoundPool.Builder().setAudioAttributes(attributes).setMaxStreams(6).build();
}

For devices running 4.4 and older use the SoundPool constructor:

@SuppressWarnings("deprecation")
protected void createSoundPoolWithConstructor(){
    mSoundPool = new SoundPool(6, AudioManager.STREAM_MUSIC, 0);
}

Check the device version to call the appropriate function to create the SoundPool:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    createSoundPoolWithBuilder();
} else{
    createSoundPoolWithConstructor();
}

Hopefully this has sorted your Android 5.0 SoundPool woes.

Update March 2015: This issue was still present for my Nexus devices after initially updating to Android 5.1, although it seems on a clean install of 5.1 the default media engine is now NuPlayer which does not have exhibit the SoundPool issue.

lollipop

Advertisements

4 Comments

Filed under Android 5.0, Android SDK, Audio, SoundPool