private Task Stage2(VoiceSessionDescriptionPayload voiceSessionDescription) { SelectedEncryptionMode = Sodium.SupportedModes[voiceSessionDescription.Mode.ToLowerInvariant()]; Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Discord updated encryption mode: {SelectedEncryptionMode}", DateTime.Now); // start keepalive KeepaliveTokenSource = new CancellationTokenSource(); KeepaliveTask = KeepaliveAsync(); // send 3 packets of silence to get things going var nullpcm = new byte[AudioFormat.CalculateSampleSize(20)]; for (var i = 0; i < 3; i++) { var nullopus = new byte[nullpcm.Length]; var nullopusmem = nullopus.AsMemory(); PreparePacket(nullpcm, ref nullopusmem); EnqueuePacket(new VoicePacket(nullopusmem, 20)); } IsInitialized = true; ReadyWait.SetResult(true); return(Task.Delay(0)); }
private async Task VoiceSenderTask() { var token = SenderToken; var client = UdpClient; var queue = PacketQueue; var synchronizerTicks = (double)Stopwatch.GetTimestamp(); var synchronizerResolution = (Stopwatch.Frequency * 0.005); var tickResolution = 10_000_000.0 / Stopwatch.Frequency; Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Timer accuracy: {Stopwatch.Frequency.ToString("#,##0", CultureInfo.InvariantCulture)}/{synchronizerResolution.ToString(CultureInfo.InvariantCulture)} (high resolution? {Stopwatch.IsHighResolution})", DateTime.Now); while (!token.IsCancellationRequested) { var hasPacket = queue.TryDequeue(out var packet); byte[] packetArray = null; if (hasPacket) { if (PlayingWait == null || PlayingWait.Task.IsCompleted) { PlayingWait = new TaskCompletionSource <bool>(); } packetArray = packet.Bytes.ToArray(); } // Provided by Laura#0090 (214796473689178133); this is Python, but adaptable: // // delay = max(0, self.delay + ((start_time + self.delay * loops) + - time.time())) // // self.delay // sample size // start_time // time since streaming started // loops // number of samples sent // time.time() // DateTime.Now var durationModifier = hasPacket ? packet.MillisecondDuration / 5 : 4; var cts = Math.Max(Stopwatch.GetTimestamp() - synchronizerTicks, 0); if (cts < synchronizerResolution * durationModifier) { await Task.Delay(TimeSpan.FromTicks((long)(((synchronizerResolution * durationModifier) - cts) * tickResolution))).ConfigureAwait(false); } synchronizerTicks += synchronizerResolution * durationModifier; if (!hasPacket) { continue; } SendSpeaking(true); await UdpClient.SendAsync(packetArray, packetArray.Length).ConfigureAwait(false); if (!packet.IsSilence && queue.Count == 0) { var nullpcm = new byte[AudioFormat.CalculateSampleSize(20)]; for (var i = 0; i < 3; i++) { var nullpacket = new byte[nullpcm.Length]; var nullpacketmem = nullpacket.AsMemory(); PreparePacket(nullpcm, ref nullpacketmem); EnqueuePacket(new VoicePacket(nullpacketmem, 20, true)); } } else if (queue.Count == 0) { SendSpeaking(false); PlayingWait?.SetResult(true); } } }