private async Task HandleDispatch(JObject jo)
        {
            var opc = (int)jo["op"];
            var opp = jo["d"] as JObject;

            switch (opc)
            {
            case 2:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP2 received", DateTime.Now);
                var vrp = opp.ToObject <VoiceReadyPayload>();
                this.SSRC = vrp.SSRC;
                this.ConnectionEndpoint = new DnsEndPoint(this.ConnectionEndpoint.Host, vrp.Port);
                this.HeartbeatInterval  = vrp.HeartbeatInterval;
                await this.Stage1();

                break;

            case 3:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP3 received", DateTime.Now);
                var dt = DateTime.Now;
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Received voice heartbeat ACK, ping {(dt - this.LastHeartbeat).TotalMilliseconds.ToString("#,###")}ms", dt);
                this.LastHeartbeat = dt;
                break;

            case 4:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP4 received", DateTime.Now);
                var vsd = opp.ToObject <VoiceSessionDescriptionPayload>();
                this.Key = vsd.SecretKey;
                await this.Stage2();

                break;

            case 5:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP5 received", DateTime.Now);
                var spd = opp.ToObject <VoiceSpeakingPayload>();
                var spk = new UserSpeakingEventArgs
                {
                    Speaking = spd.Speaking,
                    SSRC     = spd.SSRC.Value,
                    UserID   = spd.UserId.Value
                };
                await this._user_speaking.InvokeAsync(spk);

                break;

            default:
                this.Discord.DebugLogger.LogMessage(LogLevel.Warning, "VoiceNext", $"Unknown opcode received: {opc}", DateTime.Now);
                break;
            }
        }
Esempio n. 2
0
        private Task OnUserSpeaking(UserSpeakingEventArgs e)
        {
            if (this._ssrc_map.ContainsKey(e.SSRC))
            {
                return(Task.CompletedTask);
            }

            if (e.User == null)
            {
                return(Task.CompletedTask);
            }

            this._ssrc_map[e.SSRC] = e.User.Id;
            return(Task.CompletedTask);
        }
Esempio n. 3
0
        private Task OnUserSpeaking(VoiceNextConnection vnc, UserSpeakingEventArgs e)
        {
            if (this._ssrcMap.ContainsKey(e.SSRC))
            {
                return(Task.CompletedTask);
            }

            if (e.User == null)
            {
                return(Task.CompletedTask);
            }

            this._ssrcMap[e.SSRC] = e.User.Id;
            return(Task.CompletedTask);
        }
Esempio n. 4
0
        private async Task OnUserSpeaking(UserSpeakingEventArgs args, CommandContext ctx)
        {
            if (args.User != null)
            {
                if (args.Speaking == false)
                {
                    var audio = args.Client.GetCommandsNext().Services.GetService <IProvideAudioState>();

                    await Assist(ctx);

                    if (audio.IsSpeechPreservedForUser.ContainsKey(args.User.Id) && !args.Client.GetCommandsNext().Services.GetService <IProvideAudioState>().IsSpeechPreservedForUser[args.User.Id])
                    {
                        audio.SpeechFromUser[args.User.Id] = new ConcurrentQueue <byte>();
                    }
                }
            }
        }
Esempio n. 5
0
        private async Task OnUserSpeaking(UserSpeakingEventArgs args, DiscordChannel responseChannel)
        {
            if (args.User != null)
            {
                if (args.Speaking == false)
                {
                    var audio = args.Client.GetCommandsNext().Services.GetService <IProvideAudioState>();

                    var buff = audio.SpeechFromUser[args.User.Id].ToArray();

                    byte[] resampled = AudioConverter.Resample(buff, 48000, 16000, 1, 1);

                    var text = await new AzureSpeechModule(KarvisConfiguration, args.Client.DebugLogger).AudioToTextAsync(resampled);

                    await args.Client.SendMessageAsync(responseChannel, args.User.Username + ", I think I heard you say: " + text);

                    if (audio.IsSpeechPreservedForUser.ContainsKey(args.User.Id) && !args.Client.GetCommandsNext().Services.GetService <IProvideAudioState>().IsSpeechPreservedForUser[args.User.Id])
                    {
                        audio.SpeechFromUser[args.User.Id] = new ConcurrentQueue <byte>();
                    }
                }
            }
        }
