public Task CloseAsync(WebSocketCloseStatus webSocketCloseStatus = WebSocketCloseStatus.NormalClosure, string reason = "Passive Closure")
        {
            SpeechWebSocketLogger.Log("### SpeechWebSocket.STATUS: {0} ###", ClientWebSocket.State);

            switch (ClientWebSocket.State)
            {
            case WebSocketState.Closed:
            case WebSocketState.None:
                ReceiveTokenSource?.Cancel();
                return(Task.CompletedTask);

            case WebSocketState.Aborted:
            case WebSocketState.CloseReceived:
                SendingTokenSource?.Cancel();
                return(Task.CompletedTask);

            case WebSocketState.CloseSent:
                SendingTokenSource?.Cancel();
                return(ClientWebSocket.CloseAsync(webSocketCloseStatus, reason, CancellationToken.None));

            case WebSocketState.Connecting:
                ReceiveTokenSource?.Cancel();
                ClientWebSocket.Abort();
                return(Task.CompletedTask);

            case WebSocketState.Open:
            default:
                SendingTokenSource?.Cancel();
                return(ClientWebSocket.CloseOutputAsync(webSocketCloseStatus, reason, CancellationToken.None));
            }
        }
        protected async Task OnReceiving()
        {
            while (true)
            {
                var bufferBytes               = new byte[ReceiveChunkSize];
                var bufferSegment             = new ArraySegment <byte>(bufferBytes);
                WebSocketReceiveResult result = null;
                ReceiveTokenSource.Token.ThrowIfCancellationRequested();
                do
                {
                    ReceiveTokenSource.Token.ThrowIfCancellationRequested();
                    if (ClientWebSocket.State == WebSocketState.Open || ClientWebSocket.State == WebSocketState.CloseSent)
                    {
                        result = await ClientWebSocket.ReceiveAsync(bufferSegment, CancellationToken.None);

                        string text   = string.Empty;
                        var    buffer = bufferBytes.Skip(bufferSegment.Offset).Take(result.Count).ToArray();

                        switch (result.MessageType)
                        {
                        case WebSocketMessageType.Close:
                            var status      = result.CloseStatus ?? ClientWebSocket.CloseStatus ?? WebSocketCloseStatus.Empty;
                            var description = result.CloseStatusDescription;
                            SpeechWebSocketLogger.Log("### SpeechWebSocket.CLOSING: {0} -> {1} ###", status, description);
                            await CloseAsync(status, description);

                            SpeechWebSocketLogger.Log("### SpeechWebSocket.CLOSED ###");
                            OnClose(new SpeechWebSocketEventCloseArgs((int)status, description));
                            return;

                        case WebSocketMessageType.Binary:
                            // text = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
                            OnMessage(new SpeechWebSocketEventMessageArgs(buffer, text, SpeechWebSocketDataType.Binary));
                            break;

                        case WebSocketMessageType.Text:
                            SpeechWebSocketLogger.Log("### SpeechWebSocket.TEXT ###");
                            text = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
                            OnMessage(new SpeechWebSocketEventMessageArgs(buffer, text, SpeechWebSocketDataType.Text));
                            break;
                        }
                    }
                    //else
                    //{
                    //    OnClose(new SpeechWebSocketEventCloseArgs(1000));
                    //    return;
                    //}
                } while (result.EndOfMessage == false);
            }
        }
        public void Connect()
        {
            InitializeCancellationTokenSource();
            Task.Factory.StartNew(() =>
            {
                try
                {
                    var dateTime = DateTime.Now;
                    SpeechWebSocketLogger.Log("### SpeechWebSocket.CONNECT[{0}]: {1} ###", ClientWebSocket.State, UriBuilder.Uri);

                    if (ClientWebSocket.State == WebSocketState.None || ClientWebSocket.State == WebSocketState.Closed)
                    {
                        ClientWebSocket = new ClientWebSocket();
                        foreach (var item in RequestHeaders)
                        {
                            ClientWebSocket.Options.SetRequestHeader(item.Key, item.Value);
                        }

                        SendingTokenSource.Token.ThrowIfCancellationRequested();
                        var task = ClientWebSocket.ConnectAsync(UriBuilder.Uri, CancellationToken.None);
                        task.Wait();
                        SpeechWebSocketLogger.Log("### SpeechWebSocket.CONNECT: {0}ms ###", (DateTime.Now - dateTime).Milliseconds);

                        switch (task.Status)
                        {
                        case TaskStatus.RanToCompletion:
                            var receive = OnReceiving();
                            OnOpen(new SpeechWebSocketEventOpenArgs());
                            try
                            {
                                receive.Wait();
                            }
                            catch (AggregateException ex)
                            {
                                SpeechWebSocketLogger.Log("### SpeechWebSocket.RECEIVING EXCEPTIONS: {0} ###", ex.Message);
                                foreach (var v in ex.InnerExceptions)
                                {
                                    SpeechWebSocketLogger.Log("### SpeechWebSocket.RECEIVING MESSAGE: {0} ###", v.Message);
                                }
                            }
                            catch (ObjectDisposedException ex)
                            {
                                SpeechWebSocketLogger.Log("### SpeechWebSocket.RECEIVING EXCEPTION: {0} ###", ex.Message);
                            }

                            break;

                        default:
                            OnError(new SpeechWebSocketEventErrorArgs(task.Exception));
                            break;
                        }
                        return;
                    }
                    var closeTask = CloseAsync(WebSocketCloseStatus.Empty);
                    closeTask.Wait();
                    Connect();
                }
                catch (Exception ex)
                {
                    SpeechWebSocketLogger.Log("### SpeechWebSocket.EXCEPTION ###");

                    OnError(new SpeechWebSocketEventErrorArgs(ex));
                }
            });
        }