// Created by plusminus on 22:14:44 - 14.11.2008
package org.androad.sound;
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
public class MediaPlayerManager implements ISoundManager {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private static ISoundManager mSoundManagerInstance;
private final Context mCtx;
private MediaPlayerPool mMediaPlayerPool;
private final HashMap<Integer, Integer> mFollowUpSounds = new HashMap<Integer, Integer>();
// ===========================================================
// Constructors
// ===========================================================
public static ISoundManager getInstance(final Context ctx){
if(mSoundManagerInstance == null) {
mSoundManagerInstance = new MediaPlayerManager(ctx);
}
return mSoundManagerInstance;
}
private MediaPlayerManager(final Context ctx){
this.mCtx = ctx;
initMediaPlayerPool();
}
private void initMediaPlayerPool() {
this.mMediaPlayerPool = new MediaPlayerPool();
}
// ===========================================================
// Getter & Setter
// ===========================================================
private Context getContext() {
return this.mCtx;
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
@Override
public void playSound(final int soundResId) {
this.mMediaPlayerPool.get(soundResId).start();
}
@Override
public void playFollowUpSounds(final int ... soundResIds) {
for(int i = 1; i < soundResIds.length; i++) {
this.mFollowUpSounds.put(soundResIds[i-1], soundResIds[i]);
}
/* Start with the first, all others will be player as followups. */
this.mMediaPlayerPool.get(soundResIds[0]).start();
}
@Override
public void preloadSound(final int resID) {
// Nothing to do
}
@Override
public void preloadSounds(final int[] resIDs) {
// Nothing to do
}
@Override
public void releaseAll() {
this.mMediaPlayerPool.releaseAll();
}
// ===========================================================
// Methods
// ===========================================================
protected void completed(final int soundResId) {
final Integer followUpSound = this.mFollowUpSounds.remove(soundResId);
if(followUpSound != null) {
playSound(followUpSound);
}
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
private class MediaPlayerPool{
private static final int DESIRED_PLAYERS_READY = 1;
private final HashMap<Integer, ArrayList<MediaPlayer>> mPools = new HashMap<Integer, ArrayList<MediaPlayer>>();
public synchronized MediaPlayer get(final int soundResId){
final ArrayList<MediaPlayer> existingPool = this.mPools.get(soundResId);
if(existingPool != null && existingPool.size() > 0){
/* If there is one found, get it by removing it from the pool.
* At this point, the player already got the completion listener set,
* which makes it return to the pool. */
return existingPool.remove(0);
}else{
/* Create a new MediaPlayer, which later will return to the pool. */
final MediaPlayer mp = MediaPlayer.create(getContext(), soundResId);
mp.setOnCompletionListener(new OnCompletionListener(){
@Override
public void onCompletion(final MediaPlayer mp) {
mp.seekTo(0);
returnToPool(soundResId, mp);
completed(soundResId);
}
});
return mp;
}
}
private synchronized void returnToPool(final int soundResId, final MediaPlayer mp) {
final ArrayList<MediaPlayer> existingPool = this.mPools.get(soundResId);
if(existingPool != null){
if(existingPool.size() < DESIRED_PLAYERS_READY){
/* Add the returning MediaPlayer to existing Pool. */
existingPool.add(mp);
}else{
mp.release();
}
}else{
/* Create new ArrayList an add the returning MediaPlayer to it. */
final ArrayList<MediaPlayer> newPool = new ArrayList<MediaPlayer>(2);
newPool.add(mp);
this.mPools.put(soundResId, newPool);
}
}
public synchronized void releaseAll() {
for(final ArrayList<MediaPlayer> pool : this.mPools.values()){
for(final MediaPlayer p : pool){
p.release();
}
pool.clear();
}
this.mPools.clear();
}
}
}