Ejemplo n.º 1
0
        bool IsRtxCodec(RtpCodecCapability codec) // =>
                                                  //Regex.IsMatch(codec.MimeType, ".+/rtx$");
        {
            var ok = Regex.IsMatch(codec.MimeType, ".+/rtx$");

            return(ok);
        }
Ejemplo n.º 2
0
        RtcpFeedback[] ReduceRtcpFeedback(RtpCodecCapability codecA, RtpCodecCapability codecB)
        {
            var fbArray = codecA.RtcpFeedback
                          .Where(a => codecB.RtcpFeedback.Any(b =>
                                                              b.Type.Equals(a.Type) &&
                                                              a.Parameter is not null &&
                                                              b.Parameter is not null &&
                                                              a.Parameter.Equals(b.Parameter)))
                          .ToArray();

            return(fbArray);
        }
Ejemplo n.º 3
0
        // Validates RtpCodecCapability. It may modify given data by adding missing
        // fields with default values.
        // It throws if invalid.
        public void ValidateRtpCodecCapability(RtpCodecCapability codec)
        {
            // mimeType is mandatory.
            if (codec.MimeType is null)
            {
                throw new Exception("missing codec.mimeType");
            }

            var match = Regex.Match(codec.MimeType, "^(audio|video)/(.+)");

            if (!match.Success || match.Groups.Count != 3)
            {
                throw new Exception("invalid codec.mimeType");
            }

            // Just override kind with media component of mimeType.
            codec.Kind = (MediaKind)Enum.Parse(typeof(MediaKind), match.Groups[1].Value.ToLower(), true);

            // Channels is optional. If unset, set it to 1 (just if audio).
            if (codec.Kind == MediaKind.Audio)
            {
                if (!codec.Channels.HasValue)
                {
                    codec.Channels = 1;
                }
            }
            else
            {
                codec.Channels = null;
            }

            // Parameters is optional. If unset, set it to an empty object.
            if (codec.Parameters is null)
            {
                codec.Parameters = new Dictionary <string, object /*string*/>();
            }

            // RtcpFeedback is optional. If unset, set it to an empty array.
            if (codec.RtcpFeedback is null)
            {
                codec.RtcpFeedback = new RtcpFeedback[] { }
            }
            ;
            foreach (var fb in codec.RtcpFeedback)
            {
                ValidateRtcpFeedback(fb);
            }
        }
Ejemplo n.º 4
0
        public RtpCodecParameters[] ReduceCodecs(RtpCodecParameters[] codecs, RtpCodecCapability capCodec)
        {
            List <RtpCodecParameters> filteredCodecs = new();

            // If no capability codec is given, take the first one (and RTX).
            if (capCodec is null)
            {
                filteredCodecs.Add(codecs[0]);

                if (codecs.Length > 1 && IsRtxCodec(codecs[1]))
                {
                    filteredCodecs.Add(codecs[1]);
                }
            }
            // Otherwise look for a compatible set of codecs.
            else
            {
                for (var idx = 0; idx < codecs.Length; ++idx)
                {
                    if (MatchCodecs(codecs[idx], capCodec))
                    {
                        filteredCodecs.Add(codecs[idx]);

                        if (IsRtxCodec(codecs[idx + 1]))
                        {
                            filteredCodecs.Add(codecs[idx + 1]);
                        }
                        break;
                    }
                }

                if (filteredCodecs.Count() == 0)
                {
                    throw new Exception("No matching codec found");
                }
            }

            return(filteredCodecs.ToArray());
        }
