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