Browse Source

Adds fraction and packet lost calculation in RR packets

dledanseur 1 month ago
parent
commit
dbdbde565a
4 changed files with 118 additions and 11 deletions
  1. 16 0
      include/rtc/rtcpreceivingsession.hpp
  2. 1 1
      include/rtc/rtp.hpp
  3. 91 1
      src/rtcpreceivingsession.cpp
  4. 10 9
      src/rtp.cpp

+ 16 - 0
include/rtc/rtcpreceivingsession.hpp

@@ -19,6 +19,8 @@
 
 #include <atomic>
 
+#define RTP_SEQ_MOD (1<<16)
+
 namespace rtc {
 
 // An RtcpSession can be plugged into a Track to handle the whole RTCP session
@@ -40,8 +42,22 @@ protected:
 	void pushRR(const message_callback &send,unsigned int lastSrDelay);
 	void pushPLI(const message_callback &send);
 
+	void initSeq(uint16_t seq);
+	bool updateSeq(uint16_t seq);
+	
 	SSRC mSsrc = 0;
 	uint32_t mGreatestSeqNo = 0;
+    uint16_t mMaxSeq = 0;			// highest seq. number seen
+    uint32_t mCycles = 0;			// shifted count of seq. number cycles
+	uint32_t mBaseSeq = 0;			// base seq number
+    uint32_t mBadSeq = 0;			// last 'bad' seq number + 1
+	uint32_t mProbation = 0;		// sequ. packets till source is valid
+    uint32_t mReceived = 0;			// packets received
+    uint32_t mExpectedPrior = 0;	// packet expected at last interval
+    uint32_t mReceivedPrior = 0;	// packet received at last interval
+	uint32_t mTransit = 0;			// relative trans time for prev pkt
+	uint32_t mJitter = 0;	
+	
 	uint64_t mSyncRTPTS, mSyncNTPTS;
 
 	std::atomic<unsigned int> mRequestedBitrate = 0;

+ 1 - 1
include/rtc/rtp.hpp

@@ -102,7 +102,7 @@ struct RTC_CPP_EXPORT RtcpReportBlock {
 	[[nodiscard]] uint8_t getFractionLost() const;
 	[[nodiscard]] unsigned int getPacketsLostCount() const;
 
-	void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets,
+	void preparePacket(SSRC in_ssrc, uint8_t fraction, unsigned int totalPacketsLost,
 	                   uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter,
 	                   uint64_t lastSR_NTP, uint64_t lastSR_DELAY);
 	void setSSRC(SSRC in_ssrc);

+ 91 - 1
src/rtcpreceivingsession.cpp

@@ -59,6 +59,9 @@ void RtcpReceivingSession::incoming(message_vector &messages, const message_call
 			}
 
 			mSsrc = rtp->ssrc();
+
+			updateSeq(rtp->seqNumber());
+
 			result.push_back(std::move(message));
 			break;
 		}
@@ -110,7 +113,31 @@ void RtcpReceivingSession::pushRR(const message_callback &send, unsigned int las
 	auto message = make_message(RtcpRr::SizeWithReportBlocks(1), Message::Control);
 	auto rr = reinterpret_cast<RtcpRr *>(message->data());
 	rr->preparePacket(mSsrc, 1);
-	rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS,
+
+	// calculate packets lost, packet expected, fraction
+	auto extended_max = mCycles + mMaxSeq;
+    auto expected = extended_max - mBaseSeq + 1;
+	auto lost = 0;
+	if (mReceived > 0) {
+		lost = expected - mReceived;
+	} 
+
+	auto expected_interval = expected - mExpectedPrior;
+    mExpectedPrior = expected;
+    auto received_interval = mReceived - mReceivedPrior;
+    mReceivedPrior = mReceived;
+    auto lost_interval = expected_interval - received_interval;
+
+	uint8_t fraction;
+
+	if (expected_interval == 0 || lost_interval <= 0) {  
+		fraction = 0;
+	}	
+	else { 
+		fraction = (lost_interval << 8) / expected_interval;
+	}
+
+	rr->getReportBlock(0)->preparePacket(mSsrc, fraction, lost, uint16_t(mGreatestSeqNo), mMaxSeq, 0, mSyncNTPTS,
 	                                     lastSrDelay);
 	rr->log();
 	send(message);
@@ -128,6 +155,69 @@ void RtcpReceivingSession::pushPLI(const message_callback &send) {
 	send(message);
 }
 
+void RtcpReceivingSession::initSeq(uint16_t seq) {
+	mBaseSeq = seq;
+	mMaxSeq = seq;
+	mBadSeq = RTP_SEQ_MOD + 1;   /* so seq == bad_seq is false */
+	mCycles = 0;
+	mReceived = 0;
+	mReceivedPrior = 0;
+	mExpectedPrior = 0;
+}
+
+bool RtcpReceivingSession::updateSeq(uint16_t seq) {
+	uint16_t udelta = seq - mMaxSeq;
+	const int MAX_DROPOUT = 3000;
+	const int MAX_MISORDER = 100;
+	const int MIN_SEQUENTIAL = 2;
+
+	/*
+	* Source is not valid until MIN_SEQUENTIAL packets with
+	* sequential sequence numbers have been received.
+	*/
+	if (mProbation) {
+		/* packet is in sequence */
+		if (seq == mMaxSeq + 1) {
+			mProbation--;
+			mMaxSeq = seq;
+			if (mProbation == 0) {
+				initSeq(seq);
+				mReceived++;
+				return true;
+			}
+		} else {
+			mProbation = MIN_SEQUENTIAL - 1;
+			mMaxSeq = seq;
+		}
+		return false;
+	} else if (udelta < MAX_DROPOUT) {
+		/* in order, with permissible gap */
+		if (seq < mMaxSeq) {
+			/*
+			* Sequence number wrapped - count another 64K cycle.
+			*/
+			mCycles += RTP_SEQ_MOD;
+		}
+		mMaxSeq = seq;
+	} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
+		/* the sequence number made a very large jump */
+		if (seq == mBadSeq) {
+			/*
+			* Two sequential packets -- assume that the other side
+			* restarted without telling us so just re-sync
+			* (i.e., pretend this was the first packet).
+			*/
+			initSeq(seq);
+		}
+		else {
+			mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1);
+			return false;
+		}
+	}
+	mReceived++;
+	return true;
+}
+
 } // namespace rtc
 
 #endif // RTC_ENABLE_MEDIA

