MediaElement is refusing to loop - c#

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

MediaPlayer
Windows.Media.Playback.MediaPlayer is the recommended player for UWP that does not require to be in the XAML visual tree.
Its API is very similar to MediaElement:
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();
}
You can even display the visuals of a MediaPlayer in XAML using MediaPlayerElement.
MediaPlayer allows for even more advanced playback scenarios using the MediaPlaybackList with support for looping, shuffle and gapless playback.
mediaElement.SetPlaybackSource(mediaPlaybackList);
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.

Related

No audio with WAV and MediaPlayer in WPF

I'm trying to add background music to my WPF program. I also want additional sounds to happen "over" the background music. I tried using a SoundPlayer however, this could only play one piece of audio at once.
I am now trying to use MediaPlayer but I cannot get any audio to play. Here is my code:
In my ShellViewModel I start the background music:
Sounds.StartBackgroundMusic()
In my sounds class I have the following:
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri("pack://application:,,,/Assets/Sounds/backgroundmusic.wav"));
_backgroundMusic.MediaEnded += new EventHandler (BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
Since I want the background music to loop continuously, I used the answer in this question to add the BackgroundMusic_Ended event. Can someone please help shed some light on why my audio isn't playing?
I tried to reproduce the problem but it worked as expected.
I created a new WPF application in Visual Studio and used the following code in MainWindow.xaml.cs:
using System;
using System.Windows;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private static MediaPlayer _backgroundMusic = new MediaPlayer();
public MainWindow()
{
InitializeComponent();
StartBackgroundMusic();
}
public static void StartBackgroundMusic()
{
_backgroundMusic.Open(new Uri(#"C:\<path-to-sound-file>\music.wav"));
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
_backgroundMusic.Play();
}
private static void BackgroundMusic_Ended(object sender, EventArgs e)
{
_backgroundMusic.Position = TimeSpan.Zero;
_backgroundMusic.Play();
}
}
}
Did you try to use a "regular" file path to load a sound file instead of "pack://..."? When I used the wrong path I didn't get any sound and there was no error message or exception.
Since I couldn't use MediaPlayer to play embedded resources and SoundPlayer can only play one sound at a time, I used a combination of them and saved the embedded background music resource to disk so that MediaPlayer could play it. I make a blog about it here
Heres what I did:
I set up my SoundPlayer as this was the simplest one of the two. I created a new SoundPlayer object using the embedded resource
private static readonly SoundPlayer _soundOne = new SoundPlayer(WPF.Properties.Resources.soundOne);
Now the MediaPlayer. I make sure that my audio file is set as an Embedded Resource under the Build Actions in the file’s properties in Visual Studio. Now that we have done this, we can create the method for saving the embedded WAV file to the %temp% location on disk:
public static void SaveMusicToDisk(){
//This sets up a new temporary file in the %temp% location called "backgroundmusic.wav"
using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundmusic.wav")){
//This them looks into the assembly and finds the embedded resource
//inside the WPF project, under the assets folder
//under the sounds folder called backgroundmusic.wav
//PLEASE NOTE: this will be different to you
Assembly.GetExecutingAssembly().GetManifestResourceStream("WPF.Assets.Sounds.backgroundmusic.wav").CopyTo(fileStream);
}
}
We play this by creating a new MediaPlayer object and using the temp file location to play the audio:
//Create a new MediaPlayer object
private static readonly MediaPlayer _backgroundMusic = new MediaPlayer();
public static void StartBackgroundMusic(){
//Open the temp WAV file saved in the temp location and called "backgroundmusic.wav"
_backgroundMusic.Open(new Uri(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav")));
//Add an event handler for when the media has ended, this way
//the music can be played on a loop
_backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
//Start the music playing
_backgroundMusic.Play();
}
My BackgroundMusic_Ended method looks like this and just makes sure that the music is always restarted once it has finished:
private static void BackgroundMusic_Ended(object sender, EventArgs e){
//Set the music back to the beginning
_backgroundMusic.Position = TimeSpan.Zro;
//Play the music
_backgroundMusic.Play();
}
Then I just had to worry about disposing of the objects and cleaning up the temp file when the program is closing.

UWP AutoNext Function

I'm trying to Get a Auto Next method i've tried using a Index Counter but I think I misunderstand how to properly set a list using the FilePicker
The code for the FilePicker is following :
public async void pick_Click_1(object sender, RoutedEventArgs e)
{
List<StorageFile> fileList = new List<StorageFile>();
var fop = new FileOpenPicker();
fop.FileTypeFilter.Add(".mp3");
fop.FileTypeFilter.Add(".mp4");
fop.FileTypeFilter.Add(".avi");
fop.FileTypeFilter.Add(".wmv");
fop.ViewMode = PickerViewMode.List;
pickedFileList = await fop.PickMultipleFilesAsync();
// add the picked files to our existing list
fileList.AddRange(pickedFileList);
foreach (StorageFile file in pickedFileList)
{
Playlist.Items.Add(file);
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
videoMediaElement.SetSource(stream, file.ContentType);
}
videoMediaElement.Play();
The Current method i have for switching tracks|Videos
private async void itemclicked(object sender, ItemClickEventArgs e)
{
var file = e.ClickedItem as StorageFile;
if (file != null)
{
var stream = await file.OpenReadAsync();
videoMediaElement.SetSource(stream, file.ContentType);
}
}
Empty Event im trying to use to do this.
private void Element_MediaEnded(object sender, RoutedEventArgs e)
{
}
I've looked threw all the Microsoft Sample's. Issue Being They use the Mediaplayerelement += Mediaplayer And im using the MediaElement
The Answers Im looking for Can be A Resolution to my problem or assisting me in better understanding how to globally set the source of the mediaplayer using the Current or new list from the picker, Im new to all this and trying to grasp everything better Thank you!
I ended up taking Tousee's advice to seem's he's my mentor at this stage, I used the MediaplayerElement and mediaPLaybacklist's which made life Easier. And almost instantly fixed my problem.

Running Background Audio in different pages of UWP App

I am making a UWP App where I run Background Audio in the MainPage on a Button Click event. When I move to another page, there's also a different Media to play in Background Audio Task there.
How can I stop the currently playing Task to run the other? Should I define something globally? Any help regarding this issue?
Edit
I am using this sample: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BackgroundAudio While the backgroundAudio of the first Page is running, I go to the second page and on a click event I set a new List with the following code:
// First update the persisted start track
ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.TrackId, RadioFacade.mySongs[0].MediaUri.ToString()); //here
ApplicationSettingsHelper.SaveSettingsValue(ApplicationSettingsConstants.Position, new TimeSpan().ToString());
// Start task
StartBackgroundAudioTask();
But the new song takes more than the estimated time to run and enter the else of this method:
private void StartBackgroundAudioTask()
{
AddMediaPlayerEventHandlers();
var startResult = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
bool result = backgroundAudioTaskStarted.WaitOne(10000);
//Send message to initiate playback
if (result == true)
{
MessageService.SendMessageToBackground(new UpdatePlaylistMessage(RadioFacade.mySongs));
MessageService.SendMessageToBackground(new StartPlaybackMessage());
}
else
{
throw new Exception("Background Audio Task didn't start in expected time");
}
});
startResult.Completed = new AsyncActionCompletedHandler(BackgroundTaskInitializationCompleted);
}
and the old (first playing) song keeps playing.
I tried to Stop the current BackgroundMediaPlayer using BackgroundMediaPLayer.Shutdown() but it didn't work.
Any idea how to let the old song stop and the current song play?
You can control the background media player by sending messages to it from the foreground. For example,
From the foreground app:
BackgroundMediaPlayer.SendMessageToBackground(new ValueSet
{
{"playnew", "some value"}
});
In your background task:
public sealed class AudioPlayer : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundMediaPlayer.MessageReceivedFromForeground += BackgroundMediaPlayer_MessageReceivedFromForeground;
...
...
}
private async void BackgroundMediaPlayer_MessageReceivedFromForeground(object sender, MediaPlayerDataReceivedEventArgs e)
{
object value;
if (e.Data.TryGetValue("playnew", out value) && value != null)
{
// value will be whatever you pass from the foreground.
BackgroundMediaPlayer.Current.Pause();
BackgroundMediaPlayer.Current.Source = stream source;
BackgroundMediaPlayer.Current.Play();
}
}
...
}
"playnew" can be a global constant in your application. You can use the ValueSet to pass the live stream url to the background task as the value.

