Merge "VT: Introduce dynamic jitter buffer for RTP source" am: d71f5042a0 am: bc97850159 am: 1aaaf2b87c
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1652258
Change-Id: I1fb9ef3bdec27b82d45d96f11eb7f5f889f0a400
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index b43df38..d2d978a 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -124,8 +124,16 @@
// index(i) should be started from 1. 0 is reserved for [root]
mRTPConn->addStream(sockRtp, sockRtcp, desc, i + 1, notify, false);
mRTPConn->setSelfID(info->mSelfID);
- mRTPConn->setJbTime(
- (info->mJbTimeMs <= 3000 && info->mJbTimeMs >= 40) ? info->mJbTimeMs : 300);
+ mRTPConn->setStaticJitterTimeMs(info->mJbTimeMs);
+
+ unsigned long PT;
+ AString formatDesc, formatParams;
+ // index(i) should be started from 1. 0 is reserved for [root]
+ desc->getFormatType(i + 1, &PT, &formatDesc, &formatParams);
+
+ int32_t clockRate, numChannels;
+ ASessionDescription::ParseFormatDesc(formatDesc.c_str(), &clockRate, &numChannels);
+ info->mTimeScale = clockRate;
info->mRTPSocket = sockRtp;
info->mRTCPSocket = sockRtcp;
@@ -146,10 +154,8 @@
if (info->mIsAudio) {
mAudioTrack = source;
- info->mTimeScale = 16000;
} else {
mVideoTrack = source;
- info->mTimeScale = 90000;
}
info->mSource = source;
@@ -680,7 +686,7 @@
newTrackInfo.mIsAudio = isAudioKey;
mTracks.push(newTrackInfo);
info = &mTracks.editTop();
- info->mJbTimeMs = 300;
+ info->mJbTimeMs = kStaticJitterTimeMs;
}
if (key == "rtp-param-mime-type") {
@@ -724,7 +730,8 @@
int64_t networkHandle = atoll(value);
setSocketNetwork(networkHandle);
} else if (key == "rtp-param-jitter-buffer-time") {
- info->mJbTimeMs = atoi(value);
+ // clamping min at 40, max at 3000
+ info->mJbTimeMs = std::min(std::max(40, atoi(value)), 3000);
}
return OK;
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index 2f93d5d..92b2b09 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -34,6 +34,8 @@
namespace android {
+const double JITTER_MULTIPLE = 1.5f;
+
// static
AAVCAssembler::AAVCAssembler(const sp<AMessage> ¬ify)
: mNotifyMsg(notify),
@@ -123,22 +125,48 @@
int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
- int64_t startTime = source->mFirstSysTime / 1000;
- int64_t nowTime = ALooper::GetNowUs() / 1000;
- int64_t playedTime = nowTime - startTime;
+ const int64_t startTimeMs = source->mFirstSysTime / 1000;
+ const int64_t nowTimeMs = ALooper::GetNowUs() / 1000;
+ const int64_t staticJbTimeMs = source->getStaticJitterTimeMs();
+ const int64_t dynamicJbTimeMs = source->getDynamicJitterTimeMs();
+ const int64_t clockRate = source->mClockRate;
- int64_t playedTimeRtp = source->mFirstRtpTime + playedTime * (int64_t)source->mClockRate / 1000;
- const int64_t jitterTime = source->mJbTimeMs * (int64_t)source->mClockRate / 1000;
+ int64_t playedTimeMs = nowTimeMs - startTimeMs;
+ int64_t playedTimeRtp = source->mFirstRtpTime + MsToRtp(playedTimeMs, clockRate);
- int64_t expiredTimeInJb = rtpTime + jitterTime;
- bool isExpired = expiredTimeInJb <= (playedTimeRtp);
- bool isTooLate200 = expiredTimeInJb < (playedTimeRtp - jitterTime);
- bool isTooLate300 = expiredTimeInJb < (playedTimeRtp - (jitterTime * 3 / 2));
+ /**
+ * Based on experience in real commercial network services,
+ * 300 ms is a maximum heuristic jitter buffer time for video RTP service.
+ */
+
+ /**
+ * The static(base) jitter is a kind of expected propagation time that we desire.
+ * We can drop packets if it doesn't meet our standards.
+ * If it gets shorter we can get faster response but can lose packets.
+ * Expecting range : 50ms ~ 1000ms (But 300 ms would be practical upper bound)
+ */
+ const int64_t baseJbTimeRtp = MsToRtp(staticJbTimeMs, clockRate);
+ /**
+ * Dynamic jitter is a variance of interarrival time as defined in the 6.4.1 of RFC 3550.
+ * We can regard this as a tolerance of every moments.
+ * Expecting range : 0ms ~ 150ms (Not to over 300 ms practically)
+ */
+ const int64_t dynamicJbTimeRtp = // Max 150
+ std::min(MsToRtp(dynamicJbTimeMs, clockRate), MsToRtp(150, clockRate));
+ const int64_t jitterTimeRtp = baseJbTimeRtp + dynamicJbTimeRtp; // Total jitter time
+
+ int64_t expiredTimeRtp = rtpTime + jitterTimeRtp; // When does this buffer expire ? (T)
+ int64_t diffTimeRtp = playedTimeRtp - expiredTimeRtp;
+ bool isExpired = (diffTimeRtp >= 0); // It's expired if T is passed away
+ bool isFirstLineBroken = (diffTimeRtp > jitterTimeRtp); // (T + jitter) is a standard tolerance
+
+ int64_t finalMargin = dynamicJbTimeRtp * JITTER_MULTIPLE;
+ bool isSecondLineBroken = (diffTimeRtp > jitterTimeRtp + finalMargin); // The Maginot line
if (mShowQueue && mShowQueueCnt < 20) {
showCurrentQueue(queue);
- printNowTimeUs(startTime, nowTime, playedTime);
- printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
+ printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
+ printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
mShowQueueCnt++;
}
@@ -149,17 +177,23 @@
return NOT_ENOUGH_DATA;
}
- if (isTooLate200) {
- ALOGW("=== WARNING === buffer arrived 200ms late. === WARNING === ");
- }
+ if (isFirstLineBroken) {
+ if (isSecondLineBroken) {
+ ALOGW("buffer too late ... \t Diff in Jb=%lld \t "
+ "Seq# %d \t ExpSeq# %d \t"
+ "JitterMs %lld + (%lld * %.3f)",
+ (long long)(diffTimeRtp),
+ buffer->int32Data(), mNextExpectedSeqNo,
+ (long long)staticJbTimeMs, (long long)dynamicJbTimeMs, JITTER_MULTIPLE + 1);
+ printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
+ printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
- if (isTooLate300) {
- ALOGW("buffer arrived after 300ms ... \t Diff in Jb=%lld \t Seq# %d",
- (long long)(playedTimeRtp - expiredTimeInJb), buffer->int32Data());
- printNowTimeUs(startTime, nowTime, playedTime);
- printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
-
- mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTime);
+ mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
+ } else {
+ ALOGW("=== WARNING === buffer arrived after %lld + %lld = %lld ms === WARNING === ",
+ (long long)staticJbTimeMs, (long long)dynamicJbTimeMs,
+ (long long)RtpToMs(jitterTimeRtp, clockRate));
+ }
}
if (mNextExpectedSeqNoValid) {
@@ -170,6 +204,7 @@
source->noticeAbandonBuffer(cntRemove);
ALOGW("delete %d of %d buffers", cntRemove, size);
}
+
if (queue->empty()) {
return NOT_ENOUGH_DATA;
}
@@ -565,17 +600,6 @@
msg->post();
}
-inline int64_t AAVCAssembler::findRTPTime(
- const uint32_t& firstRTPTime, const sp<ABuffer>& buffer) {
- /* If you want to +, -, * rtpTime, recommend to declare rtpTime as int64_t.
- Because rtpTime can be near UINT32_MAX. Beware the overflow. */
- int64_t rtpTime = 0;
- CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
- // If the first overs 2^31 and rtp unders 2^31, the rtp value is overflowed one.
- int64_t overflowMask = (firstRTPTime & 0x80000000 & ~rtpTime) << 1;
- return rtpTime | overflowMask;
-}
-
int32_t AAVCAssembler::pickProperSeq(const Queue *queue,
uint32_t first, int64_t play, int64_t jit) {
sp<ABuffer> buffer = *(queue->begin());
@@ -620,16 +644,6 @@
return initSize - queue->size();
}
-inline void AAVCAssembler::printNowTimeUs(int64_t start, int64_t now, int64_t play) {
- ALOGD("start=%lld, now=%lld, played=%lld",
- (long long)start, (long long)now, (long long)play);
-}
-
-inline void AAVCAssembler::printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp) {
- ALOGD("rtp-time(JB)=%lld, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%lld expired=%d",
- (long long)rtp, (long long)play, (long long)exp, isExp);
-}
-
ARTPAssembler::AssemblyStatus AAVCAssembler::assembleMore(
const sp<ARTPSource> &source) {
AssemblyStatus status = addNALUnit(source);
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index 9d71e2f..954086c 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -63,13 +63,10 @@
void submitAccessUnit();
- inline int64_t findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer);
int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
size_t avail, float goodRatio);
int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);
- void printNowTimeUs(int64_t start, int64_t now, int64_t play);
- void printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp);
DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
};
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index 553ea08..cd60203 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -41,6 +41,8 @@
namespace android {
+const double JITTER_MULTIPLE = 1.5f;
+
// static
AHEVCAssembler::AHEVCAssembler(const sp<AMessage> ¬ify)
: mNotifyMsg(notify),
@@ -130,23 +132,51 @@
sp<ABuffer> buffer = *queue->begin();
buffer->meta()->setObject("source", source);
+
int64_t rtpTime = findRTPTime(firstRTPTime, buffer);
- int64_t startTime = source->mFirstSysTime / 1000;
- int64_t nowTime = ALooper::GetNowUs() / 1000;
- int64_t playedTime = nowTime - startTime;
- int64_t playedTimeRtp = source->mFirstRtpTime + playedTime * (int64_t)source->mClockRate / 1000;
- const int64_t jitterTime = source->mJbTimeMs * (int64_t)source->mClockRate / 1000;
+ const int64_t startTimeMs = source->mFirstSysTime / 1000;
+ const int64_t nowTimeMs = ALooper::GetNowUs() / 1000;
+ const int64_t staticJbTimeMs = source->getStaticJitterTimeMs();
+ const int64_t dynamicJbTimeMs = source->getDynamicJitterTimeMs();
+ const int64_t clockRate = source->mClockRate;
- int64_t expiredTimeInJb = rtpTime + jitterTime;
- bool isExpired = expiredTimeInJb <= (playedTimeRtp);
- bool isTooLate200 = expiredTimeInJb < (playedTimeRtp - jitterTime);
- bool isTooLate300 = expiredTimeInJb < (playedTimeRtp - (jitterTime * 3 / 2));
+ int64_t playedTimeMs = nowTimeMs - startTimeMs;
+ int64_t playedTimeRtp = source->mFirstRtpTime + MsToRtp(playedTimeMs, clockRate);
+
+ /**
+ * Based on experience in real commercial network services,
+ * 300 ms is a maximum heuristic jitter buffer time for video RTP service.
+ */
+
+ /**
+ * The static(base) jitter is a kind of expected propagation time that we desire.
+ * We can drop packets if it doesn't meet our standards.
+ * If it gets shorter we can get faster response but can lose packets.
+ * Expecting range : 50ms ~ 1000ms (But 300 ms would be practical upper bound)
+ */
+ const int64_t baseJbTimeRtp = MsToRtp(staticJbTimeMs, clockRate);
+ /**
+ * Dynamic jitter is a variance of interarrival time as defined in the 6.4.1 of RFC 3550.
+ * We can regard this as a tolerance of every moments.
+ * Expecting range : 0ms ~ 150ms (Not to over 300 ms practically)
+ */
+ const int64_t dynamicJbTimeRtp = // Max 150
+ std::min(MsToRtp(dynamicJbTimeMs, clockRate), MsToRtp(150, clockRate));
+ const int64_t jitterTimeRtp = baseJbTimeRtp + dynamicJbTimeRtp; // Total jitter time
+
+ int64_t expiredTimeRtp = rtpTime + jitterTimeRtp; // When does this buffer expire ? (T)
+ int64_t diffTimeRtp = playedTimeRtp - expiredTimeRtp;
+ bool isExpired = (diffTimeRtp >= 0); // It's expired if T is passed away
+ bool isFirstLineBroken = (diffTimeRtp > jitterTimeRtp); // (T + jitter) is a standard tolerance
+
+ int64_t finalMargin = dynamicJbTimeRtp * JITTER_MULTIPLE;
+ bool isSecondLineBroken = (diffTimeRtp > jitterTimeRtp + finalMargin); // The Maginot line
if (mShowQueueCnt < 20) {
showCurrentQueue(queue);
- printNowTimeUs(startTime, nowTime, playedTime);
- printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
+ printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
+ printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
mShowQueueCnt++;
}
@@ -157,17 +187,23 @@
return NOT_ENOUGH_DATA;
}
- if (isTooLate200) {
- ALOGW("=== WARNING === buffer arrived 200ms late. === WARNING === ");
- }
+ if (isFirstLineBroken) {
+ if (isSecondLineBroken) {
+ ALOGW("buffer too late ... \t Diff in Jb=%lld \t "
+ "Seq# %d \t ExpSeq# %d \t"
+ "JitterMs %lld + (%lld * %.3f)",
+ (long long)(diffTimeRtp),
+ buffer->int32Data(), mNextExpectedSeqNo,
+ (long long)staticJbTimeMs, (long long)dynamicJbTimeMs, JITTER_MULTIPLE + 1);
+ printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
+ printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
- if (isTooLate300) {
- ALOGW("buffer arrived after 300ms ... \t Diff in Jb=%lld \t Seq# %d",
- (long long)(playedTimeRtp - expiredTimeInJb), buffer->int32Data());
- printNowTimeUs(startTime, nowTime, playedTime);
- printRTPTime(rtpTime, playedTimeRtp, expiredTimeInJb, isExpired);
-
- mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTime);
+ mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
+ } else {
+ ALOGW("=== WARNING === buffer arrived after %lld + %lld = %lld ms === WARNING === ",
+ (long long)staticJbTimeMs, (long long)dynamicJbTimeMs,
+ (long long)RtpToMs(jitterTimeRtp, clockRate));
+ }
}
if (mNextExpectedSeqNoValid) {
@@ -578,17 +614,6 @@
msg->post();
}
-inline int64_t AHEVCAssembler::findRTPTime(
- const uint32_t& firstRTPTime, const sp<ABuffer>& buffer) {
- /* If you want to +, -, * rtpTime, recommend to declare rtpTime as int64_t.
- Because rtpTime can be near UINT32_MAX. Beware the overflow. */
- int64_t rtpTime = 0;
- CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
- // If the first overs 2^31 and rtp unders 2^31, the rtp value is overflowed one.
- int64_t overflowMask = (firstRTPTime & 0x80000000 & ~rtpTime) << 1;
- return rtpTime | overflowMask;
-}
-
int32_t AHEVCAssembler::pickProperSeq(const Queue *queue,
uint32_t first, int64_t play, int64_t jit) {
sp<ABuffer> buffer = *(queue->begin());
@@ -633,16 +658,6 @@
return initSize - queue->size();
}
-inline void AHEVCAssembler::printNowTimeUs(int64_t start, int64_t now, int64_t play) {
- ALOGD("start=%lld, now=%lld, played=%lld",
- (long long)start, (long long)now, (long long)play);
-}
-
-inline void AHEVCAssembler::printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp) {
- ALOGD("rtp-time(JB)=%lld, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%lld expired=%d",
- (long long)rtp, (long long)play, (long long)exp, isExp);
-}
-
ARTPAssembler::AssemblyStatus AHEVCAssembler::assembleMore(
const sp<ARTPSource> &source) {
AssemblyStatus status = addNALUnit(source);
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/AHEVCAssembler.h
index bf1cded..e64b661 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.h
+++ b/media/libstagefright/rtsp/AHEVCAssembler.h
@@ -64,13 +64,10 @@
void submitAccessUnit();
- inline int64_t findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer);
int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
size_t avail, float goodRatio);
int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);
- void printNowTimeUs(int64_t start, int64_t now, int64_t play);
- void printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp);
DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);
};
diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/ARTPAssembler.h
index 191f08e..f959c40 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.h
+++ b/media/libstagefright/rtsp/ARTPAssembler.h
@@ -19,6 +19,9 @@
#define A_RTP_ASSEMBLER_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <utils/List.h>
#include <utils/RefBase.h>
@@ -61,12 +64,47 @@
bool mShowQueue;
int32_t mShowQueueCnt;
+ // Utility functions
+ inline int64_t findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer);
+ inline int64_t MsToRtp(int64_t ms, int64_t clockRate);
+ inline int64_t RtpToMs(int64_t rtp, int64_t clockRate);
+ inline void printNowTimeMs(int64_t start, int64_t now, int64_t play);
+ inline void printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp);
+
private:
int64_t mFirstFailureTimeUs;
DISALLOW_EVIL_CONSTRUCTORS(ARTPAssembler);
};
+inline int64_t ARTPAssembler::findRTPTime(const uint32_t& firstRTPTime, const sp<ABuffer>& buffer) {
+ /* If you want to +,-,* rtpTime, recommend to declare rtpTime as int64_t.
+ Because rtpTime can be near UINT32_MAX. Beware the overflow. */
+ int64_t rtpTime = 0;
+ CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+ // If the first overs 2^31 and rtp unders 2^31, the rtp value is overflowed one.
+ int64_t overflowMask = (firstRTPTime & 0x80000000 & ~rtpTime) << 1;
+ return rtpTime | overflowMask;
+}
+
+inline int64_t ARTPAssembler::MsToRtp(int64_t ms, int64_t clockRate) {
+ return ms * clockRate / 1000;
+}
+
+inline int64_t ARTPAssembler::RtpToMs(int64_t rtp, int64_t clockRate) {
+ return rtp * 1000 / clockRate;
+}
+
+inline void ARTPAssembler::printNowTimeMs(int64_t start, int64_t now, int64_t play) {
+ ALOGD("start=%lld, now=%lld, played=%lld",
+ (long long)start, (long long)now, (long long)play);
+}
+
+inline void ARTPAssembler::printRTPTime(int64_t rtp, int64_t play, int64_t exp, bool isExp) {
+ ALOGD("rtp-time(JB)=%lld, played-rtp-time(JB)=%lld, expired-rtp-time(JB)=%lld expired=%d",
+ (long long)rtp, (long long)play, (long long)exp, isExp);
+}
+
} // namespace android
#endif // A_RTP_ASSEMBLER_H_
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 61c06d1..9509377 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -70,6 +70,8 @@
bool mIsInjected;
+ // A place to save time when it polls
+ int64_t mLastPollTimeUs;
// RTCP Extension for CVO
int mCVOExtMap; // will be set to 0 if cvo is not negotiated in sdp
};
@@ -80,7 +82,7 @@
mLastReceiverReportTimeUs(-1),
mLastBitrateReportTimeUs(-1),
mTargetBitrate(-1),
- mJbTimeMs(300) {
+ mStaticJitterTimeMs(kStaticJitterTimeMs) {
}
ARTPConnection::~ARTPConnection() {
@@ -416,6 +418,7 @@
return;
}
+ int64_t nowUs = ALooper::GetNowUs();
int res = select(maxSocket + 1, &rs, NULL, NULL, &tv);
if (res > 0) {
@@ -425,6 +428,7 @@
++it;
continue;
}
+ it->mLastPollTimeUs = nowUs;
status_t err = OK;
if (FD_ISSET(it->mRTPSocket, &rs)) {
@@ -486,7 +490,6 @@
}
}
- int64_t nowUs = ALooper::GetNowUs();
checkRxBitrate(nowUs);
if (mLastReceiverReportTimeUs <= 0
@@ -720,6 +723,7 @@
buffer->setInt32Data(u16at(&data[2]));
buffer->setRange(payloadOffset, size - payloadOffset);
+ source->putDynamicJitterData(rtpTime, s->mLastPollTimeUs);
source->processRTPPacket(buffer);
return OK;
@@ -1066,7 +1070,7 @@
}
source->setSelfID(mSelfID);
- source->setJbTime(mJbTimeMs > 0 ? mJbTimeMs : 300);
+ source->setStaticJitterTimeMs(mStaticJitterTimeMs);
info->mSources.add(srcId, source);
} else {
source = info->mSources.valueAt(index);
@@ -1086,8 +1090,8 @@
mSelfID = selfID;
}
-void ARTPConnection::setJbTime(const uint32_t jbTimeMs) {
- mJbTimeMs = jbTimeMs;
+void ARTPConnection::setStaticJitterTimeMs(const uint32_t jbTimeMs) {
+ mStaticJitterTimeMs = jbTimeMs;
}
void ARTPConnection::setTargetBitrate(int32_t targetBitrate) {
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index a37ac0e..ea0a374 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -46,7 +46,7 @@
void injectPacket(int index, const sp<ABuffer> &buffer);
void setSelfID(const uint32_t selfID);
- void setJbTime(const uint32_t jbTimeMs);
+ void setStaticJitterTimeMs(const uint32_t jbTimeMs);
void setTargetBitrate(int32_t targetBitrate);
// Creates a pair of UDP datagram sockets bound to adjacent ports
@@ -89,7 +89,7 @@
int32_t mSelfID;
int32_t mTargetBitrate;
- uint32_t mJbTimeMs;
+ uint32_t mStaticJitterTimeMs;
int32_t mCumulativeBytes;
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 3fdf8e4..402dc27 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -48,7 +48,6 @@
mFirstRtpTime(0),
mFirstSysTime(0),
mClockRate(0),
- mJbTimeMs(300), // default jitter buffer time is 300ms.
mFirstSsrc(0),
mHighestNackNumber(0),
mID(id),
@@ -59,6 +58,7 @@
mPrevNumBuffersReceived(0),
mPrevExpectedForRR(0),
mPrevNumBuffersReceivedForRR(0),
+ mStaticJbTimeMs(kStaticJitterTimeMs),
mLastNTPTime(0),
mLastNTPTimeUpdateUs(0),
mIssueFIRRequests(false),
@@ -102,6 +102,11 @@
if (mAssembler != NULL && !mAssembler->initCheck()) {
mAssembler.clear();
}
+
+ int32_t clockRate, numChannels;
+ ASessionDescription::ParseFormatDesc(desc.c_str(), &clockRate, &numChannels);
+ mClockRate = clockRate;
+ mJitterCalc = new JitterCalc(mClockRate);
}
static uint32_t AbsDiff(uint32_t seq1, uint32_t seq2) {
@@ -139,9 +144,8 @@
mBaseSeqNumber = seqNum;
mFirstRtpTime = firstRtpTime;
mFirstSsrc = ssrc;
- ALOGD("first-rtp arrived: first-rtp-time=%d, sys-time=%lld, seq-num=%u, ssrc=%d",
+ ALOGD("first-rtp arrived: first-rtp-time=%u, sys-time=%lld, seq-num=%u, ssrc=%d",
mFirstRtpTime, (long long)mFirstSysTime, mHighestSeqNumber, mFirstSsrc);
- mClockRate = 90000;
mQueue.push_back(buffer);
return true;
}
@@ -327,10 +331,11 @@
data[18] = (mHighestSeqNumber >> 8) & 0xff;
data[19] = mHighestSeqNumber & 0xff;
- data[20] = 0x00; // Interarrival jitter
- data[21] = 0x00;
- data[22] = 0x00;
- data[23] = 0x00;
+ uint32_t jitterTime = getDynamicJitterTimeMs() * mClockRate / 1000;
+ data[20] = jitterTime >> 24; // Interarrival jitter
+ data[21] = (jitterTime >> 16) & 0xff;
+ data[22] = (jitterTime >> 8) & 0xff;
+ data[23] = jitterTime & 0xff;
uint32_t LSR = 0;
uint32_t DLSR = 0;
@@ -508,15 +513,27 @@
kSourceID = selfID;
}
-void ARTPSource::setJbTime(const uint32_t jbTimeMs) {
- mJbTimeMs = jbTimeMs;
-}
-
void ARTPSource::setPeriodicFIR(bool enable) {
ALOGD("setPeriodicFIR %d", enable);
mIssueFIRRequests = enable;
}
+uint32_t ARTPSource::getStaticJitterTimeMs() {
+ return mStaticJbTimeMs;
+}
+
+uint32_t ARTPSource::getDynamicJitterTimeMs() {
+ return mJitterCalc->getJitterMs();
+}
+
+void ARTPSource::setStaticJitterTimeMs(const uint32_t jbTimeMs) {
+ mStaticJbTimeMs = jbTimeMs;
+}
+
+void ARTPSource::putDynamicJitterData(uint32_t timeStamp, int64_t arrivalTime) {
+ mJitterCalc->putData(timeStamp, arrivalTime);
+}
+
bool ARTPSource::isNeedToEarlyNotify() {
uint32_t expected = mHighestSeqNumber - mBaseSeqNumber + 1;
int32_t intervalExpectedInNow = expected - mPrevExpected;
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index c51fd8a..56011d3 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -27,8 +27,12 @@
#include <map>
+#include "JitterCalculator.h"
+
namespace android {
+const uint32_t kStaticJitterTimeMs = 50; // 50ms
+
struct ABuffer;
struct AMessage;
struct ARTPAssembler;
@@ -64,8 +68,13 @@
void setSeqNumToNACK(uint16_t seqNum, uint16_t mask, uint16_t nowJitterHeadSeqNum);
uint32_t getSelfID();
void setSelfID(const uint32_t selfID);
- void setJbTime(const uint32_t jbTimeMs);
void setPeriodicFIR(bool enable);
+
+ uint32_t getStaticJitterTimeMs();
+ uint32_t getDynamicJitterTimeMs();
+ void setStaticJitterTimeMs(const uint32_t jbTimeMs);
+ void putDynamicJitterData(uint32_t timeStamp, int64_t arrivalTime);
+
bool isNeedToEarlyNotify();
void notifyPktInfo(int32_t bitrate, bool isRegular);
// FIR needs to be sent by missing packet or broken video image.
@@ -78,7 +87,6 @@
int64_t mFirstSysTime;
int32_t mClockRate;
- uint32_t mJbTimeMs;
int32_t mFirstSsrc;
int32_t mHighestNackNumber;
@@ -96,6 +104,9 @@
List<sp<ABuffer> > mQueue;
sp<ARTPAssembler> mAssembler;
+ uint32_t mStaticJbTimeMs;
+ sp<JitterCalc> mJitterCalc;
+
typedef struct infoNACK {
uint16_t seqNum;
uint16_t mask;
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index dcadbaf..34d1788 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -36,6 +36,7 @@
"ARTPWriter.cpp",
"ARTSPConnection.cpp",
"ASessionDescription.cpp",
+ "JitterCalculator.cpp",
"SDPLoader.cpp",
],
diff --git a/media/libstagefright/rtsp/JitterCalculator.cpp b/media/libstagefright/rtsp/JitterCalculator.cpp
new file mode 100644
index 0000000..466171c
--- /dev/null
+++ b/media/libstagefright/rtsp/JitterCalculator.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "JitterCalc"
+#include <utils/Log.h>
+
+#include "JitterCalculator.h"
+
+#include <stdlib.h>
+
+namespace android {
+
+JitterCalc::JitterCalc(int32_t clockRate)
+ : mClockRate(clockRate) {
+ init();
+}
+
+void JitterCalc::init() {
+ mJitterValueUs = 0;
+ mLastTimeStamp = 0;
+ mLastArrivalTimeUs = 0;
+}
+
+void JitterCalc::putData(int64_t rtpTime, int64_t arrivalTimeUs) {
+ if (mLastTimeStamp == 0) {
+ mLastTimeStamp = rtpTime;
+ mLastArrivalTimeUs = arrivalTimeUs;
+ }
+
+ const int64_t UINT32_MSB = 0x80000000;
+ int64_t tempLastTimeStamp = mLastTimeStamp;
+ // A RTP time wraps around after UINT32_MAX. We must consider this case.
+ int64_t overflowMask = (mLastTimeStamp ^ rtpTime) & UINT32_MSB;
+ rtpTime |= ((overflowMask & ~rtpTime) << 1);
+ tempLastTimeStamp |= ((overflowMask & ~mLastTimeStamp) << 1);
+ ALOGV("Raw stamp \t\t now %llx \t\t last %llx",
+ (long long)rtpTime, (long long)tempLastTimeStamp);
+
+ int64_t diffTimeStampUs = abs(rtpTime - tempLastTimeStamp) * 1000000ll / mClockRate;
+ int64_t diffArrivalUs = abs(arrivalTimeUs - mLastArrivalTimeUs);
+ ALOGV("diffTimeStampus %lld \t\t diffArrivalUs %lld",
+ (long long)diffTimeStampUs, (long long)diffArrivalUs);
+
+ // 6.4.1 of RFC3550 defines this interarrival jitter value.
+ mJitterValueUs = (mJitterValueUs * 15 + abs(diffTimeStampUs - diffArrivalUs)) / 16;
+ ALOGV("JitterUs %lld", (long long)mJitterValueUs);
+
+ mLastTimeStamp = (uint32_t)rtpTime;
+ mLastArrivalTimeUs = arrivalTimeUs;
+}
+
+uint32_t JitterCalc::getJitterMs() {
+ return mJitterValueUs / 1000;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/rtsp/JitterCalculator.h b/media/libstagefright/rtsp/JitterCalculator.h
new file mode 100644
index 0000000..03e43ff
--- /dev/null
+++ b/media/libstagefright/rtsp/JitterCalculator.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_JITTER_CALCULATOR_H_
+
+#define A_JITTER_CALCULATOR_H_
+
+#include <stdint.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class JitterCalc : public RefBase {
+private:
+ // Time Stamp per Second
+ const int32_t mClockRate;
+
+ uint32_t mJitterValueUs;
+ uint32_t mLastTimeStamp;
+ int64_t mLastArrivalTimeUs;
+
+ void init();
+public:
+ JitterCalc(int32_t clockRate);
+ void putData(int64_t rtpTime, int64_t arrivalTime);
+ uint32_t getJitterMs();
+};
+
+} // namespace android
+
+#endif // A_JITTER_CALCULATOR_H_