Пример #1
0
        /// <summary>
        /// Get a mapping in codec payloads and encodings in the given Producer RTP
        /// parameters as values expected by the Router.
        ///
        /// It may throw if invalid or non supported RTP parameters are given.
        /// </summary>
        public static RtpMapping GetProducerRtpParametersMapping(RtpParameters parameters, RtpCapabilities caps)
        {
            var rtpMapping = new RtpMapping
            {
                Codecs    = new List <RtpMappingCodec>(),
                Encodings = new List <RtpMappingEncoding>()
            };

            // Match parameters media codecs to capabilities media codecs.
            var codecToCapCodec = new Dictionary <RtpCodecParameters, RtpCodecCapability>();

            foreach (var codec in parameters.Codecs)
            {
                if (IsRtxMimeType(codec.MimeType))
                {
                    continue;
                }

                // Search for the same media codec in capabilities.
                var matchedCapCodec = caps.Codecs
                                      .Where(capCodec => MatchCodecs(codec, capCodec, true, true))
                                      .FirstOrDefault();
                codecToCapCodec[codec] = matchedCapCodec ?? throw new Exception($"unsupported codec[mimeType:{ codec.MimeType }, payloadType:{ codec.PayloadType }, Channels:{ codec.Channels }]");
            }

            // Match parameters RTX codecs to capabilities RTX codecs.
            foreach (var codec in parameters.Codecs)
            {
                if (!IsRtxMimeType(codec.MimeType))
                {
                    continue;
                }

                // Search for the associated media codec.
                var associatedMediaCodec = parameters.Codecs
                                           .Where(mediaCodec => MatchCodecsWithPayloadTypeAndApt(mediaCodec.PayloadType, codec.Parameters))
                                           .FirstOrDefault();

                if (associatedMediaCodec == null)
                {
                    throw new Exception($"missing media codec found for RTX PT { codec.PayloadType}");
                }

                var capMediaCodec = codecToCapCodec[associatedMediaCodec];

                // Ensure that the capabilities media codec has a RTX codec.
                var associatedCapRtxCodec = caps.Codecs
                                            .Where(capCodec => IsRtxMimeType(capCodec.MimeType) && MatchCodecsWithPayloadTypeAndApt(capMediaCodec.PreferredPayloadType, capCodec.Parameters))
                                            .FirstOrDefault();
                codecToCapCodec[codec] = associatedCapRtxCodec ?? throw new Exception($"no RTX codec for capability codec PT { capMediaCodec.PreferredPayloadType}");
            }

            // Generate codecs mapping.
            foreach (var item in codecToCapCodec)
            {
                rtpMapping.Codecs.Add(new RtpMappingCodec
                {
                    PayloadType       = item.Key.PayloadType,
                    MappedPayloadType = item.Value.PreferredPayloadType !.Value,
                });
Пример #2
0
        /// <summary>
        /// Generate RTP parameters to be internally used by Consumers given the RTP
        /// parameters in a Producer and the RTP capabilities in the Router.
        /// </summary>
        public static RtpParameters GetConsumableRtpParameters(MediaKind kind, RtpParameters parameters, RtpCapabilities caps, RtpMapping rtpMapping)
        {
            var consumableParams = new RtpParameters
            {
                Codecs           = new List <RtpCodecParameters>(),
                HeaderExtensions = new List <RtpHeaderExtensionParameters>(),
                Encodings        = new List <RtpEncodingParameters>(),
                Rtcp             = new RtcpParameters(),
            };

            foreach (var codec in parameters.Codecs)
            {
                if (IsRtxMimeType(codec.MimeType))
                {
                    continue;
                }

                var consumableCodecPt = rtpMapping.Codecs
                                        .Where(entry => entry.PayloadType == codec.PayloadType)
                                        .Select(m => m.MappedPayloadType)
                                        .FirstOrDefault();

                var matchedCapCodec = caps.Codecs
                                      .Where(capCodec => capCodec.PreferredPayloadType == consumableCodecPt)
                                      .FirstOrDefault();

                var consumableCodec = new RtpCodecParameters
                {
                    MimeType     = matchedCapCodec.MimeType,
                    PayloadType  = matchedCapCodec.PreferredPayloadType.Value, // TODO: (alby)注意 null 引用
                    ClockRate    = matchedCapCodec.ClockRate,
                    Channels     = matchedCapCodec.Channels,
                    Parameters   = codec.Parameters, // Keep the Producer codec parameters.
                    RtcpFeedback = matchedCapCodec.RtcpFeedback
                };

                consumableParams.Codecs.Add(consumableCodec);

                var consumableCapRtxCodec = caps.Codecs
                                            .Where(capRtxCodec => IsRtxMimeType(capRtxCodec.MimeType) && MatchCodecsWithPayloadTypeAndApt(consumableCodec.PayloadType, capRtxCodec.Parameters))
                                            .FirstOrDefault();

                if (consumableCapRtxCodec != null)
                {
                    var consumableRtxCodec = new RtpCodecParameters
                    {
                        MimeType     = consumableCapRtxCodec.MimeType,
                        PayloadType  = consumableCapRtxCodec.PreferredPayloadType.Value, // TODO: (alby)注意 null 引用
                        ClockRate    = consumableCapRtxCodec.ClockRate,
                        Channels     = consumableCapRtxCodec.Channels,
                        Parameters   = consumableCapRtxCodec.Parameters, // Keep the Producer codec parameters.
                        RtcpFeedback = consumableCapRtxCodec.RtcpFeedback
                    };

                    consumableParams.Codecs.Add(consumableRtxCodec);
                }
            }

            foreach (var capExt in caps.HeaderExtensions) // TODO: (alby)注意 null 引用
            {
                // Just take RTP header extension that can be used in Consumers.
                if (capExt.Kind != kind || (capExt.Direction != RtpHeaderExtensionDirection.SendReceive && capExt.Direction != RtpHeaderExtensionDirection.SendOnly))
                {
                    continue;
                }

                var consumableExt = new RtpHeaderExtensionParameters
                {
                    Uri        = capExt.Uri,
                    Id         = capExt.PreferredId,
                    Encrypt    = capExt.PreferredEncrypt,
                    Parameters = new Dictionary <string, object>(),
                };

                consumableParams.HeaderExtensions.Add(consumableExt);
            }

            // Clone Producer encodings since we'll mangle them.
            var consumableEncodings = parameters.Encodings.DeepClone <List <RtpEncodingParameters> >();

            for (var i = 0; i < consumableEncodings.Count; ++i)
            {
                var consumableEncoding = consumableEncodings[i];
                var mappedSsrc         = rtpMapping.Encodings[i].MappedSsrc;

                // Remove useless fields.
                // 在 Node.js 实现中,rid, rtx, codecPayloadType 被 delete 了。
                consumableEncoding.Rid = null;
                consumableEncoding.Rtx = null;
                consumableEncoding.CodecPayloadType = null;

                // Set the mapped ssrc.
                consumableEncoding.Ssrc = mappedSsrc;

                consumableParams.Encodings.Add(consumableEncoding);
            }

            consumableParams.Rtcp = new RtcpParameters
            {
                CNAME       = parameters.Rtcp.CNAME, // TODO: (alby)注意 null 引用
                ReducedSize = true,
                Mux         = true,
            };

            return(consumableParams);
        }