// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ----------------------------------------------------------------------- namespace Microsoft.Samples.Kinect.Webserver.Sensor { using System; using System.Collections.Generic; using Microsoft.Kinect; using Microsoft.Samples.Kinect.Webserver.Sensor.Serialization; /// /// Implementation of ISensorStreamHandler that exposes skeleton streams. /// public class SkeletonStreamHandler : SensorStreamHandlerBase { /// /// JSON name of skeleton stream. /// internal const string SkeletonStreamName = "skeleton"; /// /// Context that allows this stream handler to communicate with its owner. /// private readonly SensorStreamHandlerContext ownerContext; /// /// Serializable skeleton stream message, reused as skeleton frames arrive. /// private readonly SkeletonStreamMessage skeletonStreamMessage = new SkeletonStreamMessage { stream = SkeletonStreamName }; /// /// true if skeleton stream is enabled. Skeleton stream is disabled by default. /// private bool skeletonIsEnabled; /// /// Keep track if we're in the middle of processing an skeleton frame. /// private bool isProcessingSkeletonFrame; /// /// Initializes a new instance of the class /// and associates it with a context that allows it to communicate with its owner. /// /// /// An instance of class. /// internal SkeletonStreamHandler(SensorStreamHandlerContext ownerContext) { this.ownerContext = ownerContext; this.AddStreamConfiguration(SkeletonStreamName, new StreamConfiguration(this.GetProperties, this.SetProperty)); } /// /// Process data from one Kinect skeleton frame. /// /// /// Kinect skeleton data. /// /// /// from which we obtained skeleton data. /// public override void ProcessSkeleton(Skeleton[] skeletons, SkeletonFrame skeletonFrame) { if (skeletonFrame == null) { throw new ArgumentNullException("skeletonFrame"); } this.ProcessSkeletonAsync(skeletons, skeletonFrame.Timestamp); } /// /// Process skeletons in async mode. /// /// /// Kinect skeleton data. /// /// /// Timestamp of from which we obtained skeleton data. /// internal async void ProcessSkeletonAsync(Skeleton[] skeletons, long timestamp) { if (!this.skeletonIsEnabled) { return; } if (this.isProcessingSkeletonFrame) { // Re-entered SkeletonFrameReadyAsync while a previous frame is already being processed. // Just ignore new frames until the current one finishes processing. return; } this.isProcessingSkeletonFrame = true; try { if (skeletons != null) { this.skeletonStreamMessage.timestamp = timestamp; this.skeletonStreamMessage.UpdateSkeletons(skeletons); await this.ownerContext.SendStreamMessageAsync(this.skeletonStreamMessage); } } finally { this.isProcessingSkeletonFrame = false; } } /// /// Gets a skeleton stream property value. /// /// /// Property name->value map where property values should be set. /// private void GetProperties(Dictionary propertyMap) { propertyMap.Add(KinectRequestHandler.EnabledPropertyName, this.skeletonIsEnabled); } /// /// Set a skeleton stream property value. /// /// /// Name of property to set. /// /// /// Property value to set. /// /// /// null if property setting was successful, error message otherwise. /// private string SetProperty(string propertyName, object propertyValue) { bool recognized = true; if (propertyValue == null) { // None of the skeleton stream properties accept a null value return Properties.Resources.PropertyValueInvalidFormat; } try { switch (propertyName) { case KinectRequestHandler.EnabledPropertyName: this.skeletonIsEnabled = (bool)propertyValue; break; default: recognized = false; break; } } catch (InvalidCastException) { return Properties.Resources.PropertyValueInvalidFormat; } if (!recognized) { return Properties.Resources.PropertyNameUnrecognized; } return null; } } }