Esempio n. 1
0
        // todo 3.2 direct opus streams
        public int SendPcmFrame(VoiceGateway gw, Span <byte> data, int offset, int count)
        {
            var secretKey = gw.SecretKey;

            if (secretKey.Length == 0)
            {
                return((int)SendPcmError.SecretKeyUnavailable);
            }

            // encode using opus
            var encodeOutput = _arrayPool.Rent(LibOpusEncoder.MaxData);

            try
            {
                var encodeOutputLength = Encode(data, encodeOutput);
                return(SendOpusFrame(gw, encodeOutput, 0, encodeOutputLength));
            }
            finally
            {
                _arrayPool.Return(encodeOutput);
            }
        }
Esempio n. 2
0
        public int SendOpusFrame(VoiceGateway gw, byte[] data, int offset, int count)
        {
            var secretKey = gw.SecretKey;

            if (secretKey is null)
            {
                return((int)SendPcmError.SecretKeyUnavailable);
            }

            // form RTP header
            var headerLength = 1    // version + flags
                               + 1  // payload type
                               + 2  // sequence
                               + 4  // timestamp
                               + 4; // ssrc

            var header = new byte[headerLength];

            header[0] = 0x80; // version + flags
            header[1] = 0x78; // payload type

            // get byte values for header data
            var seqBytes       = BitConverter.GetBytes(gw.Sequence);      // 2
            var nonceBytes     = BitConverter.GetBytes(gw.NonceSequence); // 2
            var timestampBytes = BitConverter.GetBytes(gw.Timestamp);     // 4
            var ssrcBytes      = BitConverter.GetBytes(gw.Ssrc);          // 4

            gw.Timestamp += (uint)FrameSizePerChannel;
            gw.Sequence++;
            gw.NonceSequence++;

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(seqBytes);
                Array.Reverse(nonceBytes);
                Array.Reverse(timestampBytes);
                Array.Reverse(ssrcBytes);
            }

            // copy headers
            Buffer.BlockCopy(seqBytes, 0, header, 2, 2);
            Buffer.BlockCopy(timestampBytes, 0, header, 4, 4);
            Buffer.BlockCopy(ssrcBytes, 0, header, 8, 4);

            //// encryption part
            //// create a byte array where to store the encrypted data
            //// it has to be inputLength + crypto_secretbox_MACBYTES (constant with value 16)
            var encryptedBytes = new byte[count + 16];

            //// form nonce with header + 12 empty bytes
            //var nonce = new byte[24];
            //Buffer.BlockCopy(rtpHeader, 0, nonce, 0, rtpHeader.Length);

            var nonce = new byte[4];

            Buffer.BlockCopy(seqBytes, 0, nonce, 2, 2);

            Sodium.Encrypt(data, 0, count, encryptedBytes, 0, nonce, secretKey);

            var rtpDataLength = headerLength + encryptedBytes.Length + nonce.Length;
            var rtpData       = _arrayPool.Rent(rtpDataLength);

            try
            {
                //copy headers
                Buffer.BlockCopy(header, 0, rtpData, 0, header.Length);
                //copy audio data
                Buffer.BlockCopy(encryptedBytes, 0, rtpData, header.Length, encryptedBytes.Length);
                Buffer.BlockCopy(nonce, 0, rtpData, rtpDataLength - 4, 4);

                gw.SendRtpData(rtpData, rtpDataLength);
                // todo 3.2 When there's a break in the sent data,
                // the packet transmission shouldn't simply stop.
                // Instead, send five frames of silence (0xF8, 0xFF, 0xFE)
                // before stopping to avoid unintended Opus interpolation
                // with subsequent transmissions.

                return(rtpDataLength);
            }
            finally
            {
                _arrayPool.Return(rtpData);
            }
        }