Esempio n. 6
0
        private async Task HandleDispatch(JObject jo)
        {
            var opc = (int)jo["op"];
            var opp = jo["d"] as JObject;

            switch (opc)
            {
            case 2:     // READY
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received READY (OP2)");
                var vrp = opp.ToObject <VoiceReadyPayload>();
                this.SSRC        = vrp.SSRC;
                this.UdpEndpoint = new ConnectionEndpoint(vrp.Address, vrp.Port);
                // this is not the valid interval
                // oh, discord
                //this.HeartbeatInterval = vrp.HeartbeatInterval;
                this.HeartbeatTask = Task.Run(this.HeartbeatAsync);
                await this.Stage1(vrp).ConfigureAwait(false);

                break;

            case 4:     // SESSION_DESCRIPTION
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received SESSION_DESCRIPTION (OP4)");
                var vsd = opp.ToObject <VoiceSessionDescriptionPayload>();
                this.Key    = vsd.SecretKey;
                this.Sodium = new Sodium(this.Key.AsMemory());
                await this.Stage2(vsd).ConfigureAwait(false);

                break;

            case 5:     // SPEAKING
                // Don't spam OP5
                // No longer spam, Discord supposedly doesn't send many of these
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received SPEAKING (OP5)");
                var spd = opp.ToObject <VoiceSpeakingPayload>();
                var foundUserInCache = this.Discord.TryGetCachedUserInternal(spd.UserId.Value, out var resolvedUser);
                var spk = new UserSpeakingEventArgs
                {
                    Speaking = spd.Speaking,
                    SSRC     = spd.SSRC.Value,
                    User     = resolvedUser,
                };

                if (foundUserInCache && this.TransmittingSSRCs.TryGetValue(spk.SSRC, out var txssrc5) && txssrc5.Id == 0)
                {
                    txssrc5.User = spk.User;
                }
                else
                {
                    var opus = this.Opus.CreateDecoder();
                    var vtx  = new AudioSender(spk.SSRC, opus)
                    {
                        User = await this.Discord.GetUserAsync(spd.UserId.Value).ConfigureAwait(false)
                    };

                    if (!this.TransmittingSSRCs.TryAdd(spk.SSRC, vtx))
                    {
                        this.Opus.DestroyDecoder(opus);
                    }
                }

                await this._userSpeaking.InvokeAsync(this, spk).ConfigureAwait(false);

                break;

            case 6:     // HEARTBEAT ACK
                var dt   = DateTime.Now;
                var ping = (int)(dt - this.LastHeartbeat).TotalMilliseconds;
                Volatile.Write(ref this._wsPing, ping);
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received HEARTBEAT_ACK (OP6, {0}ms)", ping);
                this.LastHeartbeat = dt;
                break;

            case 8:     // HELLO
                // this sends a heartbeat interval that we need to use for heartbeating
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received HELLO (OP8)");
                this.HeartbeatInterval = opp["heartbeat_interval"].ToObject <int>();
                break;

            case 9:     // RESUMED
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received RESUMED (OP9)");
                this.HeartbeatTask = Task.Run(this.HeartbeatAsync);
                break;

            case 12:     // CLIENT_CONNECTED
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received CLIENT_CONNECTED (OP12)");
                var ujpd = opp.ToObject <VoiceUserJoinPayload>();
                var usrj = await this.Discord.GetUserAsync(ujpd.UserId).ConfigureAwait(false);

                {
                    var opus = this.Opus.CreateDecoder();
                    var vtx  = new AudioSender(ujpd.SSRC, opus)
                    {
                        User = usrj
                    };

                    if (!this.TransmittingSSRCs.TryAdd(vtx.SSRC, vtx))
                    {
                        this.Opus.DestroyDecoder(opus);
                    }
                }

                await this._userJoined.InvokeAsync(this, new VoiceUserJoinEventArgs { User = usrj, SSRC = ujpd.SSRC }).ConfigureAwait(false);

                break;

            case 13:     // CLIENT_DISCONNECTED
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received CLIENT_DISCONNECTED (OP13)");
                var ulpd   = opp.ToObject <VoiceUserLeavePayload>();
                var txssrc = this.TransmittingSSRCs.FirstOrDefault(x => x.Value.Id == ulpd.UserId);
                if (this.TransmittingSSRCs.ContainsKey(txssrc.Key))
                {
                    this.TransmittingSSRCs.TryRemove(txssrc.Key, out var txssrc13);
                    this.Opus.DestroyDecoder(txssrc13.Decoder);
                }

                var usrl = await this.Discord.GetUserAsync(ulpd.UserId).ConfigureAwait(false);

                await this._userLeft.InvokeAsync(this, new VoiceUserLeaveEventArgs
                {
                    User = usrl,
                    SSRC = txssrc.Key
                }).ConfigureAwait(false);

                break;

            default:
                this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceDispatch, "Received unknown voice opcode (OP{0})", opc);
                break;
            }
        }
