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_