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