Esempio n. 7
0
        private async Task HandleDispatch(JObject jo)
        {
            var opc = (int)jo["op"];
            var opp = jo["d"] as JObject;

            switch (opc)
            {
            case 2:     // READY
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP2 received", DateTime.Now);
                var vrp = opp.ToObject <VoiceReadyPayload>();
                this.SSRC = vrp.SSRC;
                this.ConnectionEndpoint = new ConnectionEndpoint(this.ConnectionEndpoint.Hostname, vrp.Port);
                // this is not the valid interval
                // oh, discord
                //this.HeartbeatInterval = vrp.HeartbeatInterval;
                this.HeartbeatTask = Task.Run(this.HeartbeatAsync);
                await this.Stage1(vrp).ConfigureAwait(false);

                break;

            case 4:     // SESSION_DESCRIPTION
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP4 received", DateTime.Now);
                var vsd = opp.ToObject <VoiceSessionDescriptionPayload>();
                this.Key    = vsd.SecretKey;
                this.Sodium = new Sodium(this.Key.AsMemory());
                await this.Stage2(vsd).ConfigureAwait(false);

                break;

            case 5:     // SPEAKING
                // Don't spam OP5
                //this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP5 received", DateTime.Now);
                var spd = opp.ToObject <VoiceSpeakingPayload>();
                var spk = new UserSpeakingEventArgs(this.Discord)
                {
                    Speaking = spd.Speaking,
                    SSRC     = spd.SSRC.Value,
                    User     = this.Discord.InternalGetCachedUser(spd.UserId.Value)
                };

#if !NETSTANDARD1_1
                if (spk.User != null && this.TransmittingSSRCs.TryGetValue(spk.SSRC, out var txssrc5) && txssrc5.Id == 0)
                {
                    txssrc5.User = spk.User;
                }
                else
                {
                    var opus = this.Opus.CreateDecoder();
                    var vtx  = new AudioSender(spk.SSRC, opus)
                    {
                        User = await this.Discord.GetUserAsync(spd.UserId.Value).ConfigureAwait(false)
                    };

                    if (!this.TransmittingSSRCs.TryAdd(spk.SSRC, vtx))
                    {
                        this.Opus.DestroyDecoder(opus);
                    }
                }
#endif

                await this._userSpeaking.InvokeAsync(spk).ConfigureAwait(false);

                break;

            case 6:     // HEARTBEAT ACK
                var dt   = DateTime.Now;
                var ping = (int)(dt - this.LastHeartbeat).TotalMilliseconds;
                Volatile.Write(ref this._wsPing, ping);
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Received voice heartbeat ACK, ping {ping.ToString("#,##0", CultureInfo.InvariantCulture)}ms", dt);
                this.LastHeartbeat = dt;
                break;

            case 8:     // HELLO
                // this sends a heartbeat interval that we need to use for heartbeating
                this.HeartbeatInterval = opp["heartbeat_interval"].ToObject <int>();
                break;

            case 9:     // RESUMED
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP9 received", DateTime.Now);
                this.HeartbeatTask = Task.Run(this.HeartbeatAsync);
                break;

            case 12:     // CLIENT_CONNECTED
                var ujpd = opp.ToObject <VoiceUserJoinPayload>();
                var usrj = await this.Discord.GetUserAsync(ujpd.UserId).ConfigureAwait(false);

#if !NETSTANDARD1_1
                {
                    var opus = this.Opus.CreateDecoder();
                    var vtx  = new AudioSender(ujpd.SSRC, opus)
                    {
                        User = usrj
                    };

                    if (!this.TransmittingSSRCs.TryAdd(vtx.SSRC, vtx))
                    {
                        this.Opus.DestroyDecoder(opus);
                    }
                }
#endif

                await this._userJoined.InvokeAsync(new VoiceUserJoinEventArgs(this.Discord) { User = usrj, SSRC = ujpd.SSRC }).ConfigureAwait(false);

                break;

            case 13:     // CLIENT_DISCONNECTED
                var ulpd = opp.ToObject <VoiceUserLeavePayload>();

#if !NETSTANDARD1_1
                var txssrc = this.TransmittingSSRCs.FirstOrDefault(x => x.Value.Id == ulpd.UserId);
                if (this.TransmittingSSRCs.ContainsKey(txssrc.Key))
                {
                    this.TransmittingSSRCs.TryRemove(txssrc.Key, out var txssrc13);
                    this.Opus.DestroyDecoder(txssrc13.Decoder);
                }
#endif

                var usrl = await this.Discord.GetUserAsync(ulpd.UserId).ConfigureAwait(false);

                await this._userLeft.InvokeAsync(new VoiceUserLeaveEventArgs(this.Discord)
                {
                    User = usrl
#if !NETSTANDARD1_1
                    , SSRC = txssrc.Key
#endif
                }).ConfigureAwait(false);

                break;

            default:
                this.Discord.DebugLogger.LogMessage(LogLevel.Warning, "VoiceNext", $"Unknown opcode received: {opc.ToString(CultureInfo.InvariantCulture)}", DateTime.Now);
                break;
            }
        }
        private async Task HandleDispatch(JObject jo)
        {
            var opc = (int)jo["op"];
            var opp = jo["d"] as JObject;

            switch (opc)
            {
            case 2:
                Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP2 received", DateTime.Now);
                var vrp = opp.ToObject <VoiceReadyPayload>();
                SSRC = vrp.SSRC;
                ConnectionEndpoint = new ConnectionEndpoint {
                    Hostname = ConnectionEndpoint.Hostname, Port = vrp.Port
                };
                HeartbeatInterval = vrp.HeartbeatInterval;
                HeartbeatTask     = Task.Run(Heartbeat);
                await Stage1().ConfigureAwait(false);

                break;

            case 4:
                Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP4 received", DateTime.Now);
                var vsd = opp.ToObject <VoiceSessionDescriptionPayload>();
                Key = vsd.SecretKey;
                await Stage2().ConfigureAwait(false);

                break;

            case 5:
                // Don't spam OP5
                //this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP5 received", DateTime.Now);
                var spd = opp.ToObject <VoiceSpeakingPayload>();
                var spk = new UserSpeakingEventArgs(Discord)
                {
                    Speaking = spd.Speaking,
                    SSRC     = spd.SSRC.Value,
                    User     = Discord.InternalGetCachedUser(spd.UserId.Value)
                };
                if (!SSRCMap.ContainsKey(spk.SSRC))
                {
                    SSRCMap.AddOrUpdate(spk.SSRC, spk.User.Id, (k, v) => spk.User.Id);
                }
                await _userSpeaking.InvokeAsync(spk).ConfigureAwait(false);

                break;

            case 6:
                var dt   = DateTime.Now;
                var ping = (int)(dt - LastHeartbeat).TotalMilliseconds;
                Volatile.Write(ref _ping, ping);
                Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Received voice heartbeat ACK, ping {ping.ToString("#,##0", CultureInfo.InvariantCulture)}ms", dt);
                LastHeartbeat = dt;
                break;

            case 8:
                // this sends a heartbeat interval that appears to be consistent with regular GW hello
                // however opcodes don't match (8 != 10)
                // so we suppress it so that users are not alerted
                // HELLO
                break;

            case 9:
                Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP9 received", DateTime.Now);
                HeartbeatTask = Task.Run(Heartbeat);
                break;

            case 13:
                var ulpd = opp.ToObject <VoiceUserLeavePayload>();
                var usr  = await Discord.GetUserAsync(ulpd.UserId).ConfigureAwait(false);

                var ssrc = SSRCMap.FirstOrDefault(x => x.Value == ulpd.UserId);
                if (ssrc.Value != 0)
                {
                    SSRCMap.TryRemove(ssrc.Key, out _);
                }
                Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"User '{usr.Username}#{usr.Discriminator}' ({ulpd.UserId.ToString(CultureInfo.InvariantCulture)}) left voice chat in '{Channel.Guild.Name}' ({Channel.Guild.Id.ToString(CultureInfo.InvariantCulture)})", DateTime.Now);
                await _userLeft.InvokeAsync(new VoiceUserLeaveEventArgs(Discord) { User = usr }).ConfigureAwait(false);

                break;

            default:
                Discord.DebugLogger.LogMessage(LogLevel.Warning, "VoiceNext", $"Unknown opcode received: {opc.ToString(CultureInfo.InvariantCulture)}", DateTime.Now);
                break;
            }
        }
