@@ -560,7 +560,7 @@ public void FeedInRawVideoSamples(uint rtpTimestamp, List<byte[]> samples)
560560 // The last packet will have the M bit set to '1'
561561 ( List < Memory < byte > > rtpPackets , List < IMemoryOwner < byte > > memoryOwners ) = VideoTrack . CreateRtpPackets ( samples , rtpTimestamp ) ;
562562
563- FeedInRawRTP ( RTSPConnection . VIDEO , rtpTimestamp , rtpPackets ) ;
563+ FeedInRawVideoRTP ( rtpTimestamp , rtpPackets ) ;
564564
565565 foreach ( var owner in memoryOwners )
566566 {
@@ -584,87 +584,111 @@ public void FeedInRawAudioSamples(uint rtpTimestamp, List<byte[]> samples)
584584 // The last packet will have the M bit set to '1'
585585 ( List < Memory < byte > > rtpPackets , List < IMemoryOwner < byte > > memoryOwners ) = AudioTrack . CreateRtpPackets ( samples , rtpTimestamp ) ;
586586
587- FeedInRawRTP ( RTSPConnection . AUDIO , rtpTimestamp , rtpPackets ) ;
587+ FeedInRawAudioRTP ( rtpTimestamp , rtpPackets ) ;
588588
589589 foreach ( var owner in memoryOwners )
590590 {
591591 owner . Dispose ( ) ;
592592 }
593593 }
594594
595- public void FeedInRawRTP ( int streamType , uint rtpTimestamp , List < Memory < byte > > rtpPackets )
595+ public void FeedInRawVideoRTP ( uint rtpTimestamp , List < Memory < byte > > rtpPackets )
596596 {
597+ SendRTP ( RTSPConnection . VIDEO , rtpTimestamp , rtpPackets ) ;
598+ }
599+
600+ public void FeedInRawAudioRTP ( uint rtpTimestamp , List < Memory < byte > > rtpPackets )
601+ {
602+ SendRTP ( RTSPConnection . AUDIO , rtpTimestamp , rtpPackets ) ;
603+ }
604+
605+ private void SendRTP ( int streamType , uint rtpTimestamp , List < Memory < byte > > rtpPackets )
606+ {
607+ if ( streamType != 0 && streamType != 1 )
608+ throw new ArgumentException ( "Invalid streamType! Video = 0, Audio = 1" ) ;
609+
597610 lock ( _connectionList )
598611 {
599612 // Go through each RTSP connection and output the RTP on the Session
600613 foreach ( RTSPConnection connection in _connectionList . ToArray ( ) ) // ToArray makes a temp copy of the list. This lets us delete items in the foreach eg when there is Write Error
601614 {
602615 // Only process Sessions in Play Mode
603616 if ( ! connection . Play )
604- continue ;
617+ return ;
618+
619+ var stream = connection . Streams [ streamType ] ;
605620
606- if ( connection . Streams [ streamType ] . RtpChannel == null )
607- continue ;
621+ if ( stream . RtpChannel == null )
622+ return ;
608623
609624 _logger . LogDebug ( "Sending RTP session {sessionId} {TransportLogName} RTP timestamp={rtpTimestamp}. Sequence={sequenceNumber}" ,
610- connection . SessionId , TransportLogName ( connection . Streams [ streamType ] . RtpChannel ) , rtpTimestamp , connection . Streams [ streamType ] . SequenceNumber ) ;
625+ connection . SessionId , TransportLogName ( stream . RtpChannel ) , rtpTimestamp , stream . SequenceNumber ) ;
611626
612- if ( connection . Streams [ streamType ] . MustSendRtcpPacket )
627+ if ( stream . MustSendRtcpPacket )
613628 {
614- if ( ! SendRTCP ( rtpTimestamp , connection , connection . Streams [ streamType ] ) )
629+ if ( ! SendRTCP ( rtpTimestamp , connection , stream ) )
615630 {
616631 RemoveSession ( connection ) ;
632+ continue ;
617633 }
618634 }
619635
620- bool writeError = false ;
621- uint writtenBytes = 0 ;
622- // There could be more than 1 RTP packet (if the data is fragmented)
623- foreach ( var rtpPacket in rtpPackets )
624- {
625- // Add the specific data for each transmission
626- RTPPacketUtil . WriteSequenceNumber ( rtpPacket . Span , connection . Streams [ streamType ] . SequenceNumber ) ;
627- connection . Streams [ streamType ] . SequenceNumber ++ ;
636+ SendRawRTP ( connection , stream , rtpPackets ) ;
637+ }
638+ }
639+ }
628640
629- // Add the specific SSRC for each transmission
630- RTPPacketUtil . WriteSSRC ( rtpPacket . Span , connection . SSRC ) ;
641+ public void SendRawRTP ( RTSPConnection connection , RTPStream stream , List < Memory < byte > > rtpPackets )
642+ {
643+ if ( ! connection . Play )
644+ return ;
631645
632- //Debug.Assert(connection.Streams[streamType].RtpChannel != null, "If connection.Streams[streamType].RtpChannel is null here the program did not handle well connection problem");
633- try
634- {
635- // send the whole NAL. ** We could fragment the RTP packet into smaller chuncks that fit within the MTU
636- // Send to the IP address of the Client
637- // Send to the UDP Port the Client gave us in the SETUP command
638- var channel = connection . Streams [ streamType ] . RtpChannel ;
639- if ( channel != null )
640- {
641- channel . WriteToDataPort ( rtpPacket . Span ) ;
642- writtenBytes += ( uint ) rtpPacket . Span . Length ;
643- }
644- else
645- {
646- writeError = true ;
647- }
648- }
649- catch ( Exception e )
650- {
651- _logger . LogWarning ( "UDP Write Exception " + e ) ;
652- writeError = true ;
653- break ; // exit out of foreach loop
654- }
655- }
646+ bool writeError = false ;
647+ uint writtenBytes = 0 ;
648+ // There could be more than 1 RTP packet (if the data is fragmented)
649+ foreach ( var rtpPacket in rtpPackets )
650+ {
651+ // Add the specific data for each transmission
652+ RTPPacketUtil . WriteSequenceNumber ( rtpPacket . Span , stream . SequenceNumber ) ;
653+ stream . SequenceNumber ++ ;
654+
655+ // Add the specific SSRC for each transmission
656+ RTPPacketUtil . WriteSSRC ( rtpPacket . Span , connection . SSRC ) ;
656657
657- if ( writeError )
658+ //Debug.Assert(connection.Streams[streamType].RtpChannel != null, "If connection.Streams[streamType].RtpChannel is null here the program did not handle well connection problem");
659+ try
660+ {
661+ // send the whole NAL. ** We could fragment the RTP packet into smaller chuncks that fit within the MTU
662+ // Send to the IP address of the Client
663+ // Send to the UDP Port the Client gave us in the SETUP command
664+ var channel = stream . RtpChannel ;
665+ if ( channel != null )
658666 {
659- _logger . LogWarning ( "Error writing to listener " + connection . Listener . RemoteAdress ) ;
660- _logger . LogWarning ( "Removing session " + connection . SessionId + " due to write error" ) ;
661- RemoveSession ( connection ) ;
667+ channel . WriteToDataPort ( rtpPacket . Span ) ;
668+ writtenBytes += ( uint ) rtpPacket . Span . Length ;
662669 }
663670 else
664671 {
665- connection . Streams [ streamType ] . OctetCount += writtenBytes ;
672+ writeError = true ;
666673 }
667674 }
675+ catch ( Exception e )
676+ {
677+ _logger . LogWarning ( "UDP Write Exception " + e ) ;
678+ writeError = true ;
679+ break ; // exit out of foreach loop
680+ }
681+ }
682+
683+ if ( writeError )
684+ {
685+ _logger . LogWarning ( "Error writing to listener " + connection . Listener . RemoteAdress ) ;
686+ _logger . LogWarning ( "Removing session " + connection . SessionId + " due to write error" ) ;
687+ RemoveSession ( connection ) ;
688+ }
689+ else
690+ {
691+ stream . OctetCount += writtenBytes ;
668692 }
669693 }
670694
@@ -678,26 +702,30 @@ private bool SendRTCP(uint rtpTimestamp, RTSPConnection connection, RTPStream st
678702 int length = ( rtcpSenderReport . Length / 4 ) - 1 ; // num 32 bit words minus 1
679703 RTCPUtils . WriteRTCPHeader ( rtcpSenderReport , RTCPUtils . RTCP_VERSION , hasPadding , reportCount , RTCPUtils . RTCP_PACKET_TYPE_SENDER_REPORT , length , connection . SSRC ) ;
680704 RTCPUtils . WriteSenderReport ( rtcpSenderReport , DateTime . UtcNow , rtpTimestamp , stream . RtpPacketCount , stream . OctetCount ) ;
681-
682- try
683- {
684- Debug . Assert ( stream . RtpChannel != null , "If stream.rtpChannel is null here the program did not handle well connection problem" ) ;
685- // Send to the IP address of the Client
686- // Send to the UDP Port the Client gave us in the SETUP command
687- stream . RtpChannel . WriteToControlPort ( rtcpSenderReport ) ;
688- }
689- catch ( Exception e )
690- {
691- _logger . LogError ( e , "Error writing RTCP to listener {remoteAdress}" , connection . Listener . RemoteAdress ) ;
692- return false ;
693- }
694- return true ;
705+ return SendRawRTCP ( connection , stream , rtcpSenderReport ) ;
695706
696707 // Clear the flag. A timer may set this to True again at some point to send regular Sender Reports
697708 //HACK connection.must_send_rtcp_packet = false; // A Timer may set this to true again later in case it is used as a Keepalive (eg IndigoVision)
698709 }
699710 }
700711
712+ public bool SendRawRTCP ( RTSPConnection connection , RTPStream stream , Span < byte > rtcpSenderReport )
713+ {
714+ try
715+ {
716+ Debug . Assert ( stream . RtpChannel != null , "If stream.rtpChannel is null here the program did not handle well connection problem" ) ;
717+ // Send to the IP address of the Client
718+ // Send to the UDP Port the Client gave us in the SETUP command
719+ stream . RtpChannel . WriteToControlPort ( rtcpSenderReport ) ;
720+ }
721+ catch ( Exception e )
722+ {
723+ _logger . LogError ( e , "Error writing RTCP to listener {remoteAdress}" , connection . Listener . RemoteAdress ) ;
724+ return false ;
725+ }
726+ return true ;
727+ }
728+
701729 private void RemoveSession ( RTSPConnection connection )
702730 {
703731 connection . Play = false ; // stop sending data
0 commit comments