Пример #1
0
        private async Task VoiceReceiverTask()
        {
            var token  = ReceiverToken;
            var client = UdpClient;

            while (!token.IsCancellationRequested)
            {
                if (client.DataAvailable <= 0)
                {
                    continue;
                }

                byte[] data = null, header = null;
                ushort seq = 0;
                uint   ts = 0, ssrc = 0;
                try
                {
                    data = await client.ReceiveAsync().ConfigureAwait(false);

                    header = new byte[RtpCodec.SIZE_HEADER];
                    data   = Rtp.Decode(data, header);

                    var nonce = Rtp.MakeNonce(header);
                    data = Sodium.Decode(data, nonce, Key);

                    // following is thanks to code from Eris
                    // https://github.com/abalabahaha/eris/blob/master/lib/voice/VoiceConnection.js#L623
                    var doff = 0;
                    Rtp.Decode(header, out seq, out ts, out ssrc, out var has_ext);
                    if (has_ext)
                    {
                        if (data[0] == 0xBE && data[1] == 0xDE)
                        {
                            // RFC 5285, 4.2 One-Byte header
                            // http://www.rfcreader.com/#rfc5285_line186

                            var hlen = data[2] << 8 | data[3];
                            var i    = 4;
                            for (; i < hlen + 4; i++)
                            {
                                var b = data[i];
                                // This is unused(?)
                                //var id = (b >> 4) & 0x0F;
                                var len = (b & 0x0F) + 1;
                                i += len;
                            }
                            while (data[i] == 0)
                            {
                                i++;
                            }
                            doff = i;
                        }
                        // TODO: consider implementing RFC 5285, 4.3. Two-Byte Header
                    }

                    data = Opus.Decode(data, doff, data.Length - doff);
                }
                catch { continue; }

                // TODO: wait for ssrc map?
                DiscordUser user = null;
                if (SSRCMap.ContainsKey(ssrc))
                {
                    var id = SSRCMap[ssrc];
                    if (Guild != null)
                    {
                        user = Guild._members.FirstOrDefault(xm => xm.Id == id) ?? await Guild.GetMemberAsync(id).ConfigureAwait(false);
                    }

                    if (user == null)
                    {
                        user = Discord.InternalGetCachedUser(id);
                    }

                    if (user == null)
                    {
                        user = new DiscordUser {
                            Discord = Discord, Id = id
                        }
                    }
                    ;
                }

                await _voiceReceived.InvokeAsync(new VoiceReceiveEventArgs(Discord)
                {
                    SSRC        = ssrc,
                    Voice       = new ReadOnlyCollection <byte>(data),
                    VoiceLength = 20,
                    User        = user
                }).ConfigureAwait(false);
            }
        }