I have created a Windows Form Application having axWindowsMediaPlayer control. I haven't created a playlist on it, but I have stored my .mp4 files at a particular location. I pass the path to my next video at Media Ended state. For the first time, the player receives the correct path and play. But for the second video, I can only see a black screen although the player is receiving the correct path to play.
Here is my code for Media Ended State:
private void axWindowsMediaPlayer_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if(e.newState == 8)
{
//Getting jumpTo of selected page
var selectedElementJumpToValue = MainContentAreaBl.GetSelectedElementValue(_currentId, "jumpTo");
if (selectedElementJumpToValue != null)
{
_currentId = selectedElementJumpToValue;
if (_currentId != "menu")
{
pagination.Text = MainContentAreaBl.GetPaginationText(_currentId);
LaunchPlayer(selectedElementJumpToValue);
}
else
{
this.Hide();
this.SendToBack();
menu.BringToFront();
}
}
}
}
private void LaunchPlayer(string id)
{
string selectedElementPageTypeValue = MainContentAreaBl.GetSelectedElementPageTypeValue(id);
var playerFile = Path.Combine(Common.ContentFolderPath, MainContentAreaBl.GetSelectedElementDataPathValue(id));
if (selectedElementPageTypeValue == "video")
{
InitialiseMediaPlayer();
axShockwaveFlash.Stop();
axShockwaveFlash.Visible = false;
if (File.Exists(playerFile))
{
axWindowsMediaPlayer.URL = playerFile;
}
}
else if (selectedElementPageTypeValue == "flash")
{
InitialiseShockwaveFlash();
axWindowsMediaPlayer.close();
axWindowsMediaPlayer.Visible = false;
if (File.Exists(playerFile))
{
axShockwaveFlash.Movie = playerFile;
axShockwaveFlash.Play();
}
}
}
private void InitialiseMediaPlayer()
{
axWindowsMediaPlayer.Visible = true;
axWindowsMediaPlayer.enableContextMenu = false
axWindowsMediaPlayer.uiMode = "none";
axWindowsMediaPlayer.Dock = DockStyle.Fill;
}
When I debugged my application, I saw Media Player getting the correct path after e.newState == 10 (Ready state). What am I doing wrong?
Edit 1: I found out that after my current video enters into Media Ended state, the player is stopped from playing. Even if I write axWindowsMediaPlayer.ctlControls.play();, it doesn't affect the media player. Is this a bug from in axWindowsMediaPlayer?
I have encountered this issue before as well. The most likely cause is that you are giving the command axWindowsMediaPlayer.ctlControls.play(); while the play state is still changing ( after Media Ended, it will change to Ready state). If a command is sent to the player while the play state is changing, it won't do anything. Another possible cause of your error is that sometimes Media State 9 (transitioning) needs to be included with if(e.newState == 8) such that you have if(e.newState == 8 | e.newState==9). I have had cases where it doesn't pick up on State 8 (media ending), possibly because it happens really fast and jumps to transitioning - not completely sure of this cause but I had a player that wasn't moving to the next video in the playlist because of this happening. To solve this I did something like:
if (e.newState == 8 | e.newState== 9 | e.newState== 10)
{
if (e.newState == 8)
{ //Insert your code here
}
This would vary slightly depending on what you are trying to achieve. Another thing to watch out for is using the PlayStateChange Event to set the Video URL, this causes problems as a result of re-entry problems with WMP - see other posts for further explanation on my last comment:
here is a good one and another here. Hope this helps!
Related
I've been stuck on this all day, so I'm going to post everything I've been able to find today that might be useful to helping me, it will be a long post. I'm having 2 issues that I believe are related to the same problem. First, let me explain what I am doing. I have 3 Winforms combo boxes that are bound to lists of all of the devices found by MMDeviceEnumerator. Two output device boxes, one input device. I am using the MMDeviceEnumerator to register a callback for whenever the devices are changed, removed, or a default device is set. The callback fires an event that then invokes a delegate to the form thread to re-enumerate the devices into combo boxes. It looks like this:
public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
{
Devices.OnDevicesUpdated();
}
//The handler called by this event:
private void UpdateDeviceSelectors(object? sender = null, EventArgs? e = null)
{
Invoke(delegate ()
{
int primaryIndex = Devices.PrimaryOutput + 1, secondaryIndex = Devices.SecondaryOutput + 2, microphoneIndex = Devices.Microphone + 1;
Devices.Refresh();
try
{
SecondaryOutputComboBox.SelectedIndex = secondaryIndex;
PrimaryOutputComboBox.SelectedIndex = primaryIndex;
MicrophoneSelectComboBox.SelectedIndex = microphoneIndex;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
});
}
Now for the two issues I have. The first one involves a semi-random crash that leads back to NAudio.Wasapi.dll, where a System.ExecutionEngineException is thrown. It is kind of easy to reproduce. All I do is change the values of the combo boxes, switch the default devices around, and it will randomly crash.
The second issue occurs when another part of my code is involved. I have a microphone injector, which redirects a WaveInEvent that records a selected input device to a WaveOutEvent, like a loopback. Here is the relevant code for this:
public void Start()
{
if (Soundboard.Devices.SecondaryOutput == -2) return;
micStream = new WaveInEvent();
micStream.BufferMilliseconds = 50;
micStream.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(Soundboard.Devices.Microphone).Channels);
micStream.DeviceNumber = Soundboard.Devices.Microphone;
WaveInProvider waveIn = new(micStream);
var volumeSampleProvider = new VolumeSampleProvider(waveIn.ToSampleProvider());
volumeSampleProvider.Volume = 1 + Settings.Default.MicrophoneGain;
virtualCable = new WaveOutEvent();
virtualCable.DesiredLatency = 150;
virtualCable.DeviceNumber = Soundboard.Devices.SecondaryOutput;
virtualCable.Init(volumeSampleProvider);
micStream.StartRecording();
virtualCable.Play();
}
public void Stop()
{
try
{
if (micStream != null && virtualCable != null)
{
micStream.Dispose();
micStream = null;
virtualCable.Dispose();
virtualCable = null;
}
}
catch
{
micStream = null;
virtualCable = null;
}
}
In the delegate mentioned earlier, I am calling the Stop method of the Mic Injector and then the Start method to refresh the WaveIn and WaveOut devices to use the current device numbers so users do not see a device selected when a different device is being used. When this happens, the program, rather than crashing instantly and inconsistently, always hangs and has to be killed from the task manager. I am certain these 2 problems are related to the same root cause, but I have no idea what that root cause may be. Switching to Wasapi, DirectSound, or ASIO won't work because they lack certain functionalities I need, so I would really like to get this working still using Wave streams.
I've tried to find different ways to detect the device changes, assuming it is an issue deep inside NAudio, but I just can't find anything else. For the second problem specifically, I have moved the calls to the Mic Injector around thinking it may be a threading issue or something, but it didn't work or change the behavior.
I am trying to create a simple media player that just runs from the notifyIcon tray using a context menu strip, sitting on an hidden form.
When I click on the menu item 'play mp3's' it opens up a folder, allowing me to select a bunch of mp3 tracks. These tracks are stored in a listbox on the hidden form allowing me to manipulate them through the C# code. The code I have will always play the first song, no problem, but the ones after that has been a pain.
The way I found to make the songs continue to play was by using ShowDialog for each song, but as you guessed that means there are multiple instances of the same form. Soon as I stop using the show.dialog, I am back to one song again. Is it because I am using the WMPLib without the actual player on the form, I am sure that is not the case. I have managed to pick up tons of knowledge on here to get me this far, like using PlayStateChange, being able to select the next Item in the list box and how to play a song list. Unfortunately most of the time this is with using the media player console and buttons.
Here is the specific code that is causing the issue, as it stands it plays every track, soon as I comment out showdialog, it only plays the first song.
private void trackplayer()
{
listBox1.SelectedIndex = listBox1.SelectedIndex + 1;
var selectedUrl = listBox1.SelectedItem.ToString();
player.URL = selectedUrl;
player.controls.play();
mytempFormOpen();
}
public void mytempFormOpen()
{
var myform1 = new Form1();
myform1.ShowDialog();
}
Could you please help a frustrated newbie, any questions I am happy to respond to.
Here is my FormLoad section
#region check internet when form opens
private void Form1_Load(object sender, EventArgs e)
{
notifyIcon1.Text = (playingToolStripMenuItem.Text);
checkTheInternet();
}
#endregion
Here is the Internet Checker Code called from the loadform
#region Check for Internet Connection Loop
private void checkTheInternet()
{
while (true)
{
bool con = NetworkInterface.GetIsNetworkAvailable();
if (con == false)
{
MessageBox.Show("No Internet Connection!");
playingToolStripMenuItem.Text = "No Internet Connection!";
notifyIcon1.Icon = radio_Off;
notifyIcon1.Visible = true;
return;
}
else
{
return;
}
}
}
#endregion
This is where the file selection starts
region Play MP3 List Automatically
private void mP3ToolStripMenuItem_Click(object sender, EventArgs e)
{
player.PlayStateChange += new WMPLib._WMPOCXEvents_PlayStateChangeEventHandler(player_PlayStateChange);
string[] files, paths;
OpenFileDialog oFD = new OpenFileDialog();
oFD.Multiselect = true;
oFD.Filter = "Music Files |*.mp3;*.wav";
if (oFD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
pauseToolStripMenuItem.Visible = true;
files = oFD.SafeFileNames;
for (int i = 0; i < files.Length; i++)
{
listBox1.Items.Add(paths[i]);
myCount = i + 1;
}
trackplayer();
}
}
If opening a new form is needed to play your song, I am not sure why since I do not have all your code, but you do not want multiple forms then do this. Create a private field which will hold a reference to your form:
private Form1 prevForm;
Change your myTempFormOpen to:
public void mytempFormOpen()
{
if (prevForm != null)
{
prevForm.Close();
}
prevForm = new Form1();
prevForm.ShowDialog();
}
Also myTempFormOpen should be MyTempFormOpen to follow .NET naming conventions.
Also in checkInternet method, you can return right away if connection is true instead of checking false first. Also, not sure why you need the while loop.
Let me know if that solves your issue.
I eventually found the answer by using a timer. The answer to the solution can be found here How to detect when a mp3 file has finished playing Big Thanks to all those that helped.
I am experiencing some crashes on my app (somewhat similar to a compass app). The windows crash report is telling me this:
frame 0:
Microsoft.Devices.Sensors.ni.dll; Microsoft.Devices.Sensors.Accelerometer.Start; 0x0000006c
frame 1:
PivotApp1.ni.DLL; PivotApp1.MainPage+_start_d__0.MoveNext; 0x000001d4
frame 2:
mscorlib.ni.dll; System.Runtime.CompilerServices.AsyncMethodBuilderCore._ThrowAsync_b__3; 0x00000036
I am unable to understand what this exactly means here. Based on what I get from it, it is probably because of the accelerometer.
This is my current code and It seems like the error is generated from somewhere in here :
private async void start()
{
//Check for the user agreement in use his position. If not, method returns.
if ((bool)IsolatedStorageSettings.ApplicationSettings["LocationConsent"] != true)
{
// The user has opted out of Location.
MessageBox.Show(AppResources.main_cantuse);
Application.Current.Terminate();
}
else
{
//KOMPASS
if (compass == null)
{
// Instantiate the compass.
compass = new Compass();
// Specify the desired time between updates. The sensor accepts
// intervals in multiples of 20 ms.
compass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
compass.CurrentValueChanged +=
new EventHandler<SensorReadingEventArgs<CompassReading>>(compass_CurrentValueChanged);
compass.Calibrate +=
new EventHandler<CalibrationEventArgs>(compass_Calibrate);
}
try
{
compass.Start();
timer.Start();
accelerometer = new Accelerometer();
accelerometer.CurrentValueChanged +=
new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(accelerometer_CurrentValueChanged);
accelerometer.Start();
}
catch (InvalidOperationException)
{
MessageBox.Show(AppResources.main_unabletostart);
}
I would like to ask, Do I have to check if the accelerometer is ready (or null check or something else) ?
Any help or guidance here is appreciated.
Those crashes are probably from devices that do not have a compass (yes, there are devices like this out there).
You should check for the compass with Compass.IsSupported and only use it when it returns true.
I am trying to create a Coded UI property that checks for an open WMP file.
public BrowserWindow VideoWindow
{
get
{
if (this._videoWindow == null || !this._videoWindow.Exists)
{
this._videoWindow = new BrowserWindow();
this._videoWindow.SearchProperties["Name"] = "Windows Media Player";
this._videoWindow.SearchProperties["ControlType"] = "Window";
}
return this._videoWindow;
}
}
Obviously, this will not work. Originally, the application opened a link to a video site. So this worked, but since it is quite a bit different than a BrowserWindow I am not sure how to do it. How can I use Coded UI to "grab" it?
The only real difference for windows media player from the video site you've been dealing with is that windows media player will be a WpfWindow instead of a BrowserWindow -
public WpfWindow VideoWindow
{
get
{
if (this._videoWindow == null || !this._videoWindow.Exists)
{
this._videoWindow = new WpfWindow();
this._videoWindow.SearchProperties["Name"] = "Windows Media Player";
this._videoWindow.WindowTitles.Add("Windows Media Player");
}
return this._videoWindow;
}
}
After that, you just have to get the controls inside of the media player window(WpfControls instead of HtmlControls) to determine which file is open.
I am once again a bit stuck in my practising.
I want an MP3 file to play when i open my program - I can do that, i got music.
I also want a checkbox which allows to pause the music - But either I'm very tired, or the thing won't work - Nothing happens when i check/uncheck it. I've done it like this:
public void PlayPause(int Status)
{
WMPLib.WindowsMediaPlayer wmp = new WMPLib.WindowsMediaPlayer();
switch (Status)
{
case 0:
wmp.URL = "Musik.mp3";
break;
case 1:
wmp.controls.play();
break;
case 2:
wmp.controls.pause();
break;
}
}
Upon opening the program, the method is called with case 0. Music plays. All good.
However this doesn't work, and i don't get why, as it is pretty simple code.
public void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
PlayPause(2);
}
else if (checkBox1.Checked == false)
{
PlayPause(1);
}
}
Any idea as to why checking the checkbox doesn't pause/unpause the music?
You're instantiating a completely new WindowsMediaPlayer object each time you call that PlayPause function.
Thus, when you call pause later on, you're pausing nothing.
You need to hold or pass a reference to that WMP object around, so that you're operating on the same one.
Well it's because you are creating a new media player every time you call PlayPause. Create it in the constructor and it should be fine.