Esempio n. 9
0
        private async Task HandleDispatch(JObject jo)
        {
            var opc = (int)jo["op"];
            var opp = jo["d"] as JObject;

            switch (opc)
            {
            case 2:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP2 received", DateTime.Now);
                var vrp = opp.ToObject <VoiceReadyPayload>();
                this.SSRC = vrp.SSRC;
                this.ConnectionEndpoint = new ConnectionEndpoint {
                    Hostname = this.ConnectionEndpoint.Hostname, Port = vrp.Port
                };
                this.HeartbeatInterval = vrp.HeartbeatInterval;
                await this.Stage1();

                break;

            case 4:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP4 received", DateTime.Now);
                var vsd = opp.ToObject <VoiceSessionDescriptionPayload>();
                this.Key = vsd.SecretKey;
                await this.Stage2();

                break;

            case 5:
                // Don't spam OP5
                //this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP5 received", DateTime.Now);
                var spd = opp.ToObject <VoiceSpeakingPayload>();
                var spk = new UserSpeakingEventArgs(this.Discord)
                {
                    Speaking = spd.Speaking,
                    SSRC     = spd.SSRC.Value,
                    User     = this.Discord.InternalGetCachedUser(spd.UserId.Value)
                };
                if (!this.SSRCMap.ContainsKey(spk.SSRC))
                {
                    this.SSRCMap.AddOrUpdate(spk.SSRC, spk.User.Id, (k, v) => spk.User.Id);
                }
                await this._user_speaking.InvokeAsync(spk);

                break;

            case 3:
            case 6:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP3 or OP6 received", DateTime.Now);
                var dt   = DateTime.Now;
                var ping = (int)(dt - this.LastHeartbeat).TotalMilliseconds;
                Volatile.Write(ref this._ping, ping);
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Received voice heartbeat ACK, ping {ping.ToString("#,###", CultureInfo.InvariantCulture)}ms", dt);
                this.LastHeartbeat = dt;
                break;

            case 8:
                // this sends a heartbeat interval that appears to be consistent with regular GW hello
                // however opcodes don't match (8 != 10)
                // so we suppress it so that users are not alerted
                // HELLO
                break;

            case 9:
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "OP9 received, starting new session", DateTime.Now);
                this.Resume = false;
                await this.StartAsync();

                break;

            default:
                this.Discord.DebugLogger.LogMessage(LogLevel.Warning, "VoiceNext", $"Unknown opcode received: {opc.ToString(CultureInfo.InvariantCulture)}", DateTime.Now);
                break;
            }
        }