Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MediaPlayer stops working after 30 uses?

I'm trying to write a function to play a short sound (in /res/raw) in my program, called at effectively random times throughout the program. So far I have this function:

public void playSound() {
    MediaPlayer mp = new MediaPlayer();
    mp = MediaPlayer.create(this, R.raw.ShortBeep);
    mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mp.setLooping(false);
    mp.start();
}

It works fine for awhile, but after exactly 30 plays of the sound, it stops making sound.

like image 251
Lableable Avatar asked Jan 13 '23 09:01

Lableable


2 Answers

According to the Docs

... failure to call release() may cause subsequent instances of MediaPlayer objects to fallback to software implementations or fail altogether.

When you are done with it call mp.release() so that it can release the resources. I don't know what the limit is and I'm sure it depends on many factors. Either way you should be calling this function on your MediaPlayer object, especially if it will be used more than once.

like image 142
codeMagic Avatar answered Jan 22 '23 13:01

codeMagic


I've just solved the exact same problem, but I'm using Xamarin. I ended up changing from holding on to a MediaPlayer instance for the lifetime of the activity to creating an instance each time I want to play a sound. I also implemented the IOnPreparedListener and IOnCompletionListener.

Hopefully you can get the idea despite it being C# code

public class ScanBarcodeView :
    MvxActivity,
    MediaPlayer.IOnPreparedListener,
    MediaPlayer.IOnCompletionListener
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.ScanBarcodeView);

        ((ScanBarcodeViewModel) ViewModel).BarcodeScanFailed += (sender, args) => PlaySound(Resource.Raw.fail);
        ((ScanBarcodeViewModel) ViewModel).DuplicateScan += (sender, args) => PlaySound(Resource.Raw.tryagain);
    }

    private void PlaySound(int resource)
    {
        var mp = new MediaPlayer();
        mp.SetDataSource(ApplicationContext, Android.Net.Uri.Parse($"android.resource://com.company.appname/{resource}"));
        mp.SetOnPreparedListener(this);
        mp.SetOnCompletionListener(this);
        mp.PrepareAsync();
    }

    public void OnPrepared(MediaPlayer mp)
    {
        mp.Start();
    }

    public void OnCompletion(MediaPlayer mp)
    {
        mp.Release();
    }
}

So, each time I want a sound to be played I create a MediaPlayer instance, so the data source, tell it that my Activity is the listener to Prepared and Completion events and prepare it. Since I'm using PrepareAsync I don't block the UI thread. When the media player is prepared the Start method on the MediaPlayer is called, and when the sound has finished playing the MediaPlayer object is released.

Before I made these changes I would get to 30 sounds played and it would all stop working. Now I've gone way past 30, also multiple sounds can be played simultaneously.

Hope that helps.

like image 44
Antony Scott Avatar answered Jan 22 '23 11:01

Antony Scott