Fadi Banna Fadi Banna - 28 days ago 11
C# Question

MediaElement is refusing to loop

So I was trying to loop Background music in my UWP App, I have a class called soundControl that handles music and sounds like this:

public class soundControl
{
private static MediaElement loop = new MediaElement();
public static async void stopLoop()
{
loop.Stop();
}
public static async void loadLoopTimeBG()
{
Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Sounds");
Windows.Storage.StorageFile file = await folder.GetFileAsync("battle.wav");
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
loop.AutoPlay = false;
loop.SetSource(stream, file.ContentType);
loop.IsLooping = true;
}
public static void loopTimeBG()
{
loop.Play();
}


And whenever I want to play this music I call :

soundControl.loadLoopTimeBG();
soundControl.loopTimeBG();


the problem is the it plays just one time and stops and I have no Idea why
I tried another approach like:

loop.MediaEnded += mediaEnded;


and the event handler like this:

private static void mediaEnded(object sender, RoutedEventArgs e)
{
loop.Position = TimeSpan.Zero;
loop.Play();
}


it also didn't work and when debugging it doesn't even triger the mediaEnded event when music is complete.

Any help here would be most appreciated.
Thanks

Answer

MediaPlayer

It seems that Windows.Media.Playback.MediaPlayer is the recommended player that does not require to be in the XAML visual tree.

Its API is very similar to MediaElement, but so far it seems that it adds a unnatural break between the individual plays of the media, which is something I haven't found a way to overcome yet:

private static MediaPlayer _mediaPlayer = new MediaPlayer();

public static async Task PlayUsingMediaPlayerAsync()
{
    Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets");
    Windows.Storage.StorageFile file = await folder.GetFileAsync("Click.wav");
    _mediaPlayer.AutoPlay = false;
    _mediaPlayer.Source = MediaSource.CreateFromStorageFile(file);

    _mediaPlayer.MediaOpened += _mediaPlayer_MediaOpened;

    _mediaPlayer.IsLoopingEnabled = true;

}

private static void _mediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
    sender.Play();
}

MediaElement

After some digging around it seems that there are two issues.

MediaElement is XAML based control (in the Windows.UI.Xaml.Controls namespace), and it seems that it does not work properly until it is actually attached to a visual tree. Once you put the MediaElement on the page, it works as expected.

Secondly, loading source media does not happen immediately. Once you set the source, the control needs some time to actually load the media. For this purpose, you can use the MediaOpened event, that will notify you once it is really loaded.

So the code could look somewhat like this:

public static async Task LoadAndPlayAsync()
{
    Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets");
    Windows.Storage.StorageFile file = await folder.GetFileAsync("Click.wav");
    var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
    loop.AutoPlay = false;
    loop.SetSource(stream, file.ContentType);
    //or simpler -
    //loop.Source = new Uri("ms-appx:///Assets/Click.wav", UriKind.Absolute);
    loop.MediaOpened += Loop_MediaOpened;
    loop.IsLooping = true;
}

private static void Loop_MediaOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    //play once the media is actually ready
    loop.Play();
}

And before you call the LoadAndPlayAsync method, you have to attach the control somewhere (for example in a Grid):

GridContainer.Children.Add(SoundController.loop);
await SoundController.LoadAndPlayAsync();

I have created a sample project for my tests on my GitHub, you can check it out to see how I implemented it. The first button in the app attaches the control and the second loads and plays the sound. You can see that if you click only the second one, the sound does not play.

Comments