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; } }
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); }
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); }
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>(); } } } }
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>(); } } } }
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; } }
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; } }
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; } }