Ejemplo n.º 5
0
        bool MatchCodecs(RtpCodecParameters aCodec, RtpCodecCapability bCodec, bool strict = false,
                         bool modify = false)
        {
            var aMimeType = aCodec.MimeType.ToLower();
            var bMimeType = bCodec.MimeType.ToLower();

            if (aMimeType != bMimeType)
            {
                return(false);
            }

            if (aCodec.ClockRate != bCodec.ClockRate)
            {
                return(false);
            }

            if (aCodec.Channels != bCodec.Channels)
            {
                return(false);
            }

            switch (aMimeType)
            {
            case "video/h264":
                var aPacketizationMode = aCodec.Parameters.ContainsKey("packetization-mode") ?
                                         (int)aCodec.Parameters["packetization-mode"] : 0;
                var bPacketizationMode = bCodec.Parameters.ContainsKey("packetization-mode") ?
                                         (int)bCodec.Parameters["packetization-mode"] : 0;

                if (aPacketizationMode != bPacketizationMode)
                {
                    return(false);
                }

                if (strict)
                {
                    if (!H264.IsSameProfile(aCodec.Parameters, bCodec.Parameters))
                    {
                        return(false);
                    }

                    string selectedProfileLevelId;
                    try
                    {
                        selectedProfileLevelId = H264.GenerateProfileLevelIdForAnswer(
                            aCodec.Parameters, bCodec.Parameters);
                    }
                    catch
                    {
                        return(false);
                    }
                    if (modify)
                    {
                        if (selectedProfileLevelId is not null)
                        {
                            aCodec.Parameters["profile-level-id"] = selectedProfileLevelId;
                            bCodec.Parameters["profile-level-id"] = selectedProfileLevelId;
                        }
                        else
                        {
                            aCodec.Parameters.Remove("profile-level-id");
                            bCodec.Parameters.Remove("profile-level-id");
                        }
                    }
                }
                break;

            case "video/vp9":
                if (strict)
                {
                    var aProfileId = aCodec.Parameters.ContainsKey("profile-id") ?
                                     (int)aCodec.Parameters["profile-id"] : 0;
                    var bProfileId = bCodec.Parameters.ContainsKey("profile-id") ?
                                     (int)bCodec.Parameters["profile-id"] : 0;

                    if (aProfileId != bProfileId)
                    {
                        return(false);
                    }
                }
                break;
            }

            return(true);
        }
Ejemplo n.º 6
0
        public static RtpCapabilities ExtractRtpCapabilities(Utilme.SdpTransform.Sdp sdp)
        {
            Dictionary <int, RtpCodecCapability> codecsDictionary = new();
            List <RtpHeaderExtension>            headerExtensions = new();

            bool gotAudio = false;
            bool gotVideo = false;

            foreach (var m in sdp.MediaDescriptions)
            {
                var       kind      = m.Media;
                MediaKind mediaKind = MediaKind.Video;
                switch (kind)
                {
                case MediaType.Audio:
                    mediaKind = MediaKind.Audio;
                    if (gotAudio)
                    {
                        continue;
                    }
                    gotAudio = true;
                    break;

                case MediaType.Video:
                    mediaKind = MediaKind.Video;
                    if (gotVideo)
                    {
                        continue;
                    }
                    gotVideo = true;
                    break;

                default:
                    continue;
                }

                var rtpmapAttributes = m.Attributes.Rtpmaps;
                foreach (var rtpmap in rtpmapAttributes)
                {
                    var codec = new RtpCodecCapability
                    {
                        MimeType             = $"{kind.DisplayName()}/{rtpmap.EncodingName}",
                        Kind                 = mediaKind,
                        PreferredPayloadType = rtpmap.PayloadType,
                        ClockRate            = rtpmap.ClockRate,
                        Channels             = rtpmap.Channels
                    };
                    codecsDictionary.Add(codec.PreferredPayloadType, codec);
                }

                var fmtpAttributes = m.Attributes.Fmtps;
                foreach (var fmtp in fmtpAttributes)
                {
                    if (!codecsDictionary.TryGetValue(fmtp.PayloadType, out var codec))
                    {
                        continue;
                    }
                    codec.Parameters = fmtp.ToDictionary();
                }

                var rtcpFbAttributes = m.Attributes.RtcpFbs;
                foreach (var rtcpFb in rtcpFbAttributes)
                {
                    if (!codecsDictionary.TryGetValue(rtcpFb.PayloadType, out var codec))
                    {
                        continue;
                    }
                    RtcpFeedback fb = new()
                    {
                        Type      = rtcpFb.Type,
                        Parameter = rtcpFb.SubType
                    };
                    codec.RtcpFeedback ??= new RtcpFeedback[] { };
                    var rtcpFbList = codec.RtcpFeedback.ToList();
                    rtcpFbList.Add(fb);
                    codec.RtcpFeedback = rtcpFbList.ToArray();
                }


                var extmapAttributes = m.Attributes.Extmaps;
                foreach (var extmap in extmapAttributes)
                {
                    RtpHeaderExtension headerExtension = new()
                    {
                        Kind        = mediaKind,
                        Uri         = extmap.Uri.ToString(),
                        PreferredId = extmap.Value
                    };
                    headerExtensions.Add(headerExtension);
                }
            }

            RtpCapabilities rtpCapabilities = new()
            {
                Codecs           = codecsDictionary.Values.ToArray(),
                HeaderExtensions = headerExtensions.ToArray()
            };

            return(rtpCapabilities);
        }
