//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
namespace Microsoft.Samples.Kinect.Webserver.Sensor
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Kinect;
using PropertyMap = System.Collections.Generic.Dictionary;
///
/// Base implementation for interface.
///
public class SensorStreamHandlerBase : ISensorStreamHandler
{
///
/// Map of supported stream names to corresponding stream configurations.
///
private readonly Dictionary streamHandlerConfiguration = new Dictionary();
///
/// Object used to discard errors when clients didn't specify an error dictionary.
///
private readonly IDictionary errorSink = new PropertyMap();
///
/// Array of supported stream names.
///
private string[] supportedStreams;
///
/// Initializes a new instance of the class.
///
protected SensorStreamHandlerBase()
{
}
///
/// Get the names of the stream(s) supported by this stream handler.
///
///
/// An array of stream names.
///
///
/// These names will be used in JSON objects to refer to individual streams.
///
public string[] GetSupportedStreamNames()
{
return this.supportedStreams ?? (this.supportedStreams = this.streamHandlerConfiguration.Keys.ToArray());
}
///
/// Lets ISensorStreamHandler know that Kinect Sensor associated with this stream
/// handler has changed.
///
///
/// New KinectSensor.
///
public virtual void OnSensorChanged(KinectSensor newSensor)
{
}
///
/// Process data from one Kinect color frame.
///
///
/// Kinect color data.
///
///
/// from which we obtained color data.
///
public virtual void ProcessColor(byte[] colorData, ColorImageFrame colorFrame)
{
}
///
/// Process data from one Kinect depth frame.
///
///
/// Kinect depth data.
///
///
/// from which we obtained depth data.
///
public virtual void ProcessDepth(DepthImagePixel[] depthData, DepthImageFrame depthFrame)
{
}
///
/// Process data from one Kinect skeleton frame.
///
///
/// Kinect skeleton data.
///
///
/// from which we obtained skeleton data.
///
public virtual void ProcessSkeleton(Skeleton[] skeletons, SkeletonFrame skeletonFrame)
{
}
///
/// Gets the state property values associated with the specified stream name.
///
///
/// Name of stream for which property values should be returned.
///
///
/// Dictionary mapping property names to property values.
///
public IDictionary GetState(string streamName)
{
var propertyMap = new Dictionary();
StreamConfiguration config;
if (!this.streamHandlerConfiguration.TryGetValue(streamName, out config))
{
throw new ArgumentException(@"Unsupported stream name", "streamName");
}
config.GetPropertiesCallback(propertyMap);
return propertyMap;
}
///
/// Attempts to set the specified state property values associated with the specified
/// stream name.
///
///
/// Name of stream for which property values should be set.
///
///
/// Dictionary mapping property names to property values that should be set.
/// Must not be null.
///
///
/// Dictionary meant to receive mappings between property names to errors encountered
/// while trying to set each property value.
/// May be null.
///
///
/// true if there were no errors encountered while setting state. false otherwise.
///
///
/// If is non-null, it is expected that it will be empty
/// when method is called.
///
public bool SetState(string streamName, IReadOnlyDictionary properties, IDictionary errors)
{
bool successful = true;
if (properties == null)
{
throw new ArgumentException(@"properties must not be null", "properties");
}
if (errors == null)
{
// Guarantee code down the line that errors will not be null, but don't let
// the error sink ever get too large.
this.errorSink.Clear();
errors = this.errorSink;
}
StreamConfiguration config;
if (!this.streamHandlerConfiguration.TryGetValue(streamName, out config))
{
throw new ArgumentException(@"Unsupported stream name", "streamName");
}
foreach (var keyValuePair in properties)
{
try
{
var error = config.SetPropertyCallback(keyValuePair.Key, keyValuePair.Value);
if (error != null)
{
errors.Add(keyValuePair.Key, error);
successful = false;
}
}
catch (InvalidOperationException)
{
successful = false;
errors.Add(keyValuePair.Key, Properties.Resources.PropertySetError);
}
}
return successful;
}
///
/// Handle an http request.
///
///
/// Name of stream for which property values should be set.
///
///
/// Context containing HTTP request data, which will also contain associated
/// response upon return.
///
///
/// Request URI path relative to the stream name associated with this sensor stream
/// handler in the stream handler owner.
///
///
/// Await-able task.
///
///
/// Return value should never be null. Implementations should use Task.FromResult(0)
/// if function is implemented synchronously so that callers can await without
/// needing to check for null.
///
public virtual Task HandleRequestAsync(string streamName, HttpListenerContext requestContext, string subpath)
{
KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
return SharedConstants.EmptyCompletedTask;
}
///
/// Cancel all pending operations
///
public virtual void Cancel()
{
}
///
/// Lets handler know that it should clean up resources associated with sensor stream
/// handling.
///
///
/// Await-able task.
///
///
/// Return value should never be null. Implementations should use Task.FromResult(0)
/// if function is implemented synchronously so that callers can await without
/// needing to check for null.
///
public virtual Task UninitializeAsync()
{
return SharedConstants.EmptyCompletedTask;
}
///
/// Add a configuration corresponding to the specified stream name.
///
///
/// Stream name.
///
///
/// Stream configuration.
///
protected void AddStreamConfiguration(string name, StreamConfiguration configuration)
{
this.streamHandlerConfiguration.Add(name, configuration);
this.supportedStreams = null;
}
///
/// Helper class used to configure SensorStreamHandlerBase subclass behavior.
///
protected class StreamConfiguration
{
///
/// Initializes a new instance of the class.
///
///
/// Callback function used to get all state property values.
///
///
/// Callback function used to set individual state property values.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Outer generic is a functional type and won't require cumbersome syntax to use")]
public StreamConfiguration(Action getPropertiesCallback, Func setPropertyCallback)
{
this.GetPropertiesCallback = getPropertiesCallback;
this.SetPropertyCallback = setPropertyCallback;
}
///
/// Gets the callback function used to get all state property values.
///
///
/// Callback parameter is a property name->value map where property values should
/// be set.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Outer generic is a functional type and won't require cumbersome syntax to use")]
public Action GetPropertiesCallback { get; private set; }
///
/// Gets the callback function used to set individual state property values.
///
public Func SetPropertyCallback { get; private set; }
}
}
}