Ejemplo n.º 1
0
        /// <summary>
        /// Validates RtpEncodingParameters. It may modify given data by adding missing
        /// fields with default values.
        /// It throws if invalid.
        /// </summary>
        public static void ValidateRtpEncodingParameters(RtpEncodingParameters encoding)
        {
            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            // ssrc is optional.
            // 在 Node.js 实现中,判断了 ssrc 的数据类型。在强类型语言中不需要。

            // rid is optional.
            // 在 Node.js 实现中,判断了 rid 的数据类型。在强类型语言中不需要。

            // rtx is optional.
            // 在 Node.js 实现中,判断了 rtx 的数据类型。在强类型语言中不需要。
            if (encoding.Rtx != null)
            {
                // RTX ssrc is mandatory if rtx is present.
                // 在 Node.js 实现中,判断了 rtx.ssrc 的数据类型。在强类型语言中不需要。
            }

            // dtx is optional. If unset set it to false.
            if (!encoding.Dtx.HasValue)
            {
                encoding.Dtx = false;
            }

            // scalabilityMode is optional.
            // 在 Node.js 实现中,判断了 scalabilityMode 的数据类型。在强类型语言中不需要。
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Generate RTP parameters for a specific Consumer.
        ///
        /// It reduces encodings to just one and takes into account given RTP capabilities
        /// to reduce codecs, codecs' RTCP feedback and header extensions, and also enables
        /// or disabled RTX.
        /// </summary>
        public static RtpParameters GetConsumerRtpParameters(RtpParameters consumableParams, RtpCapabilities caps)
        {
            var consumerParams = new RtpParameters
            {
                Codecs           = new List <RtpCodecParameters>(),
                HeaderExtensions = new List <RtpHeaderExtensionParameters>(),
                Encodings        = new List <RtpEncodingParameters>(),
                Rtcp             = consumableParams.Rtcp
            };

            foreach (var capCodec in caps.Codecs) // TODO: (alby)注意 null 引用
            {
                ValidateRtpCodecCapability(capCodec);
            }

            var consumableCodecs = consumableParams.Codecs.DeepClone <List <RtpCodecParameters> >();
            var rtxSupported     = false;

            foreach (var codec in consumableCodecs)
            {
                var matchedCapCodec = caps.Codecs
                                      .Where(capCodec => MatchCodecs(capCodec, codec, true))
                                      .FirstOrDefault();

                if (matchedCapCodec == null)
                {
                    continue;
                }

                codec.RtcpFeedback = matchedCapCodec.RtcpFeedback;

                consumerParams.Codecs.Add(codec);

                if (!rtxSupported && IsRtxMimeType(codec.MimeType))
                {
                    rtxSupported = true;
                }
            }

            // Ensure there is at least one media codec.
            if (consumerParams.Codecs.Count == 0 || IsRtxMimeType(consumerParams.Codecs[0].MimeType))
            {
                throw new Exception("no compatible media codecs");
            }

            consumerParams.HeaderExtensions = consumableParams.HeaderExtensions
                                              .Where(ext =>
                                                     caps.HeaderExtensions
                                                     .Any(capExt => capExt.PreferredId == ext.Id && capExt.Uri == ext.Uri)
                                                     ).ToList();

            // Reduce codecs' RTCP feedback. Use Transport-CC if available, REMB otherwise.
            if (consumerParams.HeaderExtensions.Any(ext => ext.Uri == "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"))
            {
                foreach (var codec in consumerParams.Codecs)
                {
                    codec.RtcpFeedback = codec.RtcpFeedback.Where(fb => fb.Type != "goog-remb").ToArray();
                }
            }
            else if (consumerParams.HeaderExtensions.Any(ext => ext.Uri == "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"))
            {
                foreach (var codec in consumerParams.Codecs)
                {
                    codec.RtcpFeedback = codec.RtcpFeedback.Where(fb => fb.Type != "transport-cc").ToArray();
                }
            }
            else
            {
                foreach (var codec in consumerParams.Codecs)
                {
                    codec.RtcpFeedback = codec.RtcpFeedback.Where(fb => fb.Type != "transport-cc" && fb.Type != "goog-remb").ToArray();
                }
            }

            var consumerEncoding = new RtpEncodingParameters
            {
                Ssrc = Utils.GenerateRandomNumber()
            };

            if (rtxSupported)
            {
                consumerEncoding.Rtx = new Rtx {
                    Ssrc = Utils.GenerateRandomNumber()
                };
            }

            // If any in the consumableParams.Encodings has scalabilityMode, process it
            // (assume all encodings have the same value).
            var encodingWithScalabilityMode = consumableParams.Encodings.Where(encoding => !encoding.ScalabilityMode.IsNullOrWhiteSpace()).FirstOrDefault();

            var scalabilityMode = encodingWithScalabilityMode?.ScalabilityMode;

            // If there is simulast, mangle spatial layers in scalabilityMode.
            if (consumableParams.Encodings.Count > 1)                               // TODO: (alby)注意 null 引用
            {
                var scalabilityModeObject = ScalabilityMode.Parse(scalabilityMode); // TODO: (alby)注意 null 引用

                scalabilityMode = $"S{ consumableParams.Encodings.Count }T{ scalabilityModeObject.TemporalLayers }";
            }

            if (!scalabilityMode.IsNullOrWhiteSpace())
            {
                consumerEncoding.ScalabilityMode = scalabilityMode;
            }

            // Use the maximum maxBitrate in any encoding and honor it in the Consumer's
            // encoding.
            var maxEncodingMaxBitrate = consumableParams.Encodings.Max(m => m.MaxBitrate);

            if (maxEncodingMaxBitrate.HasValue && maxEncodingMaxBitrate.Value > 0)
            {
                consumerEncoding.MaxBitrate = maxEncodingMaxBitrate;
            }

            // Set a single encoding for the Consumer.
            consumerParams.Encodings.Add(consumerEncoding);

            // Copy verbatim.
            consumerParams.Rtcp = consumableParams.Rtcp;

            return(consumerParams);
        }