|
@@ -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
|