MediaElement doesn't play mp3

Trying to make some mediaplayer app. I put the mediaelement on wpf, wrote code to open media. But when i try to play it nothing is happening...
public void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args)
{
if (args.Files.Count > 0)
{
foreach (StorageFile file in args.Files)
{
if (playlist.Contains(file.Path)) return;
playlist.Add(file.Path);
}
}
}
private void PlayButton_OnClick(object sender, RoutedEventArgs e)
{
MyMedia.Source = new Uri(playlist[0], UriKind.RelativeOrAbsolute);
MyMedia.Play();
}
Checked that mediaelement source isn't empty, it has a right value of path.
Try to rebuild like that, still doesnt work
private async void PlayButton_OnClick(object sender, RoutedEventArgs e)
{
var stream = await Playlist[0].OpenAsync(FileAccessMode.Read);
MyMedia.SetSource(stream, Playlist[0].ContentType);
MyMedia.Play();
}
Sorry it was my mistake.
Into my XAML, I forgot that the AutoPlay property of the MediaElement control was set to false.
This solve my problem.
Couple of things you need to watch out.
foreach (StorageFile file in args.Files)
{
if(playlist.Contains(file.Path))
{
return;// Dont return use continue. You will probably skip rest of the files.
}
playlist.Add(file.Path);
}
Add a Watch/Quickwatch to see if the new Uri(playlist[0], UriKind.RelativeOrAbsolute) points to a right location.
Setup source from storage file:
var storageFile = await KnownFolders.MusicLibrary.GetFileAsync("line.mp3");
var stream = await storageFile.OpenAsync(FileAccessMode.Read);
mediaElement.SetSource(stream, storageFile.ContentType);
mediaElement.Play();
I got it from this answer: How to play file from Library by MediaElement?

