public void Parse_TestData_ReturnsValidFrame()
        {
            var testCodecInfo = new AACCodecInfo
            {
                ConfigBytes      = new byte[] { 20, 8 },
                IndexDeltaLength = 3,
                IndexLength      = 3,
                SizeLength       = 13
            };

            byte[] testBytes = Convert.FromBase64String(
                "ABAPyAE2Nay0eJ0OEMF4cOFyZeskqICVBWXLiAFDYHBG3GXFf0r/3nn+pRYcsdweO8Pzlxhjm0Q5QrEf7jx31b1PX8VuZOcZZ516jVY6sW/ISf8SQb6fONzpYJLiNRi7SO1o+" +
                "ByL8qHHiUeF9EoqyQ1VgamBApL8XaznlKoszkm9Td02961s0SznSmtSZcuhaEYCZaPe1k5qM+U3wHzs3CCnWMSNsK9UNCq1dzSm4YZWRkJPIY4oXJXsSCW67r8Xdb4slBDvxqu709z" +
                "ggyqrTuoOtkR3aHhFs6JHL8QwVgiusj39H8FrZ8Nu3Dt3qu0NQo5KpHN4R1jn2G71VHMfJwGEwZisU2e9Pz3h316dvpt97XbNcxLTgUCz9UpleUNXWAeygFCrPGTpWFv1Qn3JxS4W1xI" +
                "W5W/dHymYM5ElSMhtF+PFounb/IKbxKJThTUkxx3FWwYt00q7nMOilx2t6odQue/bTaENXKw304l1X5aiEl2S4+C0pIEzkHpbMp+5bmLw1+M8FNRkzlEngnPPATaJQSNOqTHTwVmK+" +
                "fAVSESminLM1TAOg0EZUw0pLTl3ka+scMp9kmxkFKLr3YRip0Uy0JMSnfefWxGezotf3sbV4afJZrnuVnKyanaK33korbN4LMIhvBgAAAAAAAAAAAAAAAAAAAAAAAAAA70=");

            byte[] frameBytes = Convert.FromBase64String(
                "ATY1rLR4nQ4QwXhw4XJl6ySogJUFZcuIAUNgcEbcZcV/Sv/eef6lFhyx3B47w/OXGGObRDlCsR/uPHfVvU9fxW5k5xlnnXqNVjqxb8hJ/xJBvp843OlgkuI1GLtI7Wj4HIvyoce" +
                "JR4X0SirJDVWBqYECkvxdrOeUqizOSb1N3Tb3rWzRLOdKa1Jly6FoRgJlo97WTmoz5TfAfOzcIKdYxI2wr1Q0KrV3NKbhhlZGQk8hjihclexIJbruvxd1viyUEO/Gq7vT3OCDKqtO6" +
                "g62RHdoeEWzokcvxDBWCK6yPf0fwWtnw27cO3eq7Q1Cjkqkc3hHWOfYbvVUcx8nAYTBmKxTZ70/PeHfXp2+m33tds1zEtOBQLP1SmV5Q1dYB7KAUKs8ZOlYW/VCfcnFLhbXEhblb90f" +
                "KZgzkSVIyG0X48Wi6dv8gpvEolOFNSTHHcVbBi3TSrucw6KXHa3qh1C579tNoQ1crDfTiXVflqISXZLj4LSkgTOQelsyn7luYvDX4zwU1GTOUSeCc88BNolBI06pMdPBWYr58BVIRKaK" +
                "cszVMA6DQRlTDSktOXeRr6xwyn2SbGQUouvdhGKnRTLQkxKd959bEZ7Oi1/extXhp8lmue5WcrJqdorfeSits3gswiG8GAAAAAAAAAAAAAAAAAAAAAAAAAADvQ==");

            RawAACFrame frame  = null;
            var         parser = new AACAudioPayloadParser(testCodecInfo);

            parser.FrameGenerated = rawFrame => frame = (RawAACFrame)rawFrame;
            parser.Parse(TimeSpan.Zero, new ArraySegment <byte>(testBytes), true);

            Assert.IsNotNull(frame);
            Assert.AreEqual(FrameType.Audio, frame.Type);
            Assert.IsTrue(frame.ConfigSegment.SequenceEqual(testCodecInfo.ConfigBytes));
            Assert.IsTrue(frame.FrameSegment.SequenceEqual(frameBytes));
        }
        public void Parse_SDPWithAACTrack_ReturnsWithAACCodecTrack()
        {
            var    configBytes = new byte[] { 0x12, 0x10 };
            string testInput   = "m=audio 0 RTP/AVP 96\r\n" +
                                 "b=AS:128\r\n" +
                                 "a=rtpmap:96 MPEG4-GENERIC/44100/2\r\n" +
                                 "a=fmtp:96 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=1210\r\n" +
                                 "a=control:streamid=0\r\n";

            var testBytes = Encoding.ASCII.GetBytes(testInput);

            var parser = new SdpParser();
            RtspMediaTrackInfo audioTrack = parser.Parse(testBytes).Where(t => t is RtspMediaTrackInfo)
                                            .Cast <RtspMediaTrackInfo>().First();

            AACCodecInfo codecInfo = (AACCodecInfo)audioTrack.Codec;

            Assert.AreEqual(3, codecInfo.IndexDeltaLength);
            Assert.AreEqual(3, codecInfo.IndexLength);
            Assert.AreEqual(13, codecInfo.SizeLength);
            Assert.IsTrue(configBytes.SequenceEqual(codecInfo.ConfigBytes));
        }
        private static void ParseAACFormatAttributes(string[] formatAttributes, AACCodecInfo aacCodecInfo)
        {
            string sizeLengthParameter = formatAttributes.FirstOrDefault(fa =>
                                                                         fa.StartsWith("sizeLength", StringComparison.InvariantCultureIgnoreCase));

            if (sizeLengthParameter == null)
            {
                throw new SdpParserException("SizeLength parameters is not found");
            }

            string indexLengthParameter = formatAttributes.FirstOrDefault(fa =>
                                                                          fa.StartsWith("indexLength", StringComparison.InvariantCultureIgnoreCase));

            if (indexLengthParameter == null)
            {
                throw new SdpParserException("IndexLength parameters is not found");
            }

            string indexDeltaLengthParameter = formatAttributes.FirstOrDefault(fa =>
                                                                               fa.StartsWith("indexDeltaLength", StringComparison.InvariantCultureIgnoreCase));

            if (indexDeltaLengthParameter == null)
            {
                throw new SdpParserException("IndexDeltaLength parameters is not found");
            }

            aacCodecInfo.SizeLength       = int.Parse(GetFormatParameterValue(sizeLengthParameter));
            aacCodecInfo.IndexLength      = int.Parse(GetFormatParameterValue(indexLengthParameter));
            aacCodecInfo.IndexDeltaLength = int.Parse(GetFormatParameterValue(indexDeltaLengthParameter));

            string configParameter = formatAttributes.FirstOrDefault(fa =>
                                                                     fa.StartsWith("config", StringComparison.InvariantCultureIgnoreCase));

            if (configParameter != null)
            {
                aacCodecInfo.ConfigBytes = Hex.StringToByteArray(GetFormatParameterValue(configParameter));
            }
        }
        public void Parse_TestData_ReturnsValidFrame()
        {
            var testCodecInfo = new AACCodecInfo
            {
                ConfigBytes      = new byte[] { 20, 8 },
                IndexDeltaLength = 3,
                IndexLength      = 3,
                SizeLength       = 13
            };

            byte[] testBytes = Convert.FromBase64String(
                "ABAPyAE2Nay0eJ0OEMF4cOFyZeskqICVBWXLiAFDYHBG3GXFf0r/3nn+pRYcsdweO8Pzlxhjm0Q5QrEf7jx31b1PX8VuZOcZZ516jVY6sW/ISf8SQb6fONzpYJLiNRi7SO1o+" +
                "ByL8qHHiUeF9EoqyQ1VgamBApL8XaznlKoszkm9Td02961s0SznSmtSZcuhaEYCZaPe1k5qM+U3wHzs3CCnWMSNsK9UNCq1dzSm4YZWRkJPIY4oXJXsSCW67r8Xdb4slBDvxqu709z" +
                "ggyqrTuoOtkR3aHhFs6JHL8QwVgiusj39H8FrZ8Nu3Dt3qu0NQo5KpHN4R1jn2G71VHMfJwGEwZisU2e9Pz3h316dvpt97XbNcxLTgUCz9UpleUNXWAeygFCrPGTpWFv1Qn3JxS4W1xI" +
                "W5W/dHymYM5ElSMhtF+PFounb/IKbxKJThTUkxx3FWwYt00q7nMOilx2t6odQue/bTaENXKw304l1X5aiEl2S4+C0pIEzkHpbMp+5bmLw1+M8FNRkzlEngnPPATaJQSNOqTHTwVmK+" +
                "fAVSESminLM1TAOg0EZUw0pLTl3ka+scMp9kmxkFKLr3YRip0Uy0JMSnfefWxGezotf3sbV4afJZrnuVnKyanaK33korbN4LMIhvBgAAAAAAAAAAAAAAAAAAAAAAAAAA70=");

            byte[] frameBytes = Convert.FromBase64String(
                "D8gBNjWstHidDhDBeHDhcmXrJKiAlQVly4gBQ2BwRtxlxX9K/955/qUWHLHcHjvD85cYY5tEOUKxH+48d9W9T1/FbmTnGWedeo1" +
                "WOrFvyEn/EkG+nzjc6WCS4jUYu0jtaPgci/Khx4lHhfRKKskNVYGpgQKS/F2s55SqLM5JvU3dNvetbNEs50prUmXLoWhGAmWj3tZO" +
                "ajPlN8B87Nwgp1jEjbCvVDQqtXc0puGGVkZCTyGOKFyV7Egluu6/F3W+LJQQ78aru9Pc4IMqq07qDrZEd2h4RbOiRy/EMFYIrrI9/R/" +
                "Ba2fDbtw7d6rtDUKOSqRzeEdY59hu9VRzHycBhMGYrFNnvT894d9enb6bfe12zXMS04FAs/VKZXlDV1gHsoBQqzxk6Vhb9UJ9ycUuFt" +
                "cSFuVv3R8pmDORJUjIbRfjxaLp2/yCm8SiU4U1JMcdxVsGLdNKu5zDopcdreqHULnv202hDVysN9OJdV+WohJdkuPgtKSBM5B6WzKfuW" +
                "5i8NfjPBTUZM5RJ4JzzwE2iUEjTqkx08FZivnwFUhEpopyzNUwDoNBGVMNKS05d5GvrHDKfZJsZBSi692EYqdFMtCTEp33n1sRns6LX97" +
                "G1eGnyWa57lZysmp2it95KK2zeCzCIbwYAAAAAAAAAAAAAAAAAAAAAAAAAA==");

            RawAACFrame frame  = null;
            var         parser = new AACAudioPayloadParser(testCodecInfo);

            parser.FrameGenerated = rawFrame => frame = (RawAACFrame)rawFrame;
            parser.Parse(TimeSpan.Zero, new ArraySegment <byte>(testBytes), true);

            Assert.IsNotNull(frame);
            Assert.AreEqual(FrameType.Audio, frame.Type);
            Assert.IsTrue(frame.ConfigSegment.SequenceEqual(testCodecInfo.ConfigBytes));
            Assert.IsTrue(frame.FrameSegment.SequenceEqual(frameBytes));
        }
 public AACAudioPayloadParser(AACCodecInfo codecInfo)
 {
     _codecInfo = codecInfo ?? throw new ArgumentNullException(nameof(codecInfo));
 }