/// <summary>
        /// Handle an http request.
        /// </summary>
        /// <param name="streamName">
        /// Name of stream for which property values should be set.
        /// </param>
        /// <param name="requestContext">
        /// Context containing HTTP request data, which will also contain associated
        /// response upon return.
        /// </param>
        /// <param name="subpath">
        /// Request URI path relative to the stream name associated with this sensor stream
        /// handler in the stream handler owner.
        /// </param>
        /// <returns>
        /// Await-able task.
        /// </returns>
        /// <remarks>
        /// 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.
        /// </remarks>
        public override Task HandleRequestAsync(string streamName, HttpListenerContext requestContext, string subpath)
        {
            if (streamName == null)
            {
                throw new ArgumentNullException("streamName");
            }

            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            if (subpath == null)
            {
                throw new ArgumentNullException("subpath");
            }

            if (!InteractionStreamName.Equals(streamName))
            {
                // Only supported endpoints are related to interaction stream
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                return(SharedConstants.EmptyCompletedTask);
            }

            var splitPath = KinectRequestHandler.SplitUriSubpath(subpath);

            if (splitPath == null)
            {
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                return(SharedConstants.EmptyCompletedTask);
            }

            var pathComponent = splitPath.Item1;

            switch (pathComponent)
            {
            case ClientUriSubpath:
                // Only support one client at any one time
                if (this.clientRpcChannel != null)
                {
                    if (this.clientRpcChannel.CheckConnectionStatus())
                    {
                        KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.Conflict);
                        return(SharedConstants.EmptyCompletedTask);
                    }

                    this.clientRpcChannel = null;
                }

                WebSocketRpcChannel.TryOpenAsync(
                    requestContext,
                    channel =>
                {
                    // Check again in case another request came in before connection was established
                    if (this.clientRpcChannel != null)
                    {
                        channel.Dispose();
                    }

                    this.clientRpcChannel = channel;
                },
                    channel =>
                {
                    // Only forget the current channel if it matches the channel being closed
                    if (this.clientRpcChannel == channel)
                    {
                        this.clientRpcChannel = null;
                    }
                });

                break;

            default:
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                break;
            }

            return(SharedConstants.EmptyCompletedTask);
        }
        /// <summary>
        /// Handle an http request.
        /// </summary>
        /// <param name="streamName">
        /// Name of stream for which property values should be set.
        /// </param>
        /// <param name="requestContext">
        /// Context containing HTTP request data, which will also contain associated
        /// response upon return.
        /// </param>
        /// <param name="subpath">
        /// Request URI path relative to the stream name associated with this sensor stream
        /// handler in the stream handler owner.
        /// </param>
        /// <returns>
        /// Await-able task.
        /// </returns>
        /// <remarks>
        /// 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.
        /// </remarks>
        public override Task HandleRequestAsync(string streamName, HttpListenerContext requestContext, string subpath)
        {
            if (streamName == null)
            {
                throw new ArgumentNullException("streamName");
            }

            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            if (subpath == null)
            {
                throw new ArgumentNullException("subpath");
            }

            if (!InteractionStreamName.Equals(streamName))
            {
                // Only supported endpoints are related to interaction stream
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                return SharedConstants.EmptyCompletedTask;
            }

            var splitPath = KinectRequestHandler.SplitUriSubpath(subpath);

            if (splitPath == null)
            {
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                return SharedConstants.EmptyCompletedTask;
            }

            var pathComponent = splitPath.Item1;
            switch (pathComponent)
            {
            case ClientUriSubpath:
                // Only support one client at any one time
                if (this.clientRpcChannel != null)
                {
                    if (this.clientRpcChannel.CheckConnectionStatus())
                    {
                        KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.Conflict);
                        return SharedConstants.EmptyCompletedTask;
                    }

                    this.clientRpcChannel = null;
                }

                WebSocketRpcChannel.TryOpenAsync(
                    requestContext,
                    channel =>
                        {
                            // Check again in case another request came in before connection was established
                            if (this.clientRpcChannel != null)
                            {
                                channel.Dispose();
                            }

                            this.clientRpcChannel = channel;
                        },
                    channel =>
                        {
                            // Only forget the current channel if it matches the channel being closed
                            if (this.clientRpcChannel == channel)
                            {
                                this.clientRpcChannel = null;
                            }
                        });

                break;

            default:
                KinectRequestHandler.CloseResponse(requestContext, HttpStatusCode.NotFound);
                break;
            }

            return SharedConstants.EmptyCompletedTask;
        }