Ejemplo n.º 7
0
        static void SetMediaDescriptorParametersObject(RtpCodecCapability codec, string fmtpValue)
        {
            var tokens = fmtpValue.Split(';');

            if (codec.MimeType.Equals("audio/opus"))
            {
                OpusParameters opus = new();
                foreach (var token in tokens)
                {
                    var kvp = token.Split('=');
                    if (kvp[0].Equals("useinbandfec"))
                    {
                        opus.UseInbandFec = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("usedtx"))
                    {
                        opus.UsedTx = int.Parse(kvp[1]);
                    }
                }
                codec.Parameters = opus;
            }
            if (codec.MimeType.Equals("video/H264"))
            {
                H264Parameters h264 = new();
                foreach (var token in tokens)
                {
                    var kvp = token.Split('=');
                    if (kvp[0].Equals("packetization-mode"))
                    {
                        h264.PacketizationMode = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("profile-level-id"))
                    {
                        h264.ProfileLevelId = kvp[1];
                    }
                    else if (kvp[0].Equals("level-asymmetry-allowed"))
                    {
                        h264.LevelAsymmetryAllowed = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-start-bitrate"))
                    {
                        h264.XGoogleStartBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-max-bitrate"))
                    {
                        h264.XGoogleMaxBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-min-bitrate"))
                    {
                        h264.XGoogleMinBitrate = int.Parse(kvp[1]);
                    }
                }
                codec.Parameters = h264;
            }
            else if (codec.MimeType.Equals("video/VP8"))
            {
                VP8Parameters vp8 = new();
                foreach (var token in tokens)
                {
                    var kvp = token.Split('=');
                    if (kvp[0].Equals("profile-id"))
                    {
                        vp8.ProfileId = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-start-bitrate"))
                    {
                        vp8.XGoogleStartBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-max-bitrate"))
                    {
                        vp8.XGoogleMaxBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-min-bitrate"))
                    {
                        vp8.XGoogleMinBitrate = int.Parse(kvp[1]);
                    }
                }
                codec.Parameters = vp8;
            }
            else if (codec.MimeType.Equals("video/VP9"))
            {
                VP9Parameters vp9 = new();
                foreach (var token in tokens)
                {
                    var kvp = token.Split('=');
                    if (kvp[0].Equals("profile-id"))
                    {
                        vp9.ProfileId = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-start-bitrate"))
                    {
                        vp9.XGoogleStartBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-max-bitrate"))
                    {
                        vp9.XGoogleMaxBitrate = int.Parse(kvp[1]);
                    }
                    else if (kvp[0].Equals("x-google-min-bitrate"))
                    {
                        vp9.XGoogleMinBitrate = int.Parse(kvp[1]);
                    }
                }
                codec.Parameters = vp9;
            }
            else if (codec.MimeType.Equals("video/rtx"))
            {
                RtxParameters rtx = new();
                foreach (var token in tokens)
                {
                    var kvp = token.Split('=');
                    if (kvp[0].Equals("apt"))
                    {
                        rtx.Apt = int.Parse(kvp[1]);
                    }
                }
                codec.Parameters = rtx;
            }
            else
            {
                codec.Parameters = null;
            }
        }