using System; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; namespace IPCamLib.Base { /// /// Abstract base class for IP cameras reading an HTTP stream. /// public abstract class BaseHTTPStreamCamera : ICamera { private readonly Uri streamUri; /// The URI to the camera stream. /// Can include basic credentials in the standard 'username:password@' format. protected BaseHTTPStreamCamera(Uri streamUri) { this.streamUri = streamUri; } /// public async Task Fetch(ICameraObserver observer, CancellationToken cancellationToken) { var request = WebRequest.CreateHttp(streamUri); if (!string.IsNullOrEmpty(streamUri.UserInfo)) { var parts = streamUri.UserInfo.Split(':'); request.Credentials = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : ""); } request.ReadWriteTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds; try { HttpWebResponse response; using (cancellationToken.Register(() => request.Abort(), false)) { response = (HttpWebResponse)await request.GetResponseAsync(); cancellationToken.ThrowIfCancellationRequested(); } if (response.StatusCode != HttpStatusCode.OK) throw new WebException(response.StatusDescription); using var responseStream = response.GetResponseStream(); await ReadFrames(observer, responseStream, cancellationToken); } catch (TaskCanceledException) { } finally { request.Abort(); } } /// /// Implement in concrete descendants to continuously read frames from the HTTP stream. /// /// The observer implementation passed to Fetch which should receive the decoded frames. /// The HTTP response stream. /// Stop reading frames when this token is cancelled. protected abstract Task ReadFrames(ICameraObserver observer, Stream stream, CancellationToken cancellationToken); } }