Unable to control volume using MediaElement.Volume property - c#

I'm trying to control the MediaElement volume level and increment it whenever I call the IncreaseVolume method. When it reaches the maximum volume I want to reset it back to the lowest volume setting. I'm noticing however that changing the volume property does nothing to the volume on playback when I call the TextToSpeech method, even though the MediaElement volume property does get set to the new value. What am I doing wrong here? Code is below:
private static readonly MediaElement MediaElement = new MediaElement();
private static readonly SpeechSynthesizer Synthesizer = new SpeechSynthesizer();
public static async void TextToSpeech(string text)
{
var stream = await Synthesizer.SynthesizeTextToStreamAsync(text);
MediaElement.SetSource(stream, stream.ContentType);
MediaElement.Play();
}
public static void IncreaseVolume()
{
if (MediaElement.Volume >= 1)
{
TextToSpeech("Max volume reached");
MediaElement.Volume = 0.1;
}
MediaElement.Volume += 0.1;
TextToSpeech("New volume is " + MediaElement.Volume);
}

I'm noticing however that changing the volume property does nothing to the volume on playback when I call the TextToSpeech method
Please try to add the MediaElement to current page's Visual Tree, or in other words, you need to add the MediaElement as a child of the page. The Volume works only when the MediaElement is in the Visual Tree.
Need something like this:
private static MediaElement mediaElement = new MediaElement();
private static SpeechSynthesizer Synthesizer = new SpeechSynthesizer();
public MainPage()
{
this.InitializeComponent();
MyRootGrid.Children.Add(mediaElement);
}

Related

Embedding LIb.VLC in winform Application

