Пример #1
0
        public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            //Assume threadsafe
            while (count > 0)
            {
                if (_partialFramePos == 0 && count >= OpusConverter.FrameBytes)
                {
                    //We have enough data and no partial frames. Pass the buffer directly to the encoder
                    int encFrameSize = _encoder.EncodeFrame(buffer, offset, _buffer, 0);
                    await _next.WriteAsync(_buffer, 0, encFrameSize, cancellationToken).ConfigureAwait(false);

                    offset += OpusConverter.FrameBytes;
                    count  -= OpusConverter.FrameBytes;
                }
                else if (_partialFramePos + count >= OpusConverter.FrameBytes)
                {
                    //We have enough data to complete a previous partial frame.
                    int partialSize = OpusConverter.FrameBytes - _partialFramePos;
                    Buffer.BlockCopy(buffer, offset, _buffer, _partialFramePos, partialSize);
                    int encFrameSize = _encoder.EncodeFrame(_buffer, 0, _buffer, 0);
                    await _next.WriteAsync(_buffer, 0, encFrameSize, cancellationToken).ConfigureAwait(false);

                    offset          += partialSize;
                    count           -= partialSize;
                    _partialFramePos = 0;
                }
                else
                {
                    //Not enough data to build a complete frame, store this part for later
                    Buffer.BlockCopy(buffer, offset, _buffer, _partialFramePos, count);
                    _partialFramePos += count;
                    break;
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Enqueues audio to be sent through the UDP client.
        /// </summary>
        /// <param name="voice">PCM audio data.</param>
        public void SendVoice(byte[] voice)
        {
            byte[] opusAudio     = new byte[voice.Length + 4];
            int    encodedLength = mainOpusEncoder.EncodeFrame(voice, 0, opusAudio);

            byte[] len = BitConverter.GetBytes(encodedLength);
            opusAudio[voice.Length]     = len[0];
            opusAudio[voice.Length + 1] = len[1];
            opusAudio[voice.Length + 2] = len[2];
            opusAudio[voice.Length + 3] = len[3];

            voiceToSend.Enqueue(opusAudio);
        }
Пример #3
0
		public void SendPCMFrame(byte[] data, int count)
		{
			if (count != _encoder.FrameSize)
				throw new InvalidOperationException($"Invalid frame size. Got {count}, expected {_encoder.FrameSize}.");

			lock (_encoder)
			{
				byte[] payload = new byte[4000];
				int encodedLength = _encoder.EncodeFrame(data, payload);

				if (_mode == "xsalsa20_poly1305")
				{
					//TODO: Encode
				}

				lock (_sendQueue)
					_sendQueue.Enqueue(new Packet(payload, encodedLength));
			}
		}
Пример #4
0
        public byte[] Encode()
        {
            int ms         = 20;
            int channels   = 2;
            int sampleRate = 48000;

            int blockSize = 48 * 2 * channels * ms; //the size per each frame to encode

            byte[] buffer    = new byte[blockSize]; //a nicely sized pcm buffer to work with.
            var    outFormat = new WaveFormat(sampleRate, 16, channels);

            if (__filename.EndsWith(".mp3"))
            {
                using (var mp3Reader = new Mp3FileReader(__filename))
                {
                    using (var resampler = new WaveFormatConversionStream(outFormat, mp3Reader))
                    {
                        int byteCount;
                        using (BinaryWriter bw = new BinaryWriter(new MemoryStream()))
                        {
                            while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0)
                            {
                                //now to encode
                                byte[] opusOutput  = new byte[buffer.Length]; //extra bytes but that's okay
                                int    opusEncoded = encoder.EncodeFrame(buffer, 0, opusOutput);
                                bw.Write((ushort)opusEncoded);
                                bw.Write(opusOutput, 0, opusEncoded);
                            }
                            MemoryStream baseStream = bw.BaseStream as MemoryStream;
                            return(baseStream.ToArray());
                        }
                    }
                }
            }
            return(null);
        }
Пример #5
0
        private async Task SendVoiceAsync(CancellationToken cancelToken)
        {
            try
            {
                while (!cancelToken.IsCancellationRequested && State != ConnectionState.Connected)
                {
                    await Task.Delay(1).ConfigureAwait(false);
                }

                if (cancelToken.IsCancellationRequested)
                {
                    return;
                }

                byte[]    frame        = new byte[_encoder.FrameSize];
                byte[]    encodedFrame = new byte[MaxOpusSize];
                byte[]    voicePacket, pingPacket, nonce = null;
                uint      timestamp = 0;
                double    nextTicks = 0.0, nextPingTicks = 0.0;
                long      ticksPerSeconds     = Stopwatch.Frequency;
                double    ticksPerMillisecond = Stopwatch.Frequency / 1000.0;
                double    ticksPerFrame       = ticksPerMillisecond * _encoder.FrameLength;
                double    spinLockThreshold   = 3 * ticksPerMillisecond;
                uint      samplesPerFrame     = (uint)_encoder.SamplesPerFrame;
                Stopwatch sw = Stopwatch.StartNew();

                if (_isEncrypted)
                {
                    nonce       = new byte[24];
                    voicePacket = new byte[MaxOpusSize + 12 + 16];
                }
                else
                {
                    voicePacket = new byte[MaxOpusSize + 12];
                }

                pingPacket = new byte[8];

                int rtpPacketLength = 0;
                voicePacket[0]  = 0x80; //Flags;
                voicePacket[1]  = 0x78; //Payload Type
                voicePacket[8]  = (byte)(_ssrc >> 24);
                voicePacket[9]  = (byte)(_ssrc >> 16);
                voicePacket[10] = (byte)(_ssrc >> 8);
                voicePacket[11] = (byte)(_ssrc >> 0);

                if (_isEncrypted)
                {
                    Buffer.BlockCopy(voicePacket, 0, nonce, 0, 12);
                }

                bool hasFrame = false;
                while (!cancelToken.IsCancellationRequested)
                {
                    if (!hasFrame && _sendBuffer.Pop(frame))
                    {
                        ushort sequence = unchecked (_sequence++);
                        voicePacket[2] = (byte)(sequence >> 8);
                        voicePacket[3] = (byte)(sequence >> 0);
                        voicePacket[4] = (byte)(timestamp >> 24);
                        voicePacket[5] = (byte)(timestamp >> 16);
                        voicePacket[6] = (byte)(timestamp >> 8);
                        voicePacket[7] = (byte)(timestamp >> 0);

                        //Encode
                        int encodedLength = _encoder.EncodeFrame(frame, 0, encodedFrame);

                        //Encrypt
                        if (_isEncrypted)
                        {
                            Buffer.BlockCopy(voicePacket, 2, nonce, 2, 6); //Update nonce
                            int ret = SecretBox.Encrypt(encodedFrame, encodedLength, voicePacket, 12, nonce, _secretKey);
                            if (ret != 0)
                            {
                                continue;
                            }
                            rtpPacketLength = encodedLength + 12 + 16;
                        }
                        else
                        {
                            Buffer.BlockCopy(encodedFrame, 0, voicePacket, 12, encodedLength);
                            rtpPacketLength = encodedLength + 12;
                        }

                        timestamp = unchecked (timestamp + samplesPerFrame);
                        hasFrame  = true;
                    }

                    long   currentTicks     = sw.ElapsedTicks;
                    double ticksToNextFrame = nextTicks - currentTicks;
                    if (ticksToNextFrame <= 0.0)
                    {
                        if (hasFrame)
                        {
                            try
                            {
                                await _udp.SendAsync(voicePacket, rtpPacketLength, _endpoint).ConfigureAwait(false);
                            }
                            catch (SocketException ex)
                            {
                                Logger.Error("Failed to send UDP packet.", ex);
                            }
                            hasFrame = false;
                        }
                        nextTicks += ticksPerFrame;

                        //Is it time to send out another ping?
                        if (currentTicks > nextPingTicks)
                        {
                            //Increment in LE
                            for (int i = 0; i < 8; i++)
                            {
                                var b = pingPacket[i];
                                if (b == byte.MaxValue)
                                {
                                    pingPacket[i] = 0;
                                }
                                else
                                {
                                    pingPacket[i] = (byte)(b + 1);
                                    break;
                                }
                            }
                            await _udp.SendAsync(pingPacket, pingPacket.Length, _endpoint).ConfigureAwait(false);

                            nextPingTicks = currentTicks + 5 * ticksPerSeconds;
                        }
                    }
                    else
                    {
                        if (hasFrame)
                        {
                            int time = (int)Math.Floor(ticksToNextFrame / ticksPerMillisecond);
                            if (time > 0)
                            {
                                await Task.Delay(time).ConfigureAwait(false);
                            }
                        }
                        else
                        {
                            await Task.Delay(1).ConfigureAwait(false); //Give as much time to the encrypter as possible
                        }
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (InvalidOperationException) { } //Includes ObjectDisposedException
        }
Пример #6
0
        private void SendVoiceAsync(CancellationToken cancelToken)
        {
            try
            {
                while (!cancelToken.IsCancellationRequested && _state != (int)WebSocketState.Connected)
                {
                    Thread.Sleep(1);
                }

                if (cancelToken.IsCancellationRequested)
                {
                    return;
                }

                byte[]    frame               = new byte[_encoder.FrameSize];
                byte[]    encodedFrame        = new byte[MaxOpusSize];
                byte[]    udpPacket, nonce    = null;
                uint      timestamp           = 0;
                double    nextTicks           = 0.0;
                double    ticksPerMillisecond = Stopwatch.Frequency / 1000.0;
                double    ticksPerFrame       = ticksPerMillisecond * _encoder.FrameLength;
                double    spinLockThreshold   = 3 * ticksPerMillisecond;
                uint      samplesPerFrame     = (uint)_encoder.SamplesPerFrame;
                Stopwatch sw = Stopwatch.StartNew();

                if (_isEncrypted)
                {
                    nonce     = new byte[24];
                    udpPacket = new byte[MaxOpusSize + 12 + 16];
                }
                else
                {
                    udpPacket = new byte[MaxOpusSize + 12];
                }

                int rtpPacketLength = 0;
                udpPacket[0]  = 0x80;                //Flags;
                udpPacket[1]  = 0x78;                //Payload Type
                udpPacket[8]  = (byte)((_ssrc >> 24) & 0xFF);
                udpPacket[9]  = (byte)((_ssrc >> 16) & 0xFF);
                udpPacket[10] = (byte)((_ssrc >> 8) & 0xFF);
                udpPacket[11] = (byte)((_ssrc >> 0) & 0xFF);

                if (_isEncrypted)
                {
                    Buffer.BlockCopy(udpPacket, 0, nonce, 0, 12);
                }

                while (!cancelToken.IsCancellationRequested)
                {
                    double ticksToNextFrame = nextTicks - sw.ElapsedTicks;
                    if (ticksToNextFrame <= 0.0)
                    {
                        while (sw.ElapsedTicks > nextTicks)
                        {
                            if (_sendBuffer.Pop(frame))
                            {
                                ushort sequence = unchecked (_sequence++);
                                udpPacket[2] = (byte)((sequence >> 8) & 0xFF);
                                udpPacket[3] = (byte)((sequence >> 0) & 0xFF);
                                udpPacket[4] = (byte)((timestamp >> 24) & 0xFF);
                                udpPacket[5] = (byte)((timestamp >> 16) & 0xFF);
                                udpPacket[6] = (byte)((timestamp >> 8) & 0xFF);
                                udpPacket[7] = (byte)((timestamp >> 0) & 0xFF);

                                //Encode
                                int encodedLength = _encoder.EncodeFrame(frame, 0, encodedFrame);

                                //Encrypt
                                if (_isEncrypted)
                                {
                                    Buffer.BlockCopy(udpPacket, 2, nonce, 2, 6);                                     //Update nonce
                                    int ret = Sodium.Encrypt(encodedFrame, encodedLength, udpPacket, 12, nonce, _secretKey);
                                    if (ret != 0)
                                    {
                                        continue;
                                    }
                                    rtpPacketLength = encodedLength + 12 + 16;
                                }
                                else
                                {
                                    Buffer.BlockCopy(encodedFrame, 0, udpPacket, 12, encodedLength);
                                    rtpPacketLength = encodedLength + 12;
                                }
                                _udp.Send(udpPacket, rtpPacketLength);
                            }
                            timestamp  = unchecked (timestamp + samplesPerFrame);
                            nextTicks += ticksPerFrame;
                        }
                    }
                    //Dont sleep if we need to output audio in the next spinLockThreshold
                    else if (ticksToNextFrame > spinLockThreshold)
                    {
                        int time = (int)Math.Ceiling((ticksToNextFrame - spinLockThreshold) / ticksPerMillisecond);
                        Thread.Sleep(1);
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (InvalidOperationException) { }             //Includes ObjectDisposedException
        }
Пример #7
0
#pragma warning restore 4014
        private async Task SendVoiceAsync(CancellationToken cancelToken)
        {
            byte[] voiceToEncode;
            voiceToSend.TryDequeue(out voiceToEncode);
            if (voiceToEncode != null)
            {
                Stopwatch timeToSend = Stopwatch.StartNew();
                byte[]    rtpPacket  = new byte[12 + voiceToEncode.Length];
                rtpPacket[0] = (byte)0x80;
                rtpPacket[1] = (byte)0x78;

                rtpPacket[8]  = (byte)((Params.ssrc >> 24) & 0xFF);
                rtpPacket[9]  = (byte)((Params.ssrc >> 16) & 0xFF);
                rtpPacket[10] = (byte)((Params.ssrc >> 8) & 0xFF);
                rtpPacket[11] = (byte)((Params.ssrc >> 0) & 0xFF);

                byte[] opusAudio     = new byte[voiceToEncode.Length];
                int    encodedLength = mainOpusEncoder.EncodeFrame(voiceToEncode, 0, opusAudio);


                int dataSent = 0;

                //actual sending
                {
                    //sequence big endian
                    rtpPacket[2] = (byte)((___sequence >> 8));
                    rtpPacket[3] = (byte)((___sequence >> 0) & 0xFF);

                    //timestamp big endian
                    rtpPacket[4] = (byte)((___timestamp >> 24) & 0xFF);
                    rtpPacket[5] = (byte)((___timestamp >> 16) & 0xFF);
                    rtpPacket[6] = (byte)((___timestamp >> 8));
                    rtpPacket[7] = (byte)((___timestamp >> 0) & 0xFF);

                    if (opusAudio == null)
                    {
                        throw new ArgumentNullException("opusAudio");
                    }

                    int maxSize = encodedLength;
                    Buffer.BlockCopy(opusAudio, 0, rtpPacket, 12, encodedLength);

                    dataSent = _udp.SendAsync(rtpPacket, encodedLength + 12).Result;

                    ___sequence  = unchecked (___sequence++);
                    ___timestamp = unchecked (___timestamp + (uint)(voiceToEncode.Length / 2));
                }

                timeToSend.Stop(); //stop after completely sending

                //Compensate for however long it took to sent.
                if (timeToSend.ElapsedMilliseconds > 0)
                {
                    long timeToWait = (msToSend * TimeSpan.TicksPerMillisecond) - (timeToSend.ElapsedMilliseconds * TimeSpan.TicksPerMillisecond);
                    if (timeToWait > 0) //if it's negative then don't bother waiting
                    {
                        await Task.Delay(new TimeSpan(timeToWait)).ConfigureAwait(false);
                    }
                }
                else
                {
                    await Task.Delay(msToSend).ConfigureAwait(false);
                }

                VoiceDebugLogger.LogAsync("Sent " + dataSent + " bytes of Opus audio", MessageLevel.Unecessary);
            }
        }
Пример #8
0
 public override void Write(byte[] buffer, int offset, int count)
 {
     count = _encoder.EncodeFrame(buffer, offset, count, _buffer, 0);
     base.Write(_buffer, 0, count);
 }
Пример #9
0
#pragma warning restore 4014
        private async Task SendVoiceAsync(CancellationToken cancelToken)
        {
            byte[] voiceToEncode; //pcm data
            voiceToSend.TryDequeue(out voiceToEncode);
            if (voiceToEncode != null)
            {
                Stopwatch timeToSend = Stopwatch.StartNew();

                byte[] fullVoicePacket = new byte[4000 + 12 + 16];
                byte[] nonce           = new byte[24];

                fullVoicePacket[0] = (byte)0x80;                          //flags
                fullVoicePacket[1] = (byte)0x78;                          //flags

                fullVoicePacket[8]  = (byte)((Params.ssrc >> 24) & 0xFF); //ssrc
                fullVoicePacket[9]  = (byte)((Params.ssrc >> 16) & 0xFF); //ssrc
                fullVoicePacket[10] = (byte)((Params.ssrc >> 8) & 0xFF);  //ssrc
                fullVoicePacket[11] = (byte)((Params.ssrc >> 0) & 0xFF);  //ssrc

                byte[] opusAudio     = new byte[voiceToEncode.Length];
                int    encodedLength = mainOpusEncoder.EncodeFrame(voiceToEncode, 0, opusAudio);

                int dataSent = 0;

                //actual sending
                {
                    ___sequence = unchecked (___sequence++);
                    //sequence big endian
                    fullVoicePacket[2] = (byte)((___sequence >> 8));
                    fullVoicePacket[3] = (byte)((___sequence >> 0) & 0xFF);

                    //timestamp big endian
                    fullVoicePacket[4] = (byte)((___timestamp >> 24) & 0xFF);
                    fullVoicePacket[5] = (byte)((___timestamp >> 16) & 0xFF);
                    fullVoicePacket[6] = (byte)((___timestamp >> 8));
                    fullVoicePacket[7] = (byte)((___timestamp >> 0) & 0xFF);

                    Buffer.BlockCopy(fullVoicePacket, 0, nonce, 0, 12); //copy header into nonce

                    //Buffer.BlockCopy(rtpPacket, 2, nonce, 2, 6); //copy 6 bytes for nonce
                    int returnVal = SecretBox.Encrypt(opusAudio, encodedLength, fullVoicePacket, 12, nonce, __secretKey);
                    if (returnVal != 0)
                    {
                        return;
                    }
                    if (opusAudio == null)
                    {
                        throw new ArgumentNullException("opusAudio");
                    }

                    int maxSize         = encodedLength;
                    int rtpPacketLength = encodedLength + 12 + 16;

#if NETFX4_5
                    //dataSent = _udp.SendAsync(fullVoicePacket, encodedLength + 12 + 16).Result;
                    await _udp.SendAsync(fullVoicePacket, encodedLength + 12 + 16);
#else
                    dataSent = _udp.Send(fullVoicePacket, rtpPacketLength);
#endif

                    ___timestamp = unchecked (___timestamp + (uint)(voiceToEncode.Length / 2));
                }

                timeToSend.Stop(); //stop after completely sending

                //Compensate for however long it took to sent.
                if (timeToSend.ElapsedMilliseconds > 0)
                {
                    long timeToWait = (msToSend * TimeSpan.TicksPerMillisecond) - (timeToSend.ElapsedMilliseconds * TimeSpan.TicksPerMillisecond);
                    if (timeToWait > 0) //if it's negative then don't bother waiting
                    {
#if NETFX4_5
                        await Task.Delay(new TimeSpan(timeToWait)).ConfigureAwait(false);
#else
                        Thread.Sleep(new TimeSpan(timeToWait));
#endif
                    }
                }
                else
                {
#if NETFX4_5
                    await Task.Delay(msToSend).ConfigureAwait(false);
#else
                    Thread.Sleep(msToSend);
#endif
                }

                VoiceDebugLogger.LogAsync("Sent " + dataSent + " bytes of Opus audio", MessageLevel.Unecessary);
            }
        }