Example #1
0
        public async Task SendAsync(VoiceOpCode opCode, object payload, RequestOptions options = null)
        {
            byte[] bytes = null;
            payload = new WebSocketMessage {
                Operation = (int)opCode, Payload = payload
            };
            if (payload != null)
            {
                bytes = Encoding.UTF8.GetBytes(SerializeJson(payload));
            }
            await _webSocketClient.SendAsync(bytes, 0, bytes.Length, true).ConfigureAwait(false);

            await _sentGatewayMessageEvent.InvokeAsync(opCode);
        }
Example #2
0
        private async Task ProcessMessageAsync(VoiceOpCode opCode, object payload)
        {
#if BENCHMARK
            Stopwatch stopwatch = Stopwatch.StartNew();
            try
            {
#endif
            try
            {
                switch (opCode)
                {
                case VoiceOpCode.Ready:
                {
                    await _audioLogger.DebugAsync("Received Ready").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <ReadyEvent>(_serializer);

                    _ssrc = data.SSRC;

                    if (!data.Modes.Contains(DiscordVoiceAPIClient.Mode))
                    {
                        throw new InvalidOperationException($"Discord does not support {DiscordVoiceAPIClient.Mode}");
                    }

                    _heartbeatTime = 0;
                    _heartbeatTask = RunHeartbeatAsync(data.HeartbeatInterval, _cancelToken.Token);

                    var entry = await Dns.GetHostEntryAsync(_url).ConfigureAwait(false);

                    ApiClient.SetUdpEndpoint(new IPEndPoint(entry.AddressList[0], data.Port));
                    await ApiClient.SendDiscoveryAsync(_ssrc).ConfigureAwait(false);
                }
                break;

                case VoiceOpCode.SessionDescription:
                {
                    await _audioLogger.DebugAsync("Received SessionDescription").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <SessionDescriptionEvent>(_serializer);

                    if (data.Mode != DiscordVoiceAPIClient.Mode)
                    {
                        throw new InvalidOperationException($"Discord selected an unexpected mode: {data.Mode}");
                    }

                    _secretKey = data.SecretKey;
                    await ApiClient.SendSetSpeaking(true).ConfigureAwait(false);

                    var _ = _connectTask.TrySetResultAsync(true);
                }
                break;

                case VoiceOpCode.HeartbeatAck:
                {
                    await _audioLogger.DebugAsync("Received HeartbeatAck").ConfigureAwait(false);

                    var heartbeatTime = _heartbeatTime;
                    if (heartbeatTime != 0)
                    {
                        int latency = (int)(Environment.TickCount - _heartbeatTime);
                        _heartbeatTime = 0;

                        int before = Latency;
                        Latency = latency;

                        await _latencyUpdatedEvent.InvokeAsync(before, latency).ConfigureAwait(false);
                    }
                }
                break;

                default:
                    await _audioLogger.WarningAsync($"Unknown OpCode ({opCode})").ConfigureAwait(false);

                    return;
                }
            }
            catch (Exception ex)
            {
                await _audioLogger.ErrorAsync($"Error handling {opCode}", ex).ConfigureAwait(false);

                return;
            }
#if BENCHMARK
        }

        finally
        {
            stopwatch.Stop();
            double millis = Math.Round(stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
            await _benchmarkLogger.DebugAsync($"{millis} ms").ConfigureAwait(false);
        }
#endif
        }
Example #3
0
        private async Task ProcessMessageAsync(VoiceOpCode opCode, object payload)
        {
            _lastMessageTime = Environment.TickCount;

            try
            {
                switch (opCode)
                {
                case VoiceOpCode.Hello:
                {
                    await _audioLogger.DebugAsync("Received Hello").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <HelloEvent>(_serializer);

                    _heartbeatInterval = data.HeartbeatInterval;
                }
                break;

                case VoiceOpCode.Ready:
                {
                    await _audioLogger.DebugAsync("Received Ready").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <ReadyEvent>(_serializer);

                    _ssrc = data.SSRC;

                    if (!data.Modes.Contains(DiscordVoiceAPIClient.Mode))
                    {
                        throw new InvalidOperationException($"Discord does not support {DiscordVoiceAPIClient.Mode}");
                    }

                    ApiClient.SetUdpEndpoint(data.Ip, data.Port);
                    await ApiClient.SendDiscoveryAsync(_ssrc).ConfigureAwait(false);


                    _heartbeatTask = RunHeartbeatAsync(_heartbeatInterval - 1000, _connection.CancelToken);         // reserve a delay time of network
                }
                break;

                case VoiceOpCode.SessionDescription:
                {
                    await _audioLogger.DebugAsync("Received SessionDescription").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <SessionDescriptionEvent>(_serializer);

                    if (data.Mode != DiscordVoiceAPIClient.Mode)
                    {
                        throw new InvalidOperationException($"Discord selected an unexpected mode: {data.Mode}");
                    }

                    SecretKey   = data.SecretKey;
                    _isSpeaking = false;
                    await ApiClient.SendSetSpeaking(false).ConfigureAwait(false);

                    _keepaliveTask = RunKeepaliveAsync(5000, _connection.CancelToken);

                    var _ = _connection.CompleteAsync();
                }
                break;

                case VoiceOpCode.HeartbeatAck:
                {
                    await _audioLogger.DebugAsync("Received HeartbeatAck").ConfigureAwait(false);

                    if (_heartbeatTimes.TryDequeue(out long time))
                    {
                        int latency = (int)(Environment.TickCount - time);
                        int before  = Latency;
                        Latency = latency;

                        await _latencyUpdatedEvent.InvokeAsync(before, latency).ConfigureAwait(false);
                    }
                }
                break;

                case VoiceOpCode.Speaking:
                {
                    await _audioLogger.DebugAsync("Received Speaking").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <SpeakingEvent>(_serializer);
                    _ssrcMap[data.Ssrc] = data.UserId;         //TODO: Memory Leak: SSRCs are never cleaned up

                    await _speakingUpdatedEvent.InvokeAsync(data.UserId, data.Speaking);
                }
                break;

                default:
                    await _audioLogger.WarningAsync($"Unknown OpCode ({opCode})").ConfigureAwait(false);

                    return;
                }
            }
            catch (Exception ex)
            {
                await _audioLogger.ErrorAsync($"Error handling {opCode}", ex).ConfigureAwait(false);

                return;
            }
        }
Example #4
0
        private async Task ProcessMessageAsync(VoiceOpCode opCode, object payload)
        {
            try
            {
                switch (opCode)
                {
                case VoiceOpCode.Ready:
                {
                    await _audioLogger.DebugAsync("Received Ready").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <ReadyEvent>(_serializer);

                    _ssrc = data.SSRC;

                    if (!data.Modes.Contains(DiscordVoiceAPIClient.Mode))
                    {
                        throw new InvalidOperationException($"Discord does not support {DiscordVoiceAPIClient.Mode}");
                    }

                    _heartbeatTime = 0;
                    _heartbeatTask = RunHeartbeatAsync(data.HeartbeatInterval, _cancelTokenSource.Token);

                    ApiClient.SetUdpEndpoint(_url, data.Port);
                    await ApiClient.SendDiscoveryAsync(_ssrc).ConfigureAwait(false);
                }
                break;

                case VoiceOpCode.SessionDescription:
                {
                    await _audioLogger.DebugAsync("Received SessionDescription").ConfigureAwait(false);

                    var data = (payload as JToken).ToObject <SessionDescriptionEvent>(_serializer);

                    if (data.Mode != DiscordVoiceAPIClient.Mode)
                    {
                        throw new InvalidOperationException($"Discord selected an unexpected mode: {data.Mode}");
                    }

                    _secretKey = data.SecretKey;
                    await ApiClient.SendSetSpeaking(true).ConfigureAwait(false);

                    var _ = _connectTask.TrySetResultAsync(true);
                }
                break;

                case VoiceOpCode.HeartbeatAck:
                {
                    await _audioLogger.DebugAsync("Received HeartbeatAck").ConfigureAwait(false);

                    var heartbeatTime = _heartbeatTime;
                    if (heartbeatTime != 0)
                    {
                        int latency = (int)(Environment.TickCount - _heartbeatTime);
                        _heartbeatTime = 0;

                        int before = Latency;
                        Latency = latency;

                        await _latencyUpdatedEvent.InvokeAsync(before, latency).ConfigureAwait(false);
                    }
                }
                break;

                default:
                    await _audioLogger.WarningAsync($"Unknown OpCode ({opCode})").ConfigureAwait(false);

                    return;
                }
            }
            catch (Exception ex)
            {
                await _audioLogger.ErrorAsync($"Error handling {opCode}", ex).ConfigureAwait(false);

                return;
            }
        }