+ 10 - 9
src/rtp.cpp

@@ -174,14 +174,16 @@ size_t RtpExtensionHeader::writeHeader(bool twoByteHeader, size_t offset, uint8_
 
 SSRC RtcpReportBlock::getSSRC() const { return ntohl(_ssrc); }
 
-void RtcpReportBlock::preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost,
-                                    [[maybe_unused]] unsigned int totalPackets,
+void RtcpReportBlock::preparePacket(SSRC in_ssrc, uint8_t fraction,
+                                	uint32_t totalPacketsLost,
                                     uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter,
                                     uint64_t lastSR_NTP, uint64_t lastSR_DELAY) {
 	setSeqNo(highestSeqNo, seqNoCycles);
 	setJitter(jitter);
 	setSSRC(in_ssrc);
 
+	setPacketsLost(fraction, totalPacketsLost);
+	
 	// Middle 32 bits of NTP Timestamp
 	// _lastReport = lastSR_NTP >> 16u;
 	setNTPOfSR(uint64_t(lastSR_NTP));
@@ -194,18 +196,18 @@ void RtcpReportBlock::preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int
 void RtcpReportBlock::setSSRC(SSRC in_ssrc) { _ssrc = htonl(in_ssrc); }
 
 void RtcpReportBlock::setPacketsLost(uint8_t fractionLost,
-                                     unsigned int packetsLostCount) {
+                                     uint32_t packetsLostCount) {
 	_fractionLostAndPacketsLost = htonl((uint32_t(fractionLost) << 24) | (packetsLostCount & 0xFFFFFF));
 }
 
 uint8_t RtcpReportBlock::getFractionLost() const {
 	// Fraction lost is expressed as 8-bit fixed point number
 	// In order to get actual lost percentage divide the result by 256
-	return _fractionLostAndPacketsLost & 0xFF;
+	return (uint8_t) ((ntohl(_fractionLostAndPacketsLost) & 0xFF00000) >> 24);
 }
 
-unsigned int RtcpReportBlock::getPacketsLostCount() const {
-	return ntohl(_fractionLostAndPacketsLost & 0xFFFFFF00);
+uint32_t RtcpReportBlock::getPacketsLostCount() const {
+	return ntohl(_fractionLostAndPacketsLost) & 0x00FFFFFF;
 }
 
 uint16_t RtcpReportBlock::seqNoCycles() const { return ntohs(_seqNoCycles); }
@@ -238,9 +240,8 @@ void RtcpReportBlock::log() const {
 	PLOG_VERBOSE << "RTCP report block: "
 	             << "ssrc="
 	             << ntohl(_ssrc)
-	             // TODO: Implement these reports
-	             //	<< ", fractionLost=" << fractionLost
-	             //	<< ", packetsLost=" << packetsLost
+	             	<< ", fractionLost=" << (uint32_t)getFractionLost()
+	             	<< ", packetsLost=" << getPacketsLostCount()
 	             << ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles()
 	             << ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR()
 	             << ", lastSRDelay=" << delaySinceSR();