Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you dispose of AVAudioPlayer when FinishedPlaying event is invoked?

I'm using AVAudioPlayer to play a sound when a user taps a row in a UITableView. If they tap the row again, the player stops and is disposed, and if they listen to the song until it's finished then the FinshedPlaying handler disposes of the player.

The problem I'm having is that when I try to dispose of the player in the FinishedPlaying handler I get the error message:

System.ObjectDisposedException: the player object was Dispose()d during the callback, this has corrupted the state of the program

Here's the code, any idea what I'm doing wrong?

void HandleOnRequestPlayMusic (object sender, UrlEventArgs e)
{
    var url = Utils.UrlFromString(e.Url);
    string oldUrl = "";
    if (musicPlayer != null)
    {
        oldUrl = musicPlayer.Url.AbsoluteString;
        KillAudioPlayer(); // no problems killing the audio player from here
    }
    if (oldUrl != url.AbsoluteString)
    {
        musicPlayer = AVAudioPlayer.FromUrl(url);
        musicPlayer.FinishedPlaying += HandleAudioFinished;
        musicPlayer.Play();
    }
}

void HandleAudioFinished (object sender, AVStatusEventArgs e) 
{
    KillAudioPlayer(); // killing audio player from here causes app to crash
}

void KillAudioPlayer ()
{
    if (musicPlayer != null)
    {
        InvokeOnMainThread(() => {
            musicPlayer.Stop();
            musicPlayer.FinishedPlaying -= HandleAudioFinished;
            musicPlayer.Dispose();
            musicPlayer = null;
        });
    }
}
like image 246
Dave Wolfe Avatar asked May 24 '13 20:05

Dave Wolfe


1 Answers

Don't use InvokeOnMainThread there, because InvokeOnMainThread waits for the input action to be completed before returning to its caller. That's why your Dispose call is occurring while you're still inside the call to KillAudioPlayer, inside the HandleAudioFinished callback.

Instead use BeginInvokeOnMainThread, which will schedule your cleanup action to occur on the main thread, but will return immediately to your KillAudioPlayer function, allowing it to finish.

like image 136
Aaron Golden Avatar answered Oct 13 '22 20:10

Aaron Golden