1 | // -----------------------------------------------------------------------
|
---|
2 | // <copyright file="SkeletonStreamHandler.cs" company="Microsoft">
|
---|
3 | // Copyright (c) Microsoft Corporation. All rights reserved.
|
---|
4 | // </copyright>
|
---|
5 | // -----------------------------------------------------------------------
|
---|
6 |
|
---|
7 | namespace Microsoft.Samples.Kinect.Webserver.Sensor
|
---|
8 | {
|
---|
9 | using System;
|
---|
10 | using System.Collections.Generic;
|
---|
11 |
|
---|
12 | using Microsoft.Kinect;
|
---|
13 | using Microsoft.Samples.Kinect.Webserver.Sensor.Serialization;
|
---|
14 |
|
---|
15 | /// <summary>
|
---|
16 | /// Implementation of ISensorStreamHandler that exposes skeleton streams.
|
---|
17 | /// </summary>
|
---|
18 | public class SkeletonStreamHandler : SensorStreamHandlerBase
|
---|
19 | {
|
---|
20 | /// <summary>
|
---|
21 | /// JSON name of skeleton stream.
|
---|
22 | /// </summary>
|
---|
23 | internal const string SkeletonStreamName = "skeleton";
|
---|
24 |
|
---|
25 | /// <summary>
|
---|
26 | /// Context that allows this stream handler to communicate with its owner.
|
---|
27 | /// </summary>
|
---|
28 | private readonly SensorStreamHandlerContext ownerContext;
|
---|
29 |
|
---|
30 | /// <summary>
|
---|
31 | /// Serializable skeleton stream message, reused as skeleton frames arrive.
|
---|
32 | /// </summary>
|
---|
33 | private readonly SkeletonStreamMessage skeletonStreamMessage = new SkeletonStreamMessage { stream = SkeletonStreamName };
|
---|
34 |
|
---|
35 | /// <summary>
|
---|
36 | /// true if skeleton stream is enabled. Skeleton stream is disabled by default.
|
---|
37 | /// </summary>
|
---|
38 | private bool skeletonIsEnabled;
|
---|
39 |
|
---|
40 | /// <summary>
|
---|
41 | /// Keep track if we're in the middle of processing an skeleton frame.
|
---|
42 | /// </summary>
|
---|
43 | private bool isProcessingSkeletonFrame;
|
---|
44 |
|
---|
45 | /// <summary>
|
---|
46 | /// Initializes a new instance of the <see cref="SkeletonStreamHandler"/> class
|
---|
47 | /// and associates it with a context that allows it to communicate with its owner.
|
---|
48 | /// </summary>
|
---|
49 | /// <param name="ownerContext">
|
---|
50 | /// An instance of <see cref="SensorStreamHandlerContext"/> class.
|
---|
51 | /// </param>
|
---|
52 | internal SkeletonStreamHandler(SensorStreamHandlerContext ownerContext)
|
---|
53 | {
|
---|
54 | this.ownerContext = ownerContext;
|
---|
55 |
|
---|
56 | this.AddStreamConfiguration(SkeletonStreamName, new StreamConfiguration(this.GetProperties, this.SetProperty));
|
---|
57 | }
|
---|
58 |
|
---|
59 | /// <summary>
|
---|
60 | /// Process data from one Kinect skeleton frame.
|
---|
61 | /// </summary>
|
---|
62 | /// <param name="skeletons">
|
---|
63 | /// Kinect skeleton data.
|
---|
64 | /// </param>
|
---|
65 | /// <param name="skeletonFrame">
|
---|
66 | /// <see cref="SkeletonFrame"/> from which we obtained skeleton data.
|
---|
67 | /// </param>
|
---|
68 | public override void ProcessSkeleton(Skeleton[] skeletons, SkeletonFrame skeletonFrame)
|
---|
69 | {
|
---|
70 | if (skeletonFrame == null)
|
---|
71 | {
|
---|
72 | throw new ArgumentNullException("skeletonFrame");
|
---|
73 | }
|
---|
74 |
|
---|
75 | this.ProcessSkeletonAsync(skeletons, skeletonFrame.Timestamp);
|
---|
76 | }
|
---|
77 |
|
---|
78 | /// <summary>
|
---|
79 | /// Process skeletons in async mode.
|
---|
80 | /// </summary>
|
---|
81 | /// <param name="skeletons">
|
---|
82 | /// Kinect skeleton data.
|
---|
83 | /// </param>
|
---|
84 | /// <param name="timestamp">
|
---|
85 | /// Timestamp of <see cref="SkeletonFrame"/> from which we obtained skeleton data.
|
---|
86 | /// </param>
|
---|
87 | internal async void ProcessSkeletonAsync(Skeleton[] skeletons, long timestamp)
|
---|
88 | {
|
---|
89 | if (!this.skeletonIsEnabled)
|
---|
90 | {
|
---|
91 | return;
|
---|
92 | }
|
---|
93 |
|
---|
94 | if (this.isProcessingSkeletonFrame)
|
---|
95 | {
|
---|
96 | // Re-entered SkeletonFrameReadyAsync while a previous frame is already being processed.
|
---|
97 | // Just ignore new frames until the current one finishes processing.
|
---|
98 | return;
|
---|
99 | }
|
---|
100 |
|
---|
101 | this.isProcessingSkeletonFrame = true;
|
---|
102 |
|
---|
103 | try
|
---|
104 | {
|
---|
105 | if (skeletons != null)
|
---|
106 | {
|
---|
107 | this.skeletonStreamMessage.timestamp = timestamp;
|
---|
108 | this.skeletonStreamMessage.UpdateSkeletons(skeletons);
|
---|
109 |
|
---|
110 | await this.ownerContext.SendStreamMessageAsync(this.skeletonStreamMessage);
|
---|
111 | }
|
---|
112 | }
|
---|
113 | finally
|
---|
114 | {
|
---|
115 | this.isProcessingSkeletonFrame = false;
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | /// <summary>
|
---|
120 | /// Gets a skeleton stream property value.
|
---|
121 | /// </summary>
|
---|
122 | /// <param name="propertyMap">
|
---|
123 | /// Property name->value map where property values should be set.
|
---|
124 | /// </param>
|
---|
125 | private void GetProperties(Dictionary<string, object> propertyMap)
|
---|
126 | {
|
---|
127 | propertyMap.Add(KinectRequestHandler.EnabledPropertyName, this.skeletonIsEnabled);
|
---|
128 | }
|
---|
129 |
|
---|
130 | /// <summary>
|
---|
131 | /// Set a skeleton stream property value.
|
---|
132 | /// </summary>
|
---|
133 | /// <param name="propertyName">
|
---|
134 | /// Name of property to set.
|
---|
135 | /// </param>
|
---|
136 | /// <param name="propertyValue">
|
---|
137 | /// Property value to set.
|
---|
138 | /// </param>
|
---|
139 | /// <returns>
|
---|
140 | /// null if property setting was successful, error message otherwise.
|
---|
141 | /// </returns>
|
---|
142 | private string SetProperty(string propertyName, object propertyValue)
|
---|
143 | {
|
---|
144 | bool recognized = true;
|
---|
145 |
|
---|
146 | if (propertyValue == null)
|
---|
147 | {
|
---|
148 | // None of the skeleton stream properties accept a null value
|
---|
149 | return Properties.Resources.PropertyValueInvalidFormat;
|
---|
150 | }
|
---|
151 |
|
---|
152 | try
|
---|
153 | {
|
---|
154 | switch (propertyName)
|
---|
155 | {
|
---|
156 | case KinectRequestHandler.EnabledPropertyName:
|
---|
157 | this.skeletonIsEnabled = (bool)propertyValue;
|
---|
158 | break;
|
---|
159 |
|
---|
160 | default:
|
---|
161 | recognized = false;
|
---|
162 | break;
|
---|
163 | }
|
---|
164 | }
|
---|
165 | catch (InvalidCastException)
|
---|
166 | {
|
---|
167 | return Properties.Resources.PropertyValueInvalidFormat;
|
---|
168 | }
|
---|
169 |
|
---|
170 | if (!recognized)
|
---|
171 | {
|
---|
172 | return Properties.Resources.PropertyNameUnrecognized;
|
---|
173 | }
|
---|
174 |
|
---|
175 | return null;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | }
|
---|