This Question is In reference with my previous question Embedding VLC player in WInform Application in .Net Core. Core.Intialize() Giving Exception
I want to run the player for certain time and during that time video should be on repeat. Currently code looks like this ...
Core.Initialize();
var libvlc = new LibVLC();
// Make VideoView control
VideoView vv = new VideoView();
vv.MediaPlayer = new MediaPlayer(libvlc);
vv.Dock = DockStyle.Fill;
// Add it to the form
Controls.Add(vv);
var uri = new Uri(#"C:\vid.3gp");
// Use command line options as Options for media playback (https://wiki.videolan.org/VLC_command-line_help/)
var media = new Media(libvlc, uri, ":input-repeat=65535");
vv.MediaPlayer.Play(media);
//Set fullscreen
this.FormBorderStyle = FormBorderStyle.None;
this.Size = Screen.PrimaryScreen.Bounds.Size;
this.Location = Screen.PrimaryScreen.Bounds.Location;
How I can close the player after certain time. currently even if I close the form with the player video keeps playing in background till I close the whole application.
Just to inform the this winform application is created in .netcore3.1.
Regards.
Create MediaPlayer as class field and call it to start/pause/stop it in you WinForm application.
private LibVLC _libVlc;
private MediaPlayer _mediaPlayer;
...
// Call this method in your constructor/initializer
private void StartMediaPlayer(string videoUrl)
{
using var media = new Media(_libVlc, new Uri(videoUrl), ":input-repeat=65535");
_mediaPlayer = new MediaPlayer(_libVlc)
{
Media = media
};
_mediaPlayer.Play();
}
// Method to stop media player
private void button1_Click(object sender, EventArgs e)
{
_mediaPlayer.Stop();
}

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.

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
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.

Windows 8 xaudio2 playing wav file in multitouch app

I am learning how to work with xAudio2. Made a simple application Windows 8 in Visual Studio 2012 Express For Windows 8.
Simple xAudio2 player class:
public class SoundEffect
{
readonly XAudio2 _xaudio;
readonly WaveFormat _waveFormat;
readonly AudioBuffer _buffer;
readonly SoundStream _soundstream;
SourceVoice sourceVoice;
public SoundEffect(string soundFxPath)
{
_xaudio = new XAudio2();
var masteringsound = new MasteringVoice(_xaudio);
var nativefilestream = new NativeFileStream(
soundFxPath,
NativeFileMode.Open,
NativeFileAccess.Read,
NativeFileShare.Read);
_soundstream = new SoundStream(nativefilestream);
_waveFormat = _soundstream.Format;
_buffer = new AudioBuffer
{
Stream = _soundstream.ToDataStream(),
AudioBytes = (int)_soundstream.Length,
Flags = BufferFlags.EndOfStream
};
//sourceVoice = null;
}
public void Play()
{
sourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
if (sourceVoice != null)
{
sourceVoice.FlushSourceBuffers();
sourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
sourceVoice.Start();
}
}
public void Stop()
{
sourceVoice.Stop();
}
}
And Xaml:
<Border Background="Gray" MinHeight="150" MinWidth="150" Margin="10,10,0,0" x:Name="A" PointerPressed="btnAPointerPressed" PointerReleased="btnAPointerReleased" />
and:
private SoundEffect shotEffect = new SoundEffect(#"sounds\mywav.wav");
private void btnAPointerPressed(object sender, PointerRoutedEventArgs e)
{
bool _hasCapture = ((Border)sender).CapturePointer(e.Pointer);
shotEffect.Play();
}
private void btnAPointerReleased(object sender, PointerRoutedEventArgs e)
{
((Border)sender).ReleasePointerCapture(e.Pointer);
shotEffect.Stop();
}
Tested in Windows 8 Simulator.
If I press one finger, then everything is fine.
When I click on the button - the sound plays when I let go of your finger - the sound stops.
If I click with two fingers and let go of both fingers, the sound continues to play. And the result is aliasing.
Called two events: btnAPointerPressed and two events: btnAPointerReleased but the sound continues to play. As if the audio stream freezes and continues to play. As if the audio stream freezes and continues to play.
I want to understand the problem haudio2? or I do not properly done something?
When you call Play() again - the previous SourceVoice gets replaced with a new one in your SoundEffect, but you never stop the old one. You should create a new SourceVoice with each touch, but keep them all associated with the pointer IDs so that we can stop each of them when the associated pointers are released.

How can I display multiple images in a loop in a WP7 app?

In my (Silverlight) weather app I am downloading up to 6 seperate weather radar images (each one taken about 20 mins apart) from a web site and what I need to do is display each image for a second then at the end of the loop, pause 2 seconds then start the loop again. (This means the loop of images will play until the user clicks the back or home button which is what I want.)
So, I have a RadarImage class as follows, and each image is getting downloaded (via WebClient) and then loaded into a instance of RadarImage which is then added to a collection (ie: List<RadarImage>)...
//Following code is in my radar.xaml.cs to download the images....
int imagesToDownload = 6;
int imagesDownloaded = 0;
RadarImage rdr = new RadarImage(<image url>); //this happens in a loop of image URLs
rdr.FileCompleteEvent += ImageDownloadedEventHandler;
//This code in a class library.
public class RadarImage
{
public int ImageIndex;
public string ImageURL;
public DateTime ImageTime;
public Boolean Downloaded;
public BitmapImage Bitmap;
private WebClient client;
public delegate void FileCompleteHandler(object sender);
public event FileCompleteHandler FileCompleteEvent;
public RadarImage(int index, string imageURL)
{
this.ImageIndex = index;
this.ImageURL = imageURL;
//...other code here to load in datetime properties etc...
client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
client.OpenReadAsync(new Uri(this.ImageURL, UriKind.Absolute));
}
private void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
StreamResourceInfo sri = new StreamResourceInfo(e.Result as Stream, null);
this.Bitmap = new BitmapImage();
this.Bitmap.SetSource(sri.Stream);
this.Downloaded = true;
FileCompleteEvent(this); //Fire the event to let the app page know to add it to it's List<RadarImage> collection
}
}
}
As you can see, in the class above I have exposed an event handler to let my app page know when each image has downloaded. When they have all downloaded I then run the following code in my xaml page - but only the last image ever shows up and I can't work out why!
private void ImageDownloadedEventHandler(object sender)
{
imagesDownloaded++;
if (imagesDownloaded == imagesToDownload)
{
AllImagesDownloaded = true;
DisplayRadarImages();
}
}
private void DisplayRadarImages()
{
TimerSingleton.Timer.Stop();
foreach (RadarImage img in radarImages)
{
imgRadar.Source = img.Bitmap;
Thread.Sleep(1000);
}
TimerSingleton.Timer.Start(); //Tick poroperty is set to 2000 milliseconds
}
private void SingleTimer_Tick(object sender, EventArgs e)
{
DisplayRadarImages();
}
So you can see that I have a static instance of a timer class which is stopped (if running), then the loop should show each image for a second. When all 6 have been displayed then it pauses, the timer starts and after two seconds DisplayRadarImages() gets called again.
But as I said before, I can only ever get the last image to show for some reason and I can't seem to get this working properly.
I'm fairly new to WP7 development (though not to .Net) so just wondering how best to do this - I was thinking of trying this with a web browser control but surely there must be a more elegant way to loop through a bunch of images!
Sorry this is so long but any help or suggestions would be really appreciated.
Mike
You can use a background thread with either a Timer or Sleep to periodically update your image control.
Phạm Tiểu Giao - Threads in WP7
You'll need to dispatch updates to the UI with
Dispatcher.BeginInvoke( () => { /* your UI code */ } );
Why don't you add the last image twice to radarImages, set the Timer to 1000 and display just one image on each tick?

Categories

Resources