VT: Add TMMBR feature for RTP Rx side
1. Seperate TMMBR sending block from RR sending block.
At least, TMMBR is sent per 5 sec.
But TMMBR is sent per 1 sec if TMMBR's bitrate is chaged.
2. TMMBR max value comes from SDP AS value
3. QualManager is separated from ARTPSource.h
Bug: 121230209
Change-Id: Ie0abb6e639f50ad8ee3081c3d5e76dc07e80d5d1
Signed-off-by: Kim Sungyeon <sy85.kim@samsung.com>
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index e9e7d06..57b6c59 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -42,7 +42,7 @@
mFinalResult(OK),
mBuffering(false),
mInPreparationPhase(true),
- mRTPConn(new ARTPConnection),
+ mRTPConn(new ARTPConnection(ARTPConnection::kViLTEConnection)),
mEOSTimeoutAudio(0),
mEOSTimeoutVideo(0),
mLastCVOUpdated(-1) {
@@ -111,7 +111,7 @@
// 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->setMinMaxBitrate(videoMinBitrate, 512000);
+ mRTPConn->setMinMaxBitrate(videoMinBitrate, info->mAS * 1000);
info->mRTPSocket = sockRtp;
info->mRTCPSocket = sockRtcp;
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 769e3f4..b933950 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -420,7 +420,8 @@
}
int64_t nowUs = ALooper::GetNowUs();
- showRxBitrate(nowUs);
+ checkRxBitrate(nowUs);
+
if (mLastReceiverReportTimeUs <= 0
|| mLastReceiverReportTimeUs + 5000000LL <= nowUs) {
sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
@@ -445,10 +446,7 @@
for (size_t i = 0; i < s->mSources.size(); ++i) {
sp<ARTPSource> source = s->mSources.valueAt(i);
- if (source->isNeedToReport()) {
- source->addReceiverReport(buffer);
- source->addTMMBR(buffer);
- }
+ source->addReceiverReport(buffer);
if (mFlags & kRegularlyRequestFIR) {
source->addFIR(buffer);
@@ -458,22 +456,7 @@
if (buffer->size() > 0) {
ALOGV("Sending RR...");
- struct sockaddr* pRemoteRTCPAddr;
- int sizeSockSt;
- if (s->isIPv6) {
- pRemoteRTCPAddr = (struct sockaddr *)&s->mRemoteRTCPAddr6;
- sizeSockSt = sizeof(struct sockaddr_in6);
- } else {
- pRemoteRTCPAddr = (struct sockaddr *)&s->mRemoteRTCPAddr;
- sizeSockSt = sizeof(struct sockaddr_in);
- }
-
- ssize_t n;
- do {
- n = sendto(
- s->mRTCPSocket, buffer->data(), buffer->size(), 0,
- pRemoteRTCPAddr, sizeSockSt);
- } while (n < 0 && errno == EINTR);
+ ssize_t n = send(s, buffer);
if (n <= 0) {
ALOGW("failed to send RTCP receiver report (%s).",
@@ -517,6 +500,9 @@
(!receiveRTP && s->mNumRTCPPacketsReceived == 0)
? sizeSockSt : 0;
+ if (mFlags & kViLTEConnection)
+ remoteAddrLen = 0;
+
ssize_t nbytes;
do {
nbytes = recvfrom(
@@ -547,6 +533,36 @@
return err;
}
+ssize_t ARTPConnection::send(const StreamInfo *info, const sp<ABuffer> buffer) {
+ struct sockaddr* pRemoteRTCPAddr;
+ int sizeSockSt;
+
+ /* It seems this isIPv6 variable is useless.
+ * We should remove it to prevent confusion */
+ if (info->isIPv6) {
+ pRemoteRTCPAddr = (struct sockaddr *)&info->mRemoteRTCPAddr6;
+ sizeSockSt = sizeof(struct sockaddr_in6);
+ } else {
+ pRemoteRTCPAddr = (struct sockaddr *)&info->mRemoteRTCPAddr;
+ sizeSockSt = sizeof(struct sockaddr_in);
+ }
+
+ if (mFlags & kViLTEConnection) {
+ ALOGV("ViLTE RTCP");
+ pRemoteRTCPAddr = NULL;
+ sizeSockSt = 0;
+ }
+
+ ssize_t n;
+ do {
+ n = sendto(
+ info->mRTCPSocket, buffer->data(), buffer->size(), 0,
+ pRemoteRTCPAddr, sizeSockSt);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
status_t ARTPConnection::parseRTP(StreamInfo *s, const sp<ABuffer> &buffer) {
if (s->mNumRTPPacketsReceived++ == 0) {
sp<AMessage> notify = s->mNotifyMsg->dup();
@@ -963,14 +979,56 @@
mMaxBitrate = max;
}
-void ARTPConnection::showRxBitrate(int64_t nowUs) {
+void ARTPConnection::checkRxBitrate(int64_t nowUs) {
if (mLastBitrateReportTimeUs <= 0) {
mCumulativeBytes = 0;
mLastBitrateReportTimeUs = nowUs;
}
else if (mLastBitrateReportTimeUs + 1000000ll <= nowUs) {
int32_t timeDiff = (nowUs - mLastBitrateReportTimeUs) / 1000000ll;
- ALOGI("Actual Rx bitrate : %d bits/sec", mCumulativeBytes * 8 / timeDiff);
+ int32_t bitrate = mCumulativeBytes * 8 / timeDiff;
+ ALOGI("Actual Rx bitrate : %d bits/sec", bitrate);
+
+ sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
+ List<StreamInfo>::iterator it = mStreams.begin();
+ while (it != mStreams.end()) {
+ StreamInfo *s = &*it;
+ if (s->mIsInjected) {
+ ++it;
+ continue;
+ }
+
+ if (s->mNumRTCPPacketsReceived == 0) {
+ // We have never received any RTCP packets on this stream,
+ // we don't even know where to send a report.
+ ++it;
+ continue;
+ }
+
+ buffer->setRange(0, 0);
+
+ for (size_t i = 0; i < s->mSources.size(); ++i) {
+ sp<ARTPSource> source = s->mSources.valueAt(i);
+ source->setTargetBitrate();
+ source->addTMMBR(buffer);
+ }
+ if (buffer->size() > 0) {
+ ALOGV("Sending TMMBR...");
+
+ ssize_t n = send(s, buffer);
+
+ if (n <= 0) {
+ ALOGW("failed to send RTCP TMMBR (%s).",
+ n == 0 ? "connection gone" : strerror(errno));
+
+ it = mStreams.erase(it);
+ continue;
+ }
+
+ CHECK_EQ(n, (ssize_t)buffer->size());
+ }
+ ++it;
+ }
mCumulativeBytes = 0;
mLastBitrateReportTimeUs = nowUs;
}
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index 4e690b2..f091ad4 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -30,6 +30,7 @@
struct ARTPConnection : public AHandler {
enum Flags {
kRegularlyRequestFIR = 2,
+ kViLTEConnection = 4,
};
explicit ARTPConnection(uint32_t flags = 0);
@@ -94,9 +95,10 @@
void onPollStreams();
void onInjectPacket(const sp<AMessage> &msg);
void onSendReceiverReports();
- void showRxBitrate(int64_t nowUs);
+ void checkRxBitrate(int64_t nowUs);
status_t receive(StreamInfo *info, bool receiveRTP);
+ ssize_t send(const StreamInfo *info, const sp<ABuffer> buffer);
status_t parseRTP(StreamInfo *info, const sp<ABuffer> &buffer);
status_t parseRTPExt(StreamInfo *s, const uint8_t *extData, size_t extLen, int32_t *cvoDegrees);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index f00cebe..9f2fed4 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -257,8 +257,6 @@
fraction = (intervalPacketLost << 8) / intervalExpected;
}
- mQualManager.setTargetBitrate(fraction);
-
mPrevExpected = expected;
mPrevNumBuffersReceived = mNumBuffersReceived;
int32_t cumulativePacketLost = (int32_t)expected - mNumBuffersReceived;
@@ -324,7 +322,9 @@
ALOGW("RTCP buffer too small to accomodate RR.");
return;
}
- if (mQualManager.mTargetBitrate <= 0)
+
+ int32_t targetBitrate = mQualManager.getTargetBitrate();
+ if (targetBitrate <= 0)
return;
uint8_t *data = buffer->data() + buffer->size();
@@ -345,7 +345,6 @@
data[14] = (mID >> 8) & 0xff;
data[15] = mID & 0xff;
- int32_t targetBitrate = mQualManager.mTargetBitrate;
int32_t exp, mantissa;
// Round off to the nearest 2^4th
@@ -363,6 +362,9 @@
buffer->setRange(buffer->offset(), buffer->size() + 20);
}
+uint32_t ARTPSource::getSelfID() {
+ return kSourceID;
+}
void ARTPSource::setSelfID(const uint32_t selfID) {
kSourceID = selfID;
}
@@ -371,6 +373,25 @@
mQualManager.setMinMaxBitrate(min, max);
}
+void ARTPSource::setTargetBitrate() {
+ uint8_t fraction = 0;
+
+ // According to appendix A.3 in RFC 3550
+ uint32_t expected = mHighestSeqNumber - mBaseSeqNumber + 1;
+ int64_t intervalExpected = expected - mPrevExpected;
+ int64_t intervalReceived = mNumBuffersReceived - mPrevNumBuffersReceived;
+ int64_t intervalPacketLost = intervalExpected - intervalReceived;
+
+ if (intervalPacketLost < 0)
+ fraction = 0;
+ else if (intervalExpected <= intervalPacketLost || intervalExpected == 0)
+ fraction = 255;
+ else
+ fraction = (intervalPacketLost << 8) / intervalExpected;
+
+ mQualManager.setTargetBitrate(fraction, ALooper::GetNowUs());
+}
+
bool ARTPSource::isNeedToReport() {
int64_t intervalReceived = mNumBuffersReceived - mPrevNumBuffersReceived;
return (intervalReceived > 0) ? true : false;
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index e4aa4c1..5b1ae73 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <utils/List.h>
#include <utils/RefBase.h>
+#include <QualManager.h>
namespace android {
@@ -46,8 +47,10 @@
void addReceiverReport(const sp<ABuffer> &buffer);
void addFIR(const sp<ABuffer> &buffer);
void addTMMBR(const sp<ABuffer> &buffer);
+ uint32_t getSelfID();
void setSelfID(const uint32_t selfID);
void setMinMaxBitrate(int32_t min, int32_t max);
+ void setTargetBitrate();
bool isNeedToReport();
@@ -59,35 +62,6 @@
int32_t mClockRate;
private:
- struct QualManager {
- QualManager() : mMinBitrate(-1), mMaxBitrate(-1), mTargetBitrate(-1) {};
-
- int32_t mMinBitrate;
- int32_t mMaxBitrate;
- int32_t mBitrateStep;
-
- int32_t mTargetBitrate;
-
- void setTargetBitrate(uint8_t fraction) {
- if (fraction <= (256 * 2 /100)) { // loss less than 2%
- mTargetBitrate += mBitrateStep;
- } else if (fraction > (256 * 5 / 100)) { // loss more than 5%
- mTargetBitrate -= mBitrateStep;
- }
-
- if (mTargetBitrate > mMaxBitrate)
- mTargetBitrate = mMaxBitrate;
- else if (mTargetBitrate < mMinBitrate)
- mTargetBitrate = mMinBitrate;
- };
-
- void setMinMaxBitrate(int32_t min, int32_t max) {
- mMinBitrate = min;
- mMaxBitrate = max;
- mBitrateStep = (max - min) / 8;
- mTargetBitrate = min;
- };
- } mQualManager;
uint32_t mID;
uint32_t mHighestSeqNumber;
@@ -108,6 +82,8 @@
sp<AMessage> mNotify;
+ QualManager mQualManager;
+
bool queuePacket(const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(ARTPSource);
diff --git a/media/libstagefright/rtsp/QualManager.h b/media/libstagefright/rtsp/QualManager.h
new file mode 100644
index 0000000..f6671ba
--- /dev/null
+++ b/media/libstagefright/rtsp/QualManager.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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 QUAL_MANAGER_H_
+
+#define QUAL_MANAGER_H_
+
+namespace android {
+
+class QualManager {
+public:
+ QualManager() : mMinBitrate(-1), mMaxBitrate(-1), mTargetBitrate(512000),
+ mLastTargetBitrate(-1), mLastSetBitrateTime(0),
+ mIsNewTargetBitrate(false){};
+
+ int32_t getTargetBitrate() {
+ if (mIsNewTargetBitrate) {
+ mIsNewTargetBitrate = false;
+ mLastTargetBitrate = mTargetBitrate;
+ return mTargetBitrate;
+ } else {
+ return -1;
+ }
+ }
+
+ void setTargetBitrate(uint8_t fraction, int64_t nowUs) {
+ if (fraction <= (256 * 2 /100)) { // loss less than 2%
+ mTargetBitrate += mBitrateStep;
+ } else if (fraction > (256 * 5 / 100)) { // loss more than 5%
+ mTargetBitrate -= mBitrateStep * 4;
+ }
+
+ if (mTargetBitrate > mMaxBitrate) {
+ mTargetBitrate = mMaxBitrate;
+ } else if (mTargetBitrate < mMinBitrate) {
+ mTargetBitrate = mMinBitrate;
+ }
+
+ if (mLastTargetBitrate != mTargetBitrate || nowUs - mLastSetBitrateTime > 5000000ll) {
+ mIsNewTargetBitrate = true;
+ mLastSetBitrateTime = nowUs;
+ }
+ };
+
+ void setMinMaxBitrate(int32_t min, int32_t max) {
+ mMinBitrate = min;
+ mMaxBitrate = max;
+ mBitrateStep = (max - min) / 8;
+ };
+private:
+ int32_t mMinBitrate;
+ int32_t mMaxBitrate;
+ int32_t mBitrateStep;
+
+ int32_t mTargetBitrate;
+ int32_t mLastTargetBitrate;
+
+ int64_t mLastSetBitrateTime;
+
+ bool mIsNewTargetBitrate;
+};
+
+} //namespace android
+
+#endif // QUAL_MANAGER_H_