44using Rtsp . Onvif ;
55using Rtsp . Rtp ;
66using Rtsp . Sdp ;
7+ using SharpSRTP . SRTP ;
78using System ;
89using System . Collections . Generic ;
910using System . Diagnostics ;
1011using System . IO ;
1112using System . Linq ;
1213using System . Net ;
1314using System . Net . Security ;
15+ using System . Numerics ;
1416using System . Text ;
1517
1618namespace SharpRTSPClient
@@ -111,6 +113,9 @@ private enum RtspStatus { WaitingToConnect, Connecting, ConnectFailed, Connected
111113 /// Audio SSRC.
112114 /// </summary>
113115 public uint AudioSSRC { get ; set ; } = ( uint ) _rand . Next ( 20000 , 29999 ) ;
116+
117+ public SrtpSessionContext VideoContext { get ; private set ; }
118+ public SrtpSessionContext AudioContext { get ; private set ; }
114119
115120 static RTSPClient ( )
116121 {
@@ -505,6 +510,13 @@ private void StopClient()
505510 /// <param name="rtcp">RTCP message bytes.</param>
506511 public void SendVideoRTCP ( byte [ ] rtcp )
507512 {
513+ if ( VideoContext != null )
514+ {
515+ byte [ ] rtcpBuffer = new byte [ VideoContext . EncodeRtcpContext . CalculateRequiredSrtcpPayloadLength ( rtcp . Length ) ] ;
516+ VideoContext . EncodeRtcpContext . ProtectRtcp ( rtcpBuffer , rtcp . Length , out int len ) ;
517+ rtcp = rtcpBuffer . Take ( len ) . ToArray ( ) ;
518+ }
519+
508520 _videoRtpTransport . WriteToControlPort ( rtcp ) ;
509521 }
510522
@@ -514,6 +526,13 @@ public void SendVideoRTCP(byte[] rtcp)
514526 /// <param name="rtcp">RTCP message bytes.</param>
515527 public void SendAudioRTCP ( byte [ ] rtcp )
516528 {
529+ if ( AudioContext != null )
530+ {
531+ byte [ ] rtcpBuffer = new byte [ AudioContext . EncodeRtcpContext . CalculateRequiredSrtcpPayloadLength ( rtcp . Length ) ] ;
532+ AudioContext . EncodeRtcpContext . ProtectRtcp ( rtcpBuffer , rtcp . Length , out int len ) ;
533+ rtcp = rtcpBuffer . Take ( len ) . ToArray ( ) ;
534+ }
535+
517536 _audioRtpTransport . WriteToControlPort ( rtcp ) ;
518537 }
519538
@@ -546,7 +565,22 @@ private void VideoRtpDataReceived(object sender, RtspDataEventArgs e)
546565
547566 using ( var data = e . Data )
548567 {
549- var rtpPacket = new RtpPacket ( data . Data . Span ) ;
568+ var rtpData = data . Data ;
569+ if ( VideoContext != null )
570+ {
571+ byte [ ] decoded = rtpData . ToArray ( ) ;
572+ if ( VideoContext . DecodeRtpContext . UnprotectRtp ( decoded , decoded . Length , out var len ) == 0 )
573+ {
574+ rtpData = decoded . Take ( len ) . ToArray ( ) . AsMemory ( ) ;
575+ }
576+ else
577+ {
578+ _logger . LogError ( "Unprotect RTP failed" ) ;
579+ return ;
580+ }
581+ }
582+
583+ var rtpPacket = new RtpPacket ( rtpData . Span ) ;
550584
551585 if ( rtpPacket . PayloadType != _videoPayload )
552586 {
@@ -557,7 +591,7 @@ private void VideoRtpDataReceived(object sender, RtspDataEventArgs e)
557591
558592 ReceivedRawVideoRTP ? . Invoke ( this ,
559593 new RawRtpDataEventArgs (
560- data . Data ,
594+ rtpData ,
561595 rtpPacket . CsrcCount ,
562596 rtpPacket . ExtensionHeaderId ,
563597 rtpPacket . HasPadding ,
@@ -608,8 +642,23 @@ private void AudioRtpDataReceived(object sender, RtspDataEventArgs e)
608642
609643 using ( var data = e . Data )
610644 {
645+ var rtpData = data . Data ;
646+ if ( AudioContext != null )
647+ {
648+ byte [ ] decoded = rtpData . ToArray ( ) ;
649+ if ( AudioContext . DecodeRtpContext . UnprotectRtp ( decoded , decoded . Length , out var len ) == 0 )
650+ {
651+ rtpData = decoded . Take ( len ) . ToArray ( ) . AsMemory ( ) ;
652+ }
653+ else
654+ {
655+ _logger . LogError ( "Unprotect RTP failed" ) ;
656+ return ;
657+ }
658+ }
659+
611660 // Received some Audio Data on the correct channel.
612- var rtpPacket = new RtpPacket ( data . Data . Span ) ;
661+ var rtpPacket = new RtpPacket ( rtpData . Span ) ;
613662
614663 // Check the payload type in the RTP packet matches the Payload Type value from the SDP
615664 if ( rtpPacket . PayloadType != _audioPayload )
@@ -620,7 +669,7 @@ private void AudioRtpDataReceived(object sender, RtspDataEventArgs e)
620669
621670 ReceivedRawAudioRTP ? . Invoke ( this ,
622671 new RawRtpDataEventArgs (
623- data . Data ,
672+ rtpData ,
624673 rtpPacket . CsrcCount ,
625674 rtpPacket . ExtensionHeaderId ,
626675 rtpPacket . HasPadding ,
@@ -666,12 +715,27 @@ private void VideoRtcpControlDataReceived(object sender, RtspDataEventArgs e)
666715
667716 using ( var data = e . Data )
668717 {
669- ReceivedRawVideoRTCP ? . Invoke ( this , new RawRtcpDataEventArgs ( data . Data ) ) ;
718+ var rtcpData = data . Data ;
719+ if ( VideoContext != null )
720+ {
721+ byte [ ] decoded = rtcpData . ToArray ( ) ;
722+ if ( VideoContext . DecodeRtcpContext . UnprotectRtcp ( decoded , decoded . Length , out var len ) == 0 )
723+ {
724+ rtcpData = decoded . Take ( len ) . ToArray ( ) . AsMemory ( ) ;
725+ }
726+ else
727+ {
728+ _logger . LogError ( "Unprotect RTCP failed" ) ;
729+ return ;
730+ }
731+ }
732+
733+ ReceivedRawVideoRTCP ? . Invoke ( this , new RawRtcpDataEventArgs ( rtcpData ) ) ;
670734
671735 if ( ! ProcessRTCP )
672736 return ;
673737
674- var reports = ParseRTCPAndGenerateReponse ( data , VideoSSRC ) ;
738+ var reports = ParseRTCPAndGenerateReponse ( rtcpData , VideoSSRC ) ;
675739 foreach ( var report in reports )
676740 {
677741 ( ( IRtpTransport ) sender ) . WriteToControlPort ( report ) ;
@@ -688,20 +752,35 @@ private void AudioRtcpControlDataReceived(object sender, RtspDataEventArgs e)
688752
689753 using ( var data = e . Data )
690754 {
755+ var rtcpData = data . Data ;
756+ if ( AudioContext != null )
757+ {
758+ byte [ ] decoded = rtcpData . ToArray ( ) ;
759+ if ( AudioContext . DecodeRtcpContext . UnprotectRtcp ( decoded , decoded . Length , out var len ) == 0 )
760+ {
761+ rtcpData = decoded . Take ( len ) . ToArray ( ) . AsMemory ( ) ;
762+ }
763+ else
764+ {
765+ _logger . LogError ( "Unprotect RTCP failed" ) ;
766+ return ;
767+ }
768+ }
769+
691770 ReceivedRawAudioRTCP ? . Invoke ( this , new RawRtcpDataEventArgs ( data . Data ) ) ;
692771
693772 if ( ! ProcessRTCP )
694773 return ;
695774
696- var reports = ParseRTCPAndGenerateReponse ( data , AudioSSRC ) ;
775+ var reports = ParseRTCPAndGenerateReponse ( rtcpData , AudioSSRC ) ;
697776 foreach ( var report in reports )
698777 {
699778 ( ( IRtpTransport ) sender ) . WriteToControlPort ( report ) ;
700779 }
701780 }
702781 }
703782
704- private List < byte [ ] > ParseRTCPAndGenerateReponse ( RtspData data , uint ssrc )
783+ private List < byte [ ] > ParseRTCPAndGenerateReponse ( Memory < byte > data , uint ssrc )
705784 {
706785 List < byte [ ] > reports = new List < byte [ ] > ( ) ;
707786
@@ -714,9 +793,9 @@ private List<byte[]> ParseRTCPAndGenerateReponse(RtspData data, uint ssrc)
714793
715794 // There can be multiple RTCP packets transmitted together. Loop ever each one
716795 int packetIndex = 0 ;
717- var span = data . Data . Span ;
796+ var span = data . Span ;
718797
719- while ( packetIndex < data . Data . Length )
798+ while ( packetIndex < data . Length )
720799 {
721800 //int rtcpVersion = (span[packetIndex + 0] >> 6);
722801 //int rtcpPadding = (span[packetIndex + 0] >> 5) & 0x01;
@@ -1061,7 +1140,7 @@ private void HandleDescribeResponse(RtspResponse message)
10611140 {
10621141 // found a valid codec
10631142 payloadName = rtpmap . EncodingName . ToUpperInvariant ( ) ;
1064- switch ( payloadName )
1143+ switch ( payloadName )
10651144 {
10661145 case "H264" :
10671146 _videoPayloadProcessor = new H264Payload ( _loggerFactory . CreateLogger < H264Payload > ( ) ) ;
@@ -1093,7 +1172,7 @@ private void HandleDescribeResponse(RtspResponse message)
10931172 if ( media . PayloadType < 96 )
10941173 {
10951174 // PayloadType is a static value, so we can use it to determine the codec
1096- switch ( media . PayloadType )
1175+ switch ( media . PayloadType )
10971176 {
10981177 case 26 :
10991178 {
@@ -1166,7 +1245,7 @@ private void HandleDescribeResponse(RtspResponse message)
11661245 byte [ ] pps = vpsSpsPps [ 3 ] ;
11671246 byte [ ] sei = vpsSpsPps [ 4 ] ;
11681247 streamConfigurationData = new H266StreamConfigurationData ( dci , vps , sps , pps , sei ) ;
1169- }
1248+ }
11701249 }
11711250 else if ( _videoPayloadProcessor is AV1Payload && fmtp ? . FormatParameter != null )
11721251 {
@@ -1189,9 +1268,12 @@ private void HandleDescribeResponse(RtspResponse message)
11891268 setupMessage . AddTransport ( transport ) ;
11901269 setupMessage . AddAuthorization ( _authentication , _uri , _rtspSocket . NextCommandIndex ( ) ) ;
11911270 if ( _playbackSession ) { setupMessage . AddRequireOnvifRequest ( ) ; }
1192-
1271+
11931272 // Add SETUP message to list of mesages to send
11941273 _setupMessages . Enqueue ( setupMessage ) ;
1274+
1275+ VideoContext = PrepareSrtpContext ( media ) ;
1276+
11951277 NewVideoStream ? . Invoke ( this , new NewStreamEventArgs ( media . PayloadType , payloadName , streamConfigurationData ) ) ;
11961278 }
11971279 break ;
@@ -1292,6 +1374,9 @@ private void HandleDescribeResponse(RtspResponse message)
12921374 }
12931375 // Add SETUP message to list of mesages to send
12941376 _setupMessages . Enqueue ( setupMessage ) ;
1377+
1378+ AudioContext = PrepareSrtpContext ( media ) ;
1379+
12951380 NewAudioStream ? . Invoke ( this , new NewStreamEventArgs ( media . PayloadType , _audioCodec , streamConfigurationData ) ) ;
12961381 }
12971382 break ;
@@ -1310,6 +1395,62 @@ private void HandleDescribeResponse(RtspResponse message)
13101395 _rtspClient ? . SendMessage ( _setupMessages . Dequeue ( ) ) ;
13111396 }
13121397
1398+ public virtual SrtpSessionContext PrepareSrtpContext ( Media media )
1399+ {
1400+ if ( media . RtpType != null && media . RtpType . EndsWith ( "/SAVP" ) || media . RtpType . EndsWith ( "/SAVPF" ) )
1401+ {
1402+ var crypto = media . Attributs . FirstOrDefault ( x => x . Key == "crypto" ) ;
1403+ if ( crypto != null )
1404+ {
1405+ byte [ ] MKI = null ;
1406+ byte [ ] masterKeySalt = null ;
1407+
1408+ string [ ] cryptoParts = crypto . Value . Split ( ' ' ) ;
1409+ if ( cryptoParts . Length == 3 )
1410+ {
1411+ string cryptoSuite = cryptoParts [ 1 ] ;
1412+
1413+ if ( cryptoParts [ 2 ] . StartsWith ( "inline:" ) )
1414+ {
1415+ string [ ] inlineParts = cryptoParts [ 2 ] . Substring ( 7 ) . Split ( '|' ) ;
1416+ masterKeySalt = Convert . FromBase64String ( inlineParts [ 0 ] ) ;
1417+ if ( inlineParts . Length > 1 )
1418+ {
1419+ if ( inlineParts . Length > 2 )
1420+ {
1421+ string lifetime = inlineParts [ 1 ] ;
1422+ MKI = ParseMKI ( inlineParts [ 2 ] ) ;
1423+ }
1424+ else if ( inlineParts [ 1 ] . Contains ( ':' ) )
1425+ {
1426+ MKI = ParseMKI ( inlineParts [ 1 ] ) ;
1427+ }
1428+ }
1429+
1430+ SrtpKeys keys = SrtpProtocol . CreateMasterKeys ( cryptoSuite , MKI , masterKeySalt ) ;
1431+ return SrtpProtocol . CreateSrtpSessionContext ( keys ) ;
1432+ }
1433+ }
1434+ }
1435+ }
1436+
1437+ return null ;
1438+ }
1439+
1440+ private static byte [ ] ParseMKI ( string sdpMki )
1441+ {
1442+ string [ ] mkiParts = sdpMki . Split ( ':' ) ;
1443+ if ( mkiParts . Length == 2 )
1444+ {
1445+ byte [ ] mkiValue = new BigInteger ( int . Parse ( mkiParts [ 0 ] ) ) . ToByteArray ( ) ;
1446+ byte [ ] MKI = new byte [ int . Parse ( mkiParts [ 1 ] ) ] ;
1447+ Buffer . BlockCopy ( mkiValue , 0 , MKI , 0 , mkiValue . Length ) ;
1448+ return MKI ;
1449+ }
1450+
1451+ return null ;
1452+ }
1453+
13131454 private Uri GetControlUri ( Media media )
13141455 {
13151456 Uri controlUri = null ;
0 commit comments