[FIXED] Audio player gets auto disposed

Issue

The audio player gets disposed when changing audio files. The app plays sequential audio in files in the shared\audio folder. The first file plays ok but stops after first audio. Im using Plugin.SimpleAudioplayer
Here’s the code, what am i doing wrong.

 public partial class MainPage : ContentPage
{
    private ISimpleAudioPlayer audio;
    private int pagenum;

    public MainPage()
    {
        InitializeComponent();
    }

    private void playaudio(int pgnum)
    {
        audio = CrossSimpleAudioPlayer.Current;
        audio.PlaybackEnded += cmdNextClicked; 
        
        var stream = GetStreamFromFile(string.Concat("audio.w", (pgnum + 1).ToString(), ".mp3"));
        audio.Load(stream);
        audio.Play();
    }

    Stream GetStreamFromFile(string filename)
    {
        var assembly = typeof(App).GetTypeInfo().Assembly;
        var stream = assembly.GetManifestResourceStream("App1." + filename);
        return stream;
    }

    private void cmdRunClicked(object sender, EventArgs e)//
    {
        playaudio(pagenum);
    }

    private void cmdStopClicked(object sender, EventArgs e)//
    {
       if (!(audio is null))
        {
            audio.Stop();
        }
    }

    private void cmdClicked(object sender, EventArgs e)
    {
        audio.Seek(audio.CurrentPosition + 30.0);
    }

    private void cmdNextClicked(object sender, EventArgs e)
    {
       
        pagenum++;
        lblPageNo.Text = pagenum.ToString();
        playaudio(pagenum);
    }

    private void cmdPrevClicked(object sender, EventArgs e)
    {
        pagenum--;
        lblPageNo.Text = pagenum.ToString();
        playaudio(pagenum);
    }
}

Solution

Given the new symptom (crash happens after return from cmdNext), queue to run after PlaybackEnded handler returns:

// NOTE: As Christopher Richmond commented, move this to a place that is only called once.
audio.PlaybackEnded += SafePlayNext;
...

private void SafePlayNext(object sender, EventArgs e)
{
    // Queue to run after return.
    Device.BeginInvokeOnMainThread(() =>
        cmdNextClicked(null, null));   // Arguments not used, `null` works fine.
}

EXPLANATION: Starting another audio apparently disposes the previous audio. Original code started another audio, then handler ends, and returns to that audio’s PlaybackEnded event processor. Something is accessed on that disposed audio. Thus the disposed Exception.

The above code puts the cmdNextClicked call on to MainThread’s queue, then immediately returns to that audio’s PlaybackEnded. Which thus has a chance to finish, before the next audio is asked for.

Answered By – ToolmakerSteve

Answer Checked By – Gilberto Lyons (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published