Exemplo n.º 1
0
        /// <summary>
        /// Parses the given scalabilityMode string according to the rules in webrtc-svc.
        /// </summary>
        /// <param name="scalabilityMode"></param>
        /// <returns></returns>
        public static ScalabilityMode Parse(string scalabilityMode)
        {
            var match  = ScalabilityModeRegex.Match(scalabilityMode);
            var result = new ScalabilityMode();

            if (match.Success)
            {
                result.SpatialLayers  = int.Parse(match.Groups[1].Value);
                result.TemporalLayers = int.Parse(match.Groups[2].Value);
                result.Ksvc           = match.Groups.Count >= 4 && match.Groups[3].Value == "_KEY";
            }
            else
            {
                result.SpatialLayers  = 1;
                result.TemporalLayers = 1;
                result.Ksvc           = false;
            }
            return(result);
        }
Exemplo 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);
        }