I have two devices I can test my game on: A US Celluar phone (SCH-R880) and a Kindle Fire, the Kindle Fire being a lot more powerful than the phone.
I have several short (Less than or about 1 second) sound effects. To save on memory I load, play, and release some of these sound effects. On the phone they play (mostly) as expected. On the Kindle Fire, however, they're cut short. The really short sounds are cut off so quickly I don't hear anything. The ones that are loaded at setup and remain, however, play fine.
Anyone have any idea what's going on here? Am I somehow releasing my media too soon? Below is one instance of this. On the phone I hear "Level two!" but on the Kindle I hear something like "Lev tw."
mpNum = null;
try
{
switch (level)
{
case 2:
mpNum = MediaPlayer.create(contxt, R.raw.l2); break;
case 3:
mpNum = MediaPlayer.create(contxt, R.raw.l3); break;
case 4:
mpNum = MediaPlayer.create(contxt, R.raw.l4); break;
case 5:
mpNum = MediaPlayer.create(contxt, R.raw.l5); break;
case 6:
mpNum = MediaPlayer.create(contxt, R.raw.l6); break;
case 7:
mpNum = MediaPlayer.create(contxt, R.raw.l7); break;
case 8:
mpNum = MediaPlayer.create(contxt, R.raw.l8); break;
default:
return;
}
MediaPlayer vLevel = MediaPlayer.create(contxt, R.raw.level);
vLevel.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
{
public void onPrepared(MediaPlayer mp)
{
mp.start();
}
});
vLevel.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
public void onCompletion(MediaPlayer mpl)
{
mpNum.start();
mpl.release();
}
});
mpNum.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
public void onCompletion(MediaPlayer mp)
{
mp.release();
}
});
}
catch (Exception e) {}
In an attempt to try to fix this, I tried SoundPool, but it doesn't work; I hear nothing. Below is what I did to try to play the music with SoundPool:
SoundPool soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 100);
soundPool.load(contxt, R.raw.song2, 1);
AudioManager mgr = (AudioManager)contxt.getSystemService(Context.AUDIO_SERVICE);
float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = streamVolumeMax;
soundPool.play(1, volume, volume, 1, 5, 2);
UPDATE
I've noticed when a sound that should be playing (but doesn't) has this error that comes up:
AudioPolicyManager: stopOutput() oldDevice 2
AudioPolicyManager: [getDeviceForStrategy] strategy : 0,forceUse(0)
I had the same problem and it indeed was a garbage collector issue! If you assign the instance of the media player to some local variable inside a method, the instance no longer exists after leaving that method, so GC can randomly delete it anytime.
To avoid this, you need to keep at least one pointer to the instance somewhere else. I have created a static set to keep all the pointers, it looks like this:
private static Set<MediaPlayer> activePlayers = new HashSet<MediaPlayer>();
Then creation of the media player is following:
MediaPlayer player = MediaPlayer.create(context, context.getResources().getIdentifier(id, "raw", pkg));
activePlayers.add(player);
player.setOnCompletionListener(releaseOnFinishListener);
player.start();
Where releaseOnFinishListener is a listener that releases the media player on finish just like yours but also removes the pointer from the activePlayers set:
MediaPlayer.OnCompletionListener releaseOnFinishListener = new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
activePlayers.remove(mp);
}
};
I hope this helps you.
well I had the same problems in one project and is because in KindleFire the sounds cut before finish so to fix that (with the release) I added a delay in the release:
mpNum.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
public void onCompletion(MediaPlayer mp)
{
// Add a handler delay
new Timer().schedule(new TimerTask() {
@Override
public void run() {
mp.release();
}
}, DELAY_TIME);
}
});
It's not the best solution but I think that maybe will help you.
I've read that the SoundPool class is more suited to short sounds like this than MediaPlayer, but that's probably not the issue.
Can you also post the code for your click handler?
Also, I'd recommend rather than releasing and regaining MediaPlayer instances, use one MediaPlayer instance, and just follow the typical reset(), setDataSource(), prepare(), start() sequence whenever you need to reuse it. It'll be more efficient than constructing a new instance every time. i.e. :
MediaPlayer mp = new MediaPlayer();
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.sound1);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength();
mp.prepare();
mp.start();
//to reuse
mp.reset();
afd = getResources().openRawResourceFd(R.raw.sound2);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength();
mp.prepare();
mp.start();
I had this issue and solved it making my MediaPlayer object private, so the garbage collector doesn't clean the instance. Hope it helps somebody!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With