0

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.

Elton
  • 3
  • 2
  • I found you use the new MediaPlayer instance (`MediaPlayer mediaplayer = new MediaPlayer`), it will not link to the playing media. – Nico Zhu Apr 20 '20 at 07:26
  • How about calling mediaplayer.Pause() after CheckUntilTimeout(..) straightforwardly? – ardget Apr 20 '20 at 08:29
  • Thanks, for your replies guys. I use `MediaPlayer` only for testing if the media is online or not, it is not associated with `MediaPlayerElement`. But as i wrote on the second part (Edit), you can try to play any of the icecast links and after calling `Pause` or `Stop` or `Source=null` or `Dispose`, the `MediaPlayer` won't stop streaming. You can see windows task manager or resource monitor to confirm that the app is still streaming every link. I think this is a memory leak... – Elton Apr 20 '20 at 17:10
  • Could you provide a [mcve], I will test it base on it. – Nico Zhu Apr 21 '20 at 01:44
  • @Elton Then... try calling MediaSource.Dispose() or MediaSource.DownloadOperation.Pause() if you haven't tried these yet. If neither works, I have no idea. – ardget Apr 21 '20 at 04:04
  • 1
    @NicoZhu-MSFT I made a sample project [link](https://www.dropbox.com/s/rvm2tvmhxeq2kcb/MplayerBug.zip?dl=0) please take a look. – Elton Apr 21 '20 at 10:50
  • @ardget Thanks for your reply, if i call MediaSource.Dispose() it works, but in the project sample [link](https://www.dropbox.com/s/rvm2tvmhxeq2kcb/MplayerBug.zip?dl=0) if I want to stop a MediaPlayerElement using the button in TransportMediaControl it doesn't stop streaming... Thanks again. – Elton Apr 21 '20 at 10:57
  • How to dispose MediaPlayerElement.Source in XAML is another problem beyond the scope of this thread. I will not discuss it here. If you'd like to resolve it, [launch a new question](https://stackoverflow.com/questions/ask). btw, I found a similar discussion [here](https://stackoverflow.com/questions/54725337/memory-leak-on-uwp-mediaplayer-windows-media-playback-mediaplayer/54947557). Accoriding to it, some behaviors may be due to bugs as you think. – ardget Apr 22 '20 at 07:32
  • Anyway, we found MediaSource.Dispose() work, so I'd leave it as my final Answer in the end. – ardget Apr 22 '20 at 07:33
  • FYI, @Elton, calling MediaSource.OpenAsync() is more efficient for checking a source is supported compared to creating an entire new media player each time. – Johnny Westlake Apr 22 '20 at 08:02
  • 1
    @JohnnyWestlake thanks for your suggestion, that way is much more faster and efficient. – Elton Apr 22 '20 at 09:39

1 Answers1

2

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();
    }
}
ardget
  • 2,561
  • 1
  • 5
  • 4