예제 #1
0
        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));
        }
예제 #2
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);
                }
            }
        }