public bool SendRR(bool isAudio) { if (_forceTcp) { return(true); } /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| RC | PT=RR=201 | length |0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of packet sender |4 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | report | SSRC_1 (SSRC of first source) |8 | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 1 | fraction lost | cumulative number of packets lost |12 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received |16 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter |20 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) |24 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) |28 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | header |V=2|P| SC | PT=SDES=202 | length | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | chunk | SSRC/CSRC_1 | | 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SDES items | | ... | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | chunk | SSRC/CSRC_2 | | 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SDES items | | ... | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ var rtp = isAudio ? _rtpAudio : _rtpVideo; var rtcp = isAudio ? _rtcpAudio : _rtcpVideo; var buffer = isAudio ? _audioRR : _videoRR; //1. prepare the buffer buffer.Write(12, rtp.SSRC); //SSRC_1 (SSRC of first source) buffer.Write(20, rtp.ExtendedSeq); //extended highest sequence number received buffer.Write(28, rtcp.LastSenderReport); //last SR (LSR) if (_forceTcp) { return(_rtsp.SendRaw(buffer)); } else { if (rtcp.LastAddress != null) { if (rtcp.IOHandler.Socket.SendTo(buffer, 4, 56, SocketFlags.None, rtcp.LastAddress) != 56) { FATAL("Unable to send data"); return(false); } } else { //WARN("Skip this RR because we don't have a valid address yet"); } return(true); } }
public bool FeedData(ref MsgHdr message, double absoluteTimestamp, bool isAudio) { if (absoluteTimestamp == 0) { return(true); } double rate = isAudio ? OutStream.Capabilities.Samplerate : 90000.0; var ssrc = isAudio ? OutStream.AudioSSRC : OutStream.VideoSSRC; var messageLength = message.Buffers.Sum(t => t.Length); if (!_rtpClient.hasAudio && !_rtpClient.hasVideo) { return(true); } var packetsCount = isAudio ? _rtpClient.audioPacketsCount : _rtpClient.videoPacketsCount; var bytesCount = isAudio ? _rtpClient.audioBytesCount : _rtpClient.videoBytesCount; var startRTP = isAudio ? _rtpClient.audioStartRTP : _rtpClient.videoStartRTP; if (startRTP == 0xffffffff) { startRTP = message.Buffers[0].ReadUInt(4); if (isAudio) { _rtpClient.audioStartRTP = startRTP; } else { _rtpClient.videoStartRTP = startRTP; } if (isAudio) { _rtpClient.audioStartTS = absoluteTimestamp; } else { _rtpClient.videoStartTS = absoluteTimestamp; } } if ((packetsCount % 500) == 0) { //FINEST("Send %c RTCP: %u", isAudio ? 'A' : 'V', packetsCount); _rtcpMessage.Buffers[0].Write(4, ssrc); //NTP var integerValue = (uint)(absoluteTimestamp / 1000.0); double fractionValue = (absoluteTimestamp / 1000.0 - ((uint)(absoluteTimestamp / 1000.0))) * 4294967296.0; var ntpVal = (ulong)(_startupTime.SecondsFrom1970() + integerValue + 2208988800UL) << 32; ntpVal |= (uint)fractionValue; _rtcpNTP.Buffer.Write(_rtcpNTP.Offset, ntpVal); //RTP var rtp = (ulong)((integerValue + fractionValue / 4294967296.0) * rate); rtp &= 0xffffffff; _rtcpRTP.Buffer.Write(_rtcpRTP.Offset, rtp); //packet count _rtcpSPC.Buffer.Write(_rtcpSPC.Offset, packetsCount); _rtcpSOC.Buffer.Write(_rtcpSOC.Offset, bytesCount); //octet count // FINEST("\n%s", STR(IOBuffer::DumpBuffer(((uint8_t *) _rtcpMessage.MSGHDR_MSG_IOV[0].IOVEC_IOV_BASE), // _rtcpMessage.MSGHDR_MSG_IOV[0].IOVEC_IOV_LEN))); if (_rtpClient.isUdp) { var rtcpSocket = isAudio ? _audioRTCPSocket : _videoRTCPSocket; var rtcpAddress = isAudio ? _rtpClient.audioRtcpAddress : _rtpClient.videoRtcpAddress; if (rtcpSocket.SendTo(_rtcpMessage.TotalBuffer, SocketFlags.None, rtcpAddress) < 0) { FATAL("Unable to send message"); return(false); } } else { if (_rtspProtocol != null) { if (!_rtspProtocol.SendRaw(_rtcpMessage, ref _rtpClient, isAudio, false)) { FATAL("Unable to send raw rtcp audio data"); return(false); } } } } if (_rtpClient.isUdp) { var dataFd = isAudio ? _audioDataSocket : _videoDataSocket; var dataAddress = isAudio ? _rtpClient.audioDataAddress : _rtpClient.videoDataAddress; if (dataFd.SendTo(message.TotalBuffer, SocketFlags.None, dataAddress) < 0) { FATAL("Unable to send message"); return(false); } } else { if (_rtspProtocol != null) { if (!_rtspProtocol.SendRaw(message, ref _rtpClient, isAudio, true)) { FATAL("Unable to send raw rtcp audio data"); return(false); } } } packetsCount++; if (isAudio) { _rtpClient.audioPacketsCount = packetsCount; } else { _rtpClient.videoPacketsCount = packetsCount; } bytesCount += (uint)messageLength; if (isAudio) { _rtpClient.audioBytesCount = bytesCount; } else { _rtpClient.videoBytesCount = bytesCount; } return(true); }