Search code examples
c#uwpmedia-playerdispose

How to dispose correctly an UWP mediaplayer?


I have a piece of code for checking if a list of media is playable. The problem is that when I run the method and let it finish or cancel it using a CancellationToken, the MediaPlayer keeps downloading content and never finishes even though I have a using and call Dispose(). Maybe I'm doing something wrong... A little help is very appreciated. Thanks a lot! Here is the code:

CancellationTokenSource tokenSource = new CancellationTokenSource();
private async Task CheckMediaAsync(CancellationToken token)
{
    using (MediaPlayer mediaplayer = new MediaPlayer { IsMuted = true, AutoPlay = true })
    {
        List<Link> links = DataAccess.GetAllMedia();
        for (int i = 0; i < links.Count; i++)
        {
            mediaplayer.Source = MediaSource.CreateFromUri(new Uri(links[i].LinkMed));

            if (await Task.Run(() => CheckUntilTimeout(token, mediaplayer), token))
            {
                OffileMedia.Add(links[i].Name);
            }

            if (tokenSource.IsCancellationRequested)
            {
                mediaplayer.Source = null;
                mediaplayer.Dispose();
                return;
            }
        }
        mediaplayer.Source = null;
        mediaplayer.Dispose();
    }
}

private bool CheckUntilTimeout(CancellationToken ct, MediaPlayer mp)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    while (stopwatch.Elapsed < TimeSpan.FromSeconds(8))
    {
        if (ct.IsCancellationRequested)
        {
            stopwatch.Stop();
            return false;
        }

        if (mp.PlaybackSession.PlaybackState == MediaPlaybackState.None)
        {
            stopwatch.Stop();
            return true;
        }
        else if (mp.PlaybackSession.PlaybackState == MediaPlaybackState.Playing)
        {
            stopwatch.Stop();
            return false;
        }
    }

    stopwatch.Stop();
    return true;
}

Edit:
After some other inspections it seems that the problem is really MediaPlayer object. If I try to set the Source as audio streaming for example:

http://icecast.unitedradio.it/Radio105.mp3
http://icecast.unitedradio.it/Virgin.mp3

or any other audio stream, the MediaPlayer will continue to download each of them even if you set Source to null or Dispose() it. Curiously, if try any video stream (m3u8 or mpd) is seems to work correcty.


Solution

  • You would rather need to dispose underlying MediaSource appropriately to stop downloading besides disposing the MediaPlayer.

    So right steps to dispose MediaPlayer currently playing MediaSource created from Uri are...

    1. Pause playback on the MediaPlayer.
    2. Detach MediaSource from the MediaPlayer.
    3. Dispose both MediaSource* and MediaPlayer.

    *Since MediaSource class also has IDisposable interface, it may be better to wrap the code-block in a using(...){ } clause. Then you don't need to call Dispose explicitly.

    private async Task CheckMediaAsync(CancellationToken token)
    {
        using (MediaPlayer mediaplayer = new MediaPlayer { IsMuted = true, AutoPlay = true })
        {
            List<Link> links = DataAccess.GetAllMedia();
            for (int i = 0; i < links.Count; i++)
            {
                using (MediaSource ms = MediaSource.CreateFromUri(new Uri(links[i].LinkMed)))
                {
                    mediaplayer.Source = ms;
    
                    if (await Task.Run(() => CheckUntilTimeout(token, mediaplayer), token))
                    {
                        OffileMedia.Add(links[i].Name);
                    }
                    mediaplayer.Pause();
                    mediaplayer.Source = null;
                }
                if (tokenSource.IsCancellationRequested)
                {
                    //mediaplayer.Source = null;
                    //mediaplayer.Dispose();
                    return;
                }
            }
            //mediaplayer.Source = null;
            //mediaplayer.Dispose();
        }
    }