Esempio n. 1
0
        /// <summary>
        /// Encodes, encrypts, and sends the provided PCM data to the connected voice channel.
        /// </summary>
        /// <param name="pcmData">PCM data to encode, encrypt, and send.</param>
        /// <param name="blockSize">Millisecond length of the PCM data.</param>
        /// <param name="bitRate">Bitrate of the PCM data.</param>
        /// <returns>Task representing the sending operation.</returns>
        public async Task SendAsync(byte[] pcmData, int blockSize, int bitRate = 16)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The connection is not initialized");
            }

            await PlaybackSemaphore.WaitAsync().ConfigureAwait(false);

            var rtp = Rtp.Encode(Sequence, Timestamp, SSRC);

            var dat = Opus.Encode(pcmData, 0, pcmData.Length, bitRate);

            dat = Sodium.Encode(dat, Rtp.MakeNonce(rtp), Key);
            dat = Rtp.Encode(rtp, dat);

            await SendSpeakingAsync(true).ConfigureAwait(false);

            // works:
            //await UdpClient.SendAsync(dat, dat.Length).ConfigureAwait(false);
            await UdpClient.SendNativelyAsync(dat, dat.Length).ConfigureAwait(false);

            Sequence++;
            Timestamp += 48 * (uint)blockSize;

            PlaybackSemaphore.Release();
        }
        /// <summary>
        /// Encodes, encrypts, and sends the provided PCM data to the connected voice channel.
        /// </summary>
        /// <param name="pcmData">PCM data to encode, encrypt, and send.</param>
        /// <param name="blockSize">Millisecond length of the PCM data.</param>
        /// <param name="bitRate">Bitrate of the PCM data.</param>
        /// <returns>Task representing the sending operation.</returns>
        public async Task SendAsync(byte[] pcmData, int blockSize, int bitRate = 16)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The connection is not initialized");
            }

            await PlaybackSemaphore.WaitAsync().ConfigureAwait(false);

            var rtp = Rtp.Encode(Sequence, Timestamp, SSRC);

            var dat = Opus.Encode(pcmData, 0, pcmData.Length, bitRate);

            dat = Sodium.Encode(dat, Rtp.MakeNonce(rtp), Key);
            dat = Rtp.Encode(rtp, dat);

            if (SynchronizerTicks == 0)
            {
                SynchronizerTicks      = Stopwatch.GetTimestamp();
                SynchronizerResolution = (Stopwatch.Frequency * 0.02);
                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);
            }
            else
            {
                // 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 cts = Math.Max(Stopwatch.GetTimestamp() - SynchronizerTicks, 0);
                if (cts < SynchronizerResolution)
                {
                    await Task.Delay(TimeSpan.FromTicks((long)((SynchronizerResolution - cts) * TickResolution))).ConfigureAwait(false);
                }

                SynchronizerTicks += SynchronizerResolution;
            }

            await SendSpeakingAsync(true).ConfigureAwait(false);

            await UdpClient.SendAsync(dat, dat.Length).ConfigureAwait(false);

            Sequence++;
            Timestamp += 48 * (uint)blockSize;

            PlaybackSemaphore.Release();
        }