This my code for clapping hand gesture ,i use the result to set a robotic arm end effector to a 3d location for every clap)
i want the event handler to trigger just once for every clap gesture,
and reset for another clap gesture. but when i clap and my hands are close together, my event handler keeps firing!! please how do i correct this issue. could i use a reset method or something
[hand clap code]
float previousDistance = 0.0f;
private void MatchClappingGesture(Skeleton skeleton)
{
if (skeleton == null)
{
return;
}
if (skeleton.Joints[JointType.WristRight].TrackingState == JointTrackingState.Tracked && skeleton.Joints[JointType.WristLeft].TrackingState == JointTrackingState.Tracked)
{
float currentDistance = GetJointDistance(skeleton.Joints[JointType.WristRight], skeleton.Joints[JointType.WristLeft]);
{
if (currentDistance < 0.1f && previousDistance > 0.1f )
{
if (this.GestureRecognized != null)
{
this.GestureRecognized(this, new GestureEventArgs(RecognitionResult.Success));
previousDate = DateTime.Now;
}
}
previousDistance = currentDistance;
}
}
}
this is where i call the event handler
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
kinect = KinectSensor.KinectSensors[0];
kinect.Start();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show("Could not find Kinect Camera: " + ex.Message);
}
kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
kinect.ColorStream.Enable(ColorImageFormat.RgbResolution1280x960Fps12);
kinect.SkeletonStream.Enable(new TransformSmoothParameters()
{
Correction = 0.5f,
JitterRadius = 0.05f,
MaxDeviationRadius = 0.05f,
Prediction = 0.5f,
Smoothing = 0.5f
});
kinect.AllFramesReady += Kinect_SkeletonAllFramesReady;
recognitionEngine = new GestureRecognitionEngine();
armEngine = new ArmControllerEngine();
recognitionEngine.GestureRecognized += new EventHandler<GestureEventArgs>(recognitionEngine_GestureRecognized);
}
event handler fires here
void recognitionEngine_GestureRecognized(object sender,
GestureEventArgs e)
{
//armEngine.setArm(raMove,port,servoId);
MessageBox.Show("HI");
}
the message box prints multiple time instead of just once!!please help
You must bear in mind that Kinect's measurements have a degree of inaccuracy. Also, in certain cases (like when the hands are together!!) that inaccuracy increases greatly, and the detected joint positions start jumping all over the place. Try it with the SDK's provided skeleton viewer and you'll see. This is often mitigated by using smoothing algorithms, but in your case that might not be the most adequate solution. Try increasing the distance you are using to detect the gesture, give it some 20cm or so (btw, what does your GetJointDistance returns? Meters? Then give it 0.2)
void wait(int a)
{
for (int i = 0; i < a; i++) ;
}
int count = 0;
void recognitionEngine_GestureRecognized(object sender, GestureEventArgs e)
{
wait(3);
clapShow();
}
//clap method
void clapShow()
{
count += 1;
if (count == 1)
{
MessageBox.Show("Gesture Capture Within >> " + time.Millisecond.ToString() + " milli Seconds");
}
count = 0 ;
}
}
I called the message box as a method every 3millsecs wait(3) so that slows down the the event handler.
Then set the count to "1" before a gesture then back to "0"after every clap gesture and it works pretty well!!
Note!.... The wait(X) method i created a simple loop that counts down to the value X. It can be any value based on the level of sensitivity level one desires. Thanks jose!!
i hope this helps someone..
Related
right now I'm making a game and a character in it to move the player. I'm just a beginner about programming.
There are 8 buttons, and each button goes to a direction. For example, this my program for
private void btnUp_Click(object sender, EventArgs e)
{
//move up
y = y - 1;
MovePlayer();
UpdateLabelLocation();
}
public void MovePlayer()
{
picPlayer.Location = new Point(x, y);
}
public void UpdateLabelLocation()
{
lblLocation.Text = "Location: (" + x + ", " + y + ")";
}
I want to make it move when I press up, down, left or right keys. Also, if possible I want to make it so that when I press right and up at the same time, it triggers this:
private void btnRightUp_Click(object sender, EventArgs e)
{
//move player
y = y - 1;
x = x + 1;
MovePlayer();
UpdateLabelLocation();
}
I appreciate the help.
What you're essentially doing is creating your own simple game engine. As commentors have noted, you're better off using an existing game engine such as Unity. It's far easier and more liberating than going about it with WinForms.
That said, if you really want to continue with this, I strongly suggest you move the code in the Click handlers to a method. This reduces code duplication. i.e.
private void DownButton_Click(...)
{
MovePlayer(0, 1);
}
private void UpButton_Click(...)
{
MovePlayer(0, -1);
}
public void MovePlayer(float xStep, float yStep)
{
x += xStep;
y += yStep;
MovePlayer();
UpdateLabelLocation();
}
To move down and left you'd call MovePlayer(-1, 1);
To move up and right you'd call MovePlayer(1, -1);
Next you'll need to respond to KeyPress events. i.e.
public void Form_KeyPress(object sender, KeyPressEventArgs args)
{
switch (args.KeyChar) {
case 'a': // Left
args.Handled = true;
MovePlayer(-1, 0);
break;
case 'd': // Right
args.Handled = true;
MovePlayer(1, 0);
break;
case 'w': // Up
args.Handled = true;
MovePlayer(0, -1);
break;
case 's': // Down
args.Handled = true;
MovePlayer(0, 1);
break;
}
}
Note that if you have another control that accepts keyboard input(such as a TextBox), it will intercept the key press. To get around this, use KeyPreview to force the window to preview the input first. args.Handled = true prevents the event from routing to child controls after your code.
Unfortunately WinForms doesn't record multiple keys pressed at the same time, so using KeyPress alone isn't enough to handle corner movement. You can work around this by hooking onto KeyDown and KeyUp, but it's more trouble than it's worth.
Here's a more robust solution. Bear in mind the following isn't thread safe, so if you plan on introducing other threads you'll need to use appropriate locking.
HashSet<KeyCode> state = new HashSet<KeyCode>();
float speed = 120; // 120 pixels/second.
private void Form_KeyDown(object sender, KeyEventArgs args)
{
var key = args.KeyCode;
state.Add(key);
// Fire pressed when a key was up.
if (!state.Contains(key)) {
state.Add(key);
OnKeyPressed(key);
}
}
private void Form_KeyUp(object sender, KeyEventArgs args)
{
var key = args.KeyCode;
state.Remove(key);
// Fire release when a key was down.
if (state.Contains(key)) {
state.Remove(key);
OnKeyReleased(key);
}
}
// Runs when key was up, but pressed just now.
private void OnKeyPressed(KeyCode key)
{
// Trigger key-based actions.
}
// Runs when key was down, but released just now.
private void OnReleased(KeyCode key)
{
// Trigger key-based actions, but on release instead of press.
}
private bool IsDown(KeyCode key)
{
return state.Contains(key);
}
// Trigger this periodically, at least 20 times a second(ideally 60).
// An option to get you started is to use a windows timer, but
// eventually you'll want to use high precision timing instead.
private void Update()
{
var deltaTime = // Calculate the seconds that have passed since the last update.
// Describing it is out of the scope of this answer, but see the links below.
// Determine horizontal direction. Holding both
// A & D down cancels movement on the x-axis.
var directionX = 0;
if (IsDown(KeyCode.A)) {
directionX--;
}
if (IsDown(KeyCode.D)) {
directionX++;
}
// Determine vertical direction. Holding both
// W & S down cancels movement on the y-axis.
var directionY = 0;
if (IsDown(KeyCode.W)) {
directionY--;
}
if (IsDown(KeyCode.S)) {
directionY++;
}
// directionX & directionY should be normalized, but
// I leave that as an exercise for the reader.
var movement = speed * deltaTime;
var offsetX = directionX * movement;
var offsetY = directionY * movement;
MovePlayer(offsetX, offsetY);
}
As you can see, there's quite a bit involved. If you want more fine-grained timing, look into this article. Eventually you'll want to transition to a game loop, but that's yet another topic out of the scope of this answer.
I am new to DirectX and Direct3D/2D etc and just currently running an experiment on whether to pursue making a cad viewer for a machine we have.
I am using the control from here Direct2dOnWPF to enable me to display Direct2D onto WPF window using SharpDX.
At the moment I have the control working and its loads a file and displays a drawing.
I have now created a camera and I have implemented zooming (to a degree) but my issue is with panning. The issue is that when panning I expect the drawing to move with the mouse but it doesn't. Small movements it kind of does but bigger movements cause the drawing to move beyond the mouse movement. Almost like the further I move the mouse in a single movement, the faster it moves.
Ok some code, the Direct2DControl is based on an Image control so I have access to mouse events etc. Here is the some of code on the control with mouse events and a timer. I tried a timer to detect when the mouse stopped as I found the panning would not stop when the mouse did.
// Timer to detect mouse stop
private Timer tmr;
public Direct2dControl()
{
//
// .... Init stuff
//
// Mouse panning
// get mouse position
MouseOrigin = CurrentMousePosition = new Point(0, 0);
tmr = new Timer { Interval = 50 };
tmr.Elapsed += Tmr_Elapsed;
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (!DragIsOn)
{
DragIsOn = true;
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (DragIsOn)
{
DragIsOn = false;
DragStarted = false;
MouseOrigin = CurrentMousePosition = e.GetPosition(this);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (!DragIsOn) return;
MouseMoved = true;
if (!DragStarted)
{
DragStarted = true;
MouseOrigin = CurrentMousePosition = e.GetPosition(this);
tmr.Start();
}
else
{
CurrentMousePosition = e.GetPosition(this);
var x = (float)(MouseOrigin.X - CurrentMousePosition.X);
var y = (float) (MouseOrigin.Y - CurrentMousePosition.Y);
cam.MoveCamera(cam.ScreenToWorld(new Vector2(x, y)));
tmr.Stop();
tmr.Start();
}
}
private void Tmr_Elapsed(object sender, ElapsedEventArgs e)
{
MouseOrigin = CurrentMousePosition;
tmr.Stop();
MouseMoved = false;
}
and the panning in camera class by moving the position.
public void MoveCamera(Vector2 cameraMovement)
{
Vector2 newPosition = Position + cameraMovement;
Position = newPosition;
}
public Matrix3x2 GetTransform3x2()
{
return TransformMatrix3x2;
}
private Matrix3x2 TransformMatrix3x2
{
get
{
return
Matrix3x2.Translation(new Vector2(-Position.X, -Position.Y)) *
Matrix3x2.Rotation(Rotation) *
Matrix3x2.Scaling(Zoom) *
Matrix3x2.Translation(new Vector2(Bounds.Width * 0.5f, Bounds.Height * 0.5f));
}
}
and finally at the start of the begin rendering I update the RenderTarget Transform
target.Transform = cam.GetTransform3x2();
I believe you're calculating the coordinates wrong. First, you need to set the MouseOrigin variable in OnLeftMouseButtonDown and don't modify it in any other method:
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (!DragIsOn)
{
DragIsOn = true;
MouseOrigin = e.GetPosition(this);
// I don't know the type of your cam variable so the following is pseudo code
MouseOrigin.x -= cam.CurrentPosition.x;
MouseOrigin.y -= cam.CurrentPosition.y;
}
}
And modify OnMouseMove like this:
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (!DragIsOn) return;
MouseMoved = true;
var x = (float)(e.GetPosition(this).x - MouseOrigin.X);
var y = (float) (e.GetPosition(this).y - MouseOrigin.Y);
cam.MoveCamera(cam.ScreenToWorld(new Vector2(x, y)));
tmr.Stop();
tmr.Start();
}
The DragStarted and CurrentMousePosition variables are not needed.
Let me know if it works.
I have a PictueBox and I have some dice, I would like to play an animation for the "rolling" of the dice, I did a .gif with the dice, but after the dice stop rolling, I want the actual dice number that I got, I have a random funcion that handles that.
My question is, I press the "Roll Dice" button, it plays the animation and after the animation ends I should set int the picturebox the dice that actually came. but it immediately chnages to the dice number that actually came, skipping the animation;
This is how it works:
dice1.Image = Resources.DiceAnimation; //Here the gif is called to be played
int x = rollDice(); //Here I roll the dice
switch (x){
case 1: dice.Image = resources.diceFace1; //Image set depending on x
break
case 2: //etc...
}
There might be two things needed to do that.
Firstly, you may need to ensure that your PictureBox receives a gif image and it knows it. To do this, please check this answer and this answer. The posts have code to show GifImage frame by frame:
public class GifImage
{
private Image gifImage;
private FrameDimension dimension;
private int frameCount;
private int currentFrame = -1;
private bool reverse;
private int step = 1;
public GifImage(string path)
{
gifImage = Image.FromFile(path);
//initialize
dimension = new FrameDimension(gifImage.FrameDimensionsList[0]);
//gets the GUID
//total frames in the animation
frameCount = gifImage.GetFrameCount(dimension);
}
public bool ReverseAtEnd {
//whether the gif should play backwards when it reaches the end
get { return reverse; }
set { reverse = value; }
}
public Image GetNextFrame()
{
currentFrame += step;
//if the animation reaches a boundary...
if (currentFrame >= frameCount || currentFrame < 1) {
if (reverse) {
step *= -1;
//...reverse the count
//apply it
currentFrame += step;
}
else {
currentFrame = 0;
//...or start over
}
}
return GetFrame(currentFrame);
}
public Image GetFrame(int index)
{
gifImage.SelectActiveFrame(dimension, index);
//find the frame
return (Image)gifImage.Clone();
//return a copy of it
}
}
Use it like this (note that you need a Timer object):
private GifImage gifImage = null;
private string filePath = #"C:\Users\Jeremy\Desktop\ExampleAnimation.gif";
public Form1()
{
InitializeComponent();
//a) Normal way
//pictureBox1.Image = Image.FromFile(filePath);
//b) We control the animation
gifImage = new GifImage(filePath);
gifImage.ReverseAtEnd = false; //dont reverse at end
}
private void button1_Click(object sender, EventArgs e)
{
//Start the time/animation
timer1.Enabled = true;
}
//The event that is animating the Frames
private void timer1_Tick(object sender, EventArgs e)
{
pictureBox1.Image = gifImage.GetNextFrame();
}
Secondly, to know how long you want to run your GIF image, you may need to Get Frame Duration of GIF image like this:
double delayIn10Ms; //declare somewhere
//Initialize on your form load
PropertyItem item = img.GetPropertyItem (0x5100); // FrameDelay in libgdiplus
// Time is in 1/100th of a second
delayIn10Ms = (item.Value [0] + item.Value [1] * 256) * 10;
Then use the delayIn10Ms time plus, probably, a little bit more time to stop your timer. You may also want to check when was the last time your timer Ticks and store it. If it exceeds the given delay time, then you should stop your timer and start it again on dice roll, after image assignment in your switch case.
DateTime currentTick = DateTime.Min;
DateTime startTick = DateTime.Min;
private void timer1_Tick(object sender, EventArgs e)
{
currentTick = DateTime.Now;
if ((currentTick - startTick).TotalSeconds / 100 < delayIn10Ms)
pictureBox1.Image = gifImage.GetNextFrame();
else
timer1.Stop(); //stop the timer
}
//And somewhere else you have
timer1.Start(); //to start the timer
int x = rollDice(); //Here I roll the dice
switch (x){
case 1: dice.Image = resources.diceFace1; //Image set depending on x
break
case 2: //etc...
}
You can make a timer with the Interval property set to the length of the animation and set it's Tag to 0 and in the timer write the code:
if(timer.Tag == "0")
timer.Tag == "1";
else if(timer.Tag == "1")
{
int x = rollDice();
switch (x)
{
case 1: dice.Image = resources.diceFace1; break;
case 2: //etc...
}
timer.Tag == "0";
timer.Stop();
}
I'm doing an 8 Puzzle solver that ultimately stores each node (int[] of elements 0-8) in the path to put the blocks in order in a stack. I have a WPF GUI that displays an int[,]
foreach (var node in stack)
{
int[,] unstrung = node.unstringNode(node); // turns node of int[] into board of int[,]
blocks.setBoard(unstrung); // sets the board to pass in to the GUI
DrawBoard(); // Takes the board (int[,]) and sets the squares on the GUI to match it.
Thread.Sleep(500);
}
The GUI displays the initial board, and then after I click solve, the final (in order) board is displayed correctly. What I want to do is display each node on the board for some amount of time, ultimately arriving at the in-order board. With Thread.Sleep, the GUI will simply pause for the set amount of time before displaying the final node. Any ideas as to why it this code wouldn't display the board at each node every 500ms?
For reference, here's an example output from Console.Write for the nodes:
4,2,3,6,1,0,7,5,8
4,2,0,6,1,3,7,5,8
4,0,2,6,1,3,7,5,8
4,1,2,6,0,3,7,5,8
4,1,2,0,6,3,7,5,8
0,1,2,4,6,3,7,5,8
1,0,2,4,6,3,7,5,8
1,2,0,4,6,3,7,5,8
1,2,3,4,6,0,7,5,8
1,2,3,4,0,6,7,5,8
1,2,3,4,5,6,7,0,8
1,2,3,4,5,6,7,8,0
Edit:
Since my original answer was downvoted for using a Thread instead of a Timer, here is an example using a timer.
The code for using a Thread was just shorter and I wanted to give him a solution quickly.
Also, using a Thread instead of a timer meant he didn't need to pass parameters differently or restructure his loop.
This is why it is a good idea to discuss pros/cons of alternate solutions instead of simply insisting that there is only one right way.
Use the timer_Tick function to update the position.
You might notice that this complicates the original code since you will have to pass parameters differently and restructure your loop.
public partial class Form1 : Form
{
private Point pos = new Point(1,1);
private float[] vel = new float[2];
private Size bounds = new Size(20,20);
private Timer ticky = new Timer(); //System.Windows.Forms.Timer
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ticky.Interval = 20;
ticky.Tick += ticky_Tick;
vel[0] = 4; vel[1] = 0;
ticky.Start();
}
void ticky_Tick(object sender, EventArgs e)
{
updatePosition();
//This tells our form to repaint itself (and call the OnPaint method)
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillEllipse(new SolidBrush(Color.LightBlue), new Rectangle(pos, bounds));
}
private void updatePosition()
{
pos = new Point(pos.X + (int)vel[0], pos.Y + (int)vel[1]);
vel[1] += .5f; //Apply some gravity
if (pos.X + bounds.Width > this.ClientSize.Width)
{
vel[0] *= -1;
pos.X = this.ClientSize.Width - bounds.Width;
}
else if (pos.X < 0)
{
vel[0] *= -1;
pos.X = 0;
}
if (pos.Y + bounds.Height > this.ClientSize.Height)
{
vel[1] *= -.90f; //Lose some velocity when bouncing off the ground
pos.Y = this.ClientSize.Height - bounds.Height;
}
else if (pos.Y < 0)
{
vel[1] *= -1;
pos.Y = 0;
}
}
}
Results:
You can use timers to do all sorts of delayed form drawing:
Original Solution:
//Create a separate thread so that the GUI thread doesn't sleep through updates:
using System.Threading;
new Thread(() => {
foreach (var node in stack)
{
//The invoke only needs to be used when updating GUI Elements
this.Invoke((MethodInvoker)delegate() {
//Everything inside of this Invoke runs on the GUI Thread
int[,] unstrung = node.unstringNode(node); // turns node of int[] into board of int[,]
blocks.setBoard(unstrung); // sets the board to pass in to the GUI
DrawBoard(); // Takes the board (int[,]) and sets the squares on the GUI to match it.
});
Thread.Sleep(500);
}
}).Start();
Solution in 2022:
await Task.Delay(500);
Things really are better these days.
I am using a design for playing wav files one after another. This design is based on mediaEnded event and works fine. When trying to imply this design on very short wav files, the mediaEnded event isn't always raised.
Is their a solution for this problem?
Thanks.
I implemented a workaround using a timer to periodically check for two situations:
Video Playback Position has not moved since last check - indicates the video is stuck.
Video Playback Position is beyond the end of the video - indicates the video is playing but usually just a black screen will be displayed.
If either condition exists force the next vide to start playing.
Note that this is an extract of code from a class file.
namespace XXXX
{
public partial class VideoWindow : Window
{
private DispatcherTimer mediaPositionTimer; // We check the play position of the video each time this fires to see if it has hung
double _lastPosition = -1;
int _video_count;
int videoDuration;
DateTime lastVideoStartTime;
public VideoWindow()
{
adMediaElement.LoadedBehavior = MediaState.Manual;
adMediaElement.MediaEnded += adMediaElement_MediaEnded;
adMediaElement.MediaOpened += adMediaElement_MediaOpened;
adMediaElement.MediaFailed += adMediaElement_MediaFailed;
}
// Increment the counter every time we open a video
void adMediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
Log("Media opened");
_video_count++;
}
// If we have a failure then just start the next video
void adMediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
Log("Media failed");
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
PlayNextMedia();
}));
}
// When a video ends start the next one
private void adMediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
Log("MediaEnded called");
this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
PlayNextMedia();
}));
}
// Stops and Closes any existing video
// Increments the file pointer index
// Switches to display ads if no more videos
// else
// Starts the video playing
private void PlayNextMedia()
{
// Log(String.Format("PlayNextMedia called"));
//Close the existing file and stop the timer
EndVideo2();
adMediaElement.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
adMediaElement.Stop();
adMediaElement.Close();
}));
currentMediaFileIndex++;
if (currentMediaFileIndex > (mediaFileCount - 1))
{
Log(String.Format(" switching to Ads, currentMediaFileIndex = {0}", currentMediaFileIndex));
// Now setup and then run static adds for 10 minutes
currentMediaFileIndex = 0;
StartAds();
}
else
{
Log(String.Format(" switching media, index = {0}", currentMediaFileIndex));
adMediaElement.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
StartVideo2();
}));
}
}
// Stops the mediaPositionTimer, must be called in conjunction with a admediaElement.Pause() or Stop()
private void EndVideo2()
{
// Log("EndVideo2() called");
_is_playing = false;
// Stop the timer
if (mediaPositionTimer != null)
{
mediaPositionTimer.Stop();
}
}
// Load the media file
// Set the volume
// Set the lastVideoStartTime variable
private void StartVideo2()
{
// Log("StartVideo2() called");
loadMediaFile(currentMediaFileIndex);
adMediaElement.Volume = Properties.StationSettings.Default.VolumeMedia;
lastVideoStartTime = DateTime.Now; // Record the time we started
// Stop the timer if it exists, otherwise create a new one
if (mediaPositionTimer == null)
{
mediaPositionTimer = new DispatcherTimer();
// Set up the timer
mediaPositionTimer.Interval = TimeSpan.FromSeconds(10);
mediaPositionTimer.Tick += new EventHandler(positionTimerTick);
}
else
{
mediaPositionTimer.Stop();
}
// Start it running
adMediaElement.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
mediaPositionTimer.Start();
_is_playing = true;
adMediaElement.Play();
}));
}
private void RestartVideo2()
{
//Log("Restart the video");
adMediaElement.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
mediaPositionTimer.Start();
_is_playing = true;
adMediaElement.Play();
}));
}
// Check the playback position of the mediaElement has moved since the last check,
// if not then the video has hung
// Also check if the playback position exceeds the video duration,
// if so it has also hung
// If video has hung then force the next one to start and report a Warning
private void positionTimerTick(object sender, EventArgs e)
{
double duration;
double currentPosition = adMediaElement.Position.TotalSeconds;
if (adMediaElement.NaturalDuration.HasTimeSpan)
{
duration = adMediaElement.NaturalDuration.TimeSpan.TotalSeconds;
}
else
{
duration = 5 * 60; // Default to 5 minutes if video does not report a duration
}
if ((currentPosition == lastPosition) || currentPosition > (duration + 30))
{
// do something
//Log("*** Video position has exceed the end of the media or video playback position has not moved ***");
if (_is_playing)
{
String logString = String.Format("*** Video {0} has frozen ({1}c:{2}l:{3}d)so forcing the next one to start ***", mediaFiles[currentMediaFileIndex], currentPosition, lastPosition, duration);
Log(logString);
PlayNextMedia();
// Send a message indicating we had to do this
mainWindow.SendHeartbeat(MainWindow.STATUS_WARNING, logString);
}
}
lastPosition = currentPosition;
}
}
}