diff --git a/CameraStream.cs b/CameraStream.cs index 2da6a35..b27d01e 100644 --- a/CameraStream.cs +++ b/CameraStream.cs @@ -12,12 +12,20 @@ namespace IPCamAppBar public Image Image { get; set; } } + public class StreamExceptionEventArgs : EventArgs + { + public Exception Exception { get; set; } + } + + public delegate void FrameEvent(object sender, FrameEventArgs args); + public delegate void StreamExceptionEvent(object sender, StreamExceptionEventArgs args); internal abstract class CameraStream : IDisposable { public event FrameEvent Frame; + public event StreamExceptionEvent StreamException; private readonly CancellationTokenSource cancelTaskTokenSource = new CancellationTokenSource(); private Task streamTask; @@ -57,6 +65,8 @@ namespace IPCamAppBar request.Credentials = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : ""); } + request.ReadWriteTimeout = 10; + try { HttpWebResponse response; @@ -83,7 +93,11 @@ namespace IPCamAppBar if (cancellationToken.IsCancellationRequested) break; - // TODO onException + OnStreamException(new StreamExceptionEventArgs + { + Exception = e + }); + await Task.Delay(5000, cancellationToken); } } @@ -97,6 +111,12 @@ namespace IPCamAppBar { Frame?.Invoke(this, args); } + + + protected virtual void OnStreamException(StreamExceptionEventArgs args) + { + StreamException?.Invoke(this, args); + } } diff --git a/CameraView.Designer.cs b/CameraView.Designer.cs index e4ca926..7a3d2d9 100644 --- a/CameraView.Designer.cs +++ b/CameraView.Designer.cs @@ -28,9 +28,11 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.ConnectingLabel = new System.Windows.Forms.Label(); this.StreamView = new System.Windows.Forms.PictureBox(); - this.NoDataLabel = new System.Windows.Forms.Label(); + this.IssueLabel = new System.Windows.Forms.Label(); + this.NoDataTimer = new System.Windows.Forms.Timer(this.components); ((System.ComponentModel.ISupportInitialize)(this.StreamView)).BeginInit(); this.SuspendLayout(); // @@ -57,26 +59,31 @@ this.StreamView.TabStop = false; this.StreamView.Visible = false; // - // NoDataLabel + // IssueLabel // - this.NoDataLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.IssueLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.NoDataLabel.BackColor = System.Drawing.Color.Black; - this.NoDataLabel.ForeColor = System.Drawing.Color.DarkRed; - this.NoDataLabel.Location = new System.Drawing.Point(0, 129); - this.NoDataLabel.Name = "NoDataLabel"; - this.NoDataLabel.Size = new System.Drawing.Size(150, 21); - this.NoDataLabel.TabIndex = 2; - this.NoDataLabel.Text = "No data for x seconds"; - this.NoDataLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.NoDataLabel.Visible = false; + this.IssueLabel.BackColor = System.Drawing.Color.Black; + this.IssueLabel.ForeColor = System.Drawing.Color.DarkRed; + this.IssueLabel.Location = new System.Drawing.Point(0, 0); + this.IssueLabel.Name = "IssueLabel"; + this.IssueLabel.Size = new System.Drawing.Size(150, 21); + this.IssueLabel.TabIndex = 2; + this.IssueLabel.Text = "Someone set up us the bomb"; + this.IssueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.IssueLabel.Visible = false; + // + // NoDataTimer + // + this.NoDataTimer.Interval = 1000; + this.NoDataTimer.Tick += new System.EventHandler(this.NoDataTimer_Tick); // // CameraView // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Gray; - this.Controls.Add(this.NoDataLabel); + this.Controls.Add(this.IssueLabel); this.Controls.Add(this.StreamView); this.Controls.Add(this.ConnectingLabel); this.Margin = new System.Windows.Forms.Padding(0); @@ -90,6 +97,7 @@ private System.Windows.Forms.Label ConnectingLabel; private System.Windows.Forms.PictureBox StreamView; - private System.Windows.Forms.Label NoDataLabel; + private System.Windows.Forms.Label IssueLabel; + private System.Windows.Forms.Timer NoDataTimer; } } diff --git a/CameraView.cs b/CameraView.cs index 24dcb0c..00a5d16 100644 --- a/CameraView.cs +++ b/CameraView.cs @@ -9,8 +9,7 @@ namespace IPCamAppBar public partial class CameraView : UserControl { private DateTime lastFrameTime; - private Timer noDataTimer; - + public CameraView(string url) { @@ -18,22 +17,15 @@ namespace IPCamAppBar var cameraStream = new CameraMJPEGStream(); cameraStream.Frame += CameraStreamOnFrame; + cameraStream.StreamException += CameraStreamOnStreamException; cameraStream.Start(url); - noDataTimer = new Timer - { - Interval = 1000 - }; - noDataTimer.Tick += CheckNoData; - Disposed += (sender, args) => { - noDataTimer?.Dispose(); cameraStream?.Dispose(); }; } - private void CameraStreamOnFrame(object sender, FrameEventArgs args) { // The event comes from a background thread, so if needed invoke it on the main thread @@ -45,10 +37,10 @@ namespace IPCamAppBar ConnectingLabel.Visible = false; StreamView.Visible = true; - NoDataLabel.Visible = false; + IssueLabel.Visible = false; lastFrameTime = DateTime.Now; - noDataTimer.Start(); + NoDataTimer.Start(); var viewImage = new Bitmap(Width, Height); using (var graphics = Graphics.FromImage(viewImage)) @@ -86,14 +78,23 @@ namespace IPCamAppBar } - private void CheckNoData(object sender, EventArgs e) + private void CameraStreamOnStreamException(object sender, StreamExceptionEventArgs args) + { + IssueLabel.Text = args.Exception.Message; + IssueLabel.Visible = true; + IssueLabel.BringToFront(); + } + + + private void NoDataTimer_Tick(object sender, EventArgs e) { var timeSinceLastFrame = DateTime.Now - lastFrameTime; if (timeSinceLastFrame.TotalSeconds < 10) return; - NoDataLabel.Text = $@"No data for {timeSinceLastFrame.TotalSeconds} seconds"; - NoDataLabel.Visible = true; + IssueLabel.Text = $@"No data for {(int)timeSinceLastFrame.TotalSeconds} seconds"; + IssueLabel.Visible = true; + IssueLabel.BringToFront(); } } } diff --git a/CameraView.resx b/CameraView.resx index 1af7de1..0c1ffce 100644 --- a/CameraView.resx +++ b/CameraView.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index f265fd7..f2906d1 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -28,18 +28,36 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.CameraViewContainer = new System.Windows.Forms.FlowLayoutPanel(); + this.DefaultContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DefaultContextMenu.SuspendLayout(); this.SuspendLayout(); // // CameraViewContainer // + this.CameraViewContainer.ContextMenuStrip = this.DefaultContextMenu; this.CameraViewContainer.Dock = System.Windows.Forms.DockStyle.Fill; this.CameraViewContainer.Location = new System.Drawing.Point(0, 0); this.CameraViewContainer.Margin = new System.Windows.Forms.Padding(0); this.CameraViewContainer.Name = "CameraViewContainer"; this.CameraViewContainer.Size = new System.Drawing.Size(269, 211); this.CameraViewContainer.TabIndex = 0; - this.CameraViewContainer.Click += new System.EventHandler(this.CameraViewContainer_Click); + // + // DefaultContextMenu + // + this.DefaultContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.closeToolStripMenuItem}); + this.DefaultContextMenu.Name = "ContextMenu"; + this.DefaultContextMenu.Size = new System.Drawing.Size(181, 48); + // + // closeToolStripMenuItem + // + this.closeToolStripMenuItem.Name = "closeToolStripMenuItem"; + this.closeToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.closeToolStripMenuItem.Text = "&Close"; + this.closeToolStripMenuItem.Click += new System.EventHandler(this.CloseToolStripMenuItem_Click); // // MainForm // @@ -53,6 +71,7 @@ this.ShowInTaskbar = false; this.Text = "IPCam AppBar"; this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed); + this.DefaultContextMenu.ResumeLayout(false); this.ResumeLayout(false); } @@ -60,6 +79,8 @@ #endregion private System.Windows.Forms.FlowLayoutPanel CameraViewContainer; + private System.Windows.Forms.ContextMenuStrip DefaultContextMenu; + private System.Windows.Forms.ToolStripMenuItem closeToolStripMenuItem; } } diff --git a/MainForm.cs b/MainForm.cs index 25cb2d5..b03ce03 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -85,9 +85,9 @@ namespace IPCamAppBar } - private void CameraViewContainer_Click(object sender, EventArgs e) + private void CloseToolStripMenuItem_Click(object sender, EventArgs e) { - //Close(); + Close(); } } } diff --git a/MainForm.resx b/MainForm.resx index 1af7de1..fbef4e5 100644 --- a/MainForm.resx +++ b/MainForm.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file