Play audio from Assets folder in W10 universal app

I have several .wav and .mp3 files in my app under Assets/Audio, and I'm trying to play them when something is tapped in the UI. I've written the following code (with the file name hardcoded for testing purposes), but when the function is triggered, no sound plays. If I replace attempting to play from a file to playing an audio stream created by Windows.Media.SpeechSynthesis.SpeechSynthesizer, everything works fine.
private async void SoundItem_Tapped(object sender, TappedRoutedEventArgs e)
{
ListViewItem soundItem = sender as ListViewItem;
if (soundItem.IsSelected)
{
Uri sourceUri = new Uri(String.Format("ms-appx:///Assets/Audio/151Cry.wav", UriKind.Absolute));
await PlayAudio(sourceUri, soundItem);
}
else if (inUsePlayers.ContainsKey(soundItem))
{
MediaElement player = inUsePlayers[soundItem];
player.Stop();
inUsePlayers.Remove(soundItem);
players.Enqueue(player);
}
else
{
}
}
private async Task PlayAudio(Uri sourceUri, ListViewItem soundItem)
{
MediaElement player = RequestPlayer(soundItem);
player.Source = sourceUri;
player.IsLooping = true;
await player.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
player.Stop();
player.Play();
});
}
Here's the location of the file within the tree:
Aside from dragging the sound files into the project, I've haven't done anything. Maybe they need to be added to a resource file or copied to the output folder as well? I expected that something would throw an exception if the item pointed to by the URI didn't exist, but nothing's being thrown, even when I give it a bogus filename.
You need to do following things to play you media element.
Your resource files should be set to "Copy to Output directory"
value to "Copy if newer" or "Copy always". to do this right
click your resource file go to Properties and set Copy to Output directory value to Copy always and Build action to
content
Your player(MediaElement) should be added somewhere to View xaml
tree. I do not know your RequestPlayer method is adding
mediaEelement to view xaml or not. e.g
layoutRoot.Children.Add(player)
You need to register Player_MediaOpened event to play your
audio file. If you call 'play' before player is opened media will
not play the sound... and if you want that if any thing is happend
to your player not playing than register Player_MediaFailed it
will give you the reason why it is filed to play.
here is the code.
private async Task PlayAudio(Uri sourceUri, ListViewItem soundItem)
{
MediaElement player = RequestPlayer(soundItem);
player.IsLooping = true;
player.AutoPlay = false;
player.MediaOpened += Player_MediaOpened;
player.MediaFailed += Player_MediaFailed;
player.Source = sourceUri;
player.IsLooping = true;
//Add media element to xaml tree if not added by your RequestPlayer Method..
this.LayoutRoot.Children.Add(player);
}
private void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
}
private async void Player_MediaOpened(object sender, RoutedEventArgs e)
{
await player.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
player.Play();
});
}
Hope this helps...

Categories

Resources