Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knowing if the loading of a sound with SoundPool has been successful on Android 1.6/2.0/2.1

On Android 2.2+ there is something called SoundPool.OnLoadCompleteListener allowing to know whether a sound has been loaded successfully or not.

I am targeting lower API version (ideally 1.6 but could go for 2.1) and I need to know whether a sound has been loaded correctly (as it is selected by the user). What's the proper way to do it?

I hope not load the sound once with MediaPlayer and if correct with SoundPool?!

like image 509
Vincent Mimoun-Prat Avatar asked Jan 14 '11 15:01

Vincent Mimoun-Prat


2 Answers

I implemented a kind-of-compatible OnLoadCompleteListener class that works at least for Android 2.1.

The constructor takes a SoundPool object, and sounds for which the SoundPool.load(..) has been called must be registered with OnLoadCompleteListener.addSound(soundId). After this, the listener periodically attempts to play the requested sounds (at zero volume). If successful, it calls your implementation of onLoadComplete, like in the Android 2.2+ version.

Here's a usage example:

    SoundPool mySoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
    OnLoadCompleteListener completionListener = new OnLoadCompleteListener(mySoundPool) {
        @Override
        public void onLoadComplete(SoundPool soundPool, int soundId, int status) {
            Log.i("OnLoadCompleteListener","Sound "+soundId+" loaded.");
        }
    }
    int soundId=mySoundPool.load(this, R.raw.funnyvoice,1);
    completionListener.addSound(soundId);  // tell the listener to test for this sound.

And here's the source:

abstract class OnLoadCompleteListener {    
    final int testPeriodMs = 100; // period between tests in ms

     /**
     * OnLoadCompleteListener fallback implementation for Android versions before 2.2. 
     * After using: int soundId=SoundPool.load(..), call OnLoadCompleteListener.listenFor(soundId)
     * to periodically test sound load completion. If a sound is playable, onLoadComplete is called.
     *
     * @param soundPool  The SoundPool in which you loaded the sounds. 
     */
    public OnLoadCompleteListener(SoundPool soundPool) {
        testSoundPool = soundPool;
    }

    /**
     * Method called when determined that a soundpool sound has been loaded. 
     *
     * @param soundPool  The soundpool that was given to the constructor of this OnLoadCompleteListener
     * @param soundId    The soundId of the sound that loaded
     * @param status     Status value for forward compatibility. Always 0.  
     */
    public abstract void onLoadComplete(SoundPool soundPool, int soundId, int status); // implement yourself

     /**
     * Method to add sounds for which a test is required. Assumes that SoundPool.load(soundId,...) has been called.
     *
     * @param soundPool  The SoundPool in which you loaded the sounds. 
     */
    public void addSound(int soundId) {
        boolean isFirstOne;
        synchronized (this) {
            mySoundIds.add(soundId);
            isFirstOne = (mySoundIds.size()==1);
        }
        if (isFirstOne) {
            // first sound, start timer
            testTimer = new Timer();
            TimerTask task = new TimerTask() { // import java.util.TimerTask for this
                @Override
                public void run() {
                    testCompletions();
                }  
            };
            testTimer.scheduleAtFixedRate(task , 0, testPeriodMs);
        }
    }

    private ArrayList<Integer> mySoundIds = new ArrayList<Integer>();
    private Timer testTimer;  // import java.util.Timer for this
    private SoundPool testSoundPool;

    private synchronized void testCompletions() {
        ArrayList<Integer> completedOnes = new ArrayList<Integer>();
        for (Integer soundId: mySoundIds) {
            int streamId = testSoundPool.play(soundId, 0, 0, 0, 0, 1.0f);
            if (streamId>0) {                   // successful
                testSoundPool.stop(streamId);
                onLoadComplete(testSoundPool, soundId, 0); 
                completedOnes.add(soundId);
            }
        }
        mySoundIds.removeAll(completedOnes);
        if (mySoundIds.size()==0) {
            testTimer.cancel();
            testTimer.purge();
        }
    }
}
like image 116
jeroent Avatar answered Oct 06 '22 21:10

jeroent


SoundPool does load the file asynchronously. Before API8 level there is unfortunately no API to check if the loading has been completely.

As you said as of Android API8 it is possible to check if the loading complete via a OnLoadCompleteListener. Here is a small example for this: Android sounds tutorial.

like image 22
vogella Avatar answered Oct 06 '22 22:10

vogella