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);
}
}