private void ReceiveVoice()
        {
            if (client.Available > 0)
            {
                byte[] packet, buffer = null, nonce = null, result;
                packet = client.Receive(ref endpoint);
                int packetLength, resultLength;
                buffer       = new byte[4000];
                nonce        = new byte[24];
                packetLength = packet.Length;

                if (packet.Length > 0)
                {
                    if (packetLength < 12)
                    {
                        return;
                    }
                    if (packet[0] != 0x80)
                    {
                        return;
                    }
                    if (packet[1] != 0x78)
                    {
                        return;
                    }

                    ushort sequenceNumber = (ushort)((packet[2] << 8) | packet[3] << 0);
                    uint   timDocuestamp  = (uint)((packet[4] << 24) | packet[5] << 16 | packet[6] << 8 | packet[7] << 0);
                    uint   ssrc           = (uint)((packet[8] << 24) | (packet[9] << 16) | (packet[10] << 8) | (packet[11] << 0));

                    if (packetLength < 28)
                    {
                        return;
                    }

                    Buffer.BlockCopy(packet, 0, nonce, 0, 12);
                    var length      = Convert.ToUInt64(packetLength - 12);
                    int returnValue = SecretBox.Decrypt(packet, length, buffer, nonce, key);
                    if (returnValue != 0)
                    {
                        return;
                    }
                    result       = buffer;
                    resultLength = packetLength - 28;

                    if (users.ContainsValue(ssrc))
                    {
                        byte[] output = new byte[1920];
                        decoder.DecodeFrame(result, 0, resultLength, output);
                        float[] outputFloat = Utils.BytesToFloats(output);
                        parent.unityInvoker.Enqueue(() => OnVoicePacketReceived(this, new DiscordVoiceArgs()
                        {
                            channel = channel, client = parent, packet = output, unitypacket = outputFloat, raw = result, sender = GetUserBySsrc(ssrc)
                        }));
                    }
                }
            }
        }
        private void SendVoice()
        {
            byte[] buffer = voiceToSend.Dequeue();

            if (buffer != null)
            {
                System.Diagnostics.Stopwatch timeToSend = System.Diagnostics.Stopwatch.StartNew();

                byte[] packet = new byte[4028];
                byte[] nonce  = new byte[24];

                packet[0] = (byte)0x80;
                packet[1] = (byte)0x78;

                packet[8]  = (byte)(ssrc >> 24);
                packet[9]  = (byte)(ssrc >> 16);
                packet[10] = (byte)(ssrc >> 8);
                packet[11] = (byte)(ssrc >> 0);

                sequence  = unchecked (sequence++);
                packet[2] = (byte)(sequence >> 8);
                packet[3] = (byte)(sequence >> 0);

                packet[4] = (byte)(timestamp >> 24);
                packet[5] = (byte)(timestamp >> 16);
                packet[6] = (byte)(timestamp >> 8);
                packet[7] = (byte)(timestamp >> 0);

                byte[] opusVoice     = new byte[buffer.Length];
                int    encodedLength = encoder.EncodeFrame(buffer, 0, opusVoice);

                Buffer.BlockCopy(packet, 0, nonce, 0, 12);
                int returnVal = SecretBox.Encrypt(opusVoice, encodedLength, packet, nonce, key);
                if (returnVal != 0)
                {
                    return;
                }
                if (opusVoice == null)
                {
                    Debug.LogError("opusVoice");
                }

                int dataSent = client.Send(packet, encodedLength + 28);
                timestamp = unchecked (timestamp + (uint)encoder.SamplesPerFrame);
                float[] inputFloat = Utils.BytesToFloats(buffer);
                parent.unityInvoker.Enqueue(() => OnVoicePacketSend(this, new DiscordVoiceArgs()
                {
                    channel = channel, client = parent, packet = packet, unitypacket = inputFloat, raw = buffer, sender = parent.user
                }));

                timeToSend.Stop();

                if (timeToSend.ElapsedMilliseconds > 0)
                {
                    Thread.Sleep(20 - (int)timeToSend.ElapsedMilliseconds);
                }

                else
                {
                    Thread.Sleep(20);
                }
            }

            else
            {
                byte[] empty = new byte[3] {
                    (byte)0xF8, (byte)0xFF, (byte)0xFE
                };
                client.Send(empty, empty.Length);
            }
        }