VT: Add TMMBR function on Rx

Now Player(Rx) can measure and check Rx status(bitrate & loss)
And send TMMBR base on the status

Merged-in: I203ff5022ca95859c8acc662ba6cedff256a6995
Change-Id: I203ff5022ca95859c8acc662ba6cedff256a6995
Signed-off-by: Kim Sungyeon <sy85.kim@samsung.com>
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index 4b1b164..6f4933c 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -110,6 +110,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);
 
         info->mRTPSocket = sockRtp;
         info->mRTCPSocket = sockRtcp;
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.h b/media/libmediaplayerservice/nuplayer/RTPSource.h
index e3df2a4..faed1e1 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.h
@@ -46,6 +46,8 @@
 struct ALooper;
 struct AnotherPacketSource;
 
+const int32_t videoMinBitrate = 192000;
+
 struct NuPlayer::RTPSource : public NuPlayer::Source {
     RTPSource(
             const sp<AMessage> &notify,
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 2bedc9a..01ce43b 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -72,7 +72,8 @@
 ARTPConnection::ARTPConnection(uint32_t flags)
     : mFlags(flags),
       mPollEventPending(false),
-      mLastReceiverReportTimeUs(-1) {
+      mLastReceiverReportTimeUs(-1),
+      mLastBitrateReportTimeUs(-1) {
 }
 
 ARTPConnection::~ARTPConnection() {
@@ -411,6 +412,7 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
+    showRxBitrate(nowUs);
     if (mLastReceiverReportTimeUs <= 0
             || mLastReceiverReportTimeUs + 5000000LL <= nowUs) {
         sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
@@ -435,7 +437,10 @@
             for (size_t i = 0; i < s->mSources.size(); ++i) {
                 sp<ARTPSource> source = s->mSources.valueAt(i);
 
-                source->addReceiverReport(buffer);
+                if (source->isNeedToReport()) {
+                    source->addReceiverReport(buffer);
+                    source->addTMMBR(buffer);
+                }
 
                 if (mFlags & kRegularlyRequestFIR) {
                     source->addFIR(buffer);
@@ -513,6 +518,7 @@
             0,
             remoteAddrLen > 0 ? pRemoteRTCPAddr : NULL,
             remoteAddrLen > 0 ? &remoteAddrLen : NULL);
+        mCumulativeBytes += nbytes;
     } while (nbytes < 0 && errno == EINTR);
 
     if (nbytes <= 0) {
@@ -875,6 +881,7 @@
                 srcId, info->mSessionDesc, info->mIndex, info->mNotifyMsg);
 
         source->setSelfID(mSelfID);
+        source->setMinMaxBitrate(mMinBitrate, mMaxBitrate);
         info->mSources.add(srcId, source);
     } else {
         source = info->mSources.valueAt(index);
@@ -894,6 +901,23 @@
     mSelfID = selfID;
 }
 
+void ARTPConnection::setMinMaxBitrate(int32_t min, int32_t max) {
+    mMinBitrate = min;
+    mMaxBitrate = max;
+}
+
+void ARTPConnection::showRxBitrate(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);
+        mCumulativeBytes = 0;
+        mLastBitrateReportTimeUs = nowUs;
+    }
+}
 void ARTPConnection::onInjectPacket(const sp<AMessage> &msg) {
     int32_t index;
     CHECK(msg->findInt32("index", &index));
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index 287430e..ae638e4 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -45,6 +45,7 @@
     void injectPacket(int index, const sp<ABuffer> &buffer);
 
     void setSelfID(const uint32_t selfID);
+    void setMinMaxBitrate(int32_t min, int32_t max);
 
     // Creates a pair of UDP datagram sockets bound to adjacent ports
     // (the rtpSocket is bound to an even port, the rtcpSocket to the
@@ -80,14 +81,20 @@
 
     bool mPollEventPending;
     int64_t mLastReceiverReportTimeUs;
+    int64_t mLastBitrateReportTimeUs;
 
     int32_t mSelfID;
 
+    int32_t mMinBitrate;
+    int32_t mMaxBitrate;
+    int32_t mCumulativeBytes;
+
     void onAddStream(const sp<AMessage> &msg);
     void onRemoveStream(const sp<AMessage> &msg);
     void onPollStreams();
     void onInjectPacket(const sp<AMessage> &msg);
     void onSendReceiverReports();
+    void showRxBitrate(int64_t nowUs);
 
     status_t receive(StreamInfo *info, bool receiveRTP);
 
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index c39b4c2..5c3f2d8 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -263,10 +263,14 @@
         fraction = (intervalPacketLost << 8) / intervalExpected;
     }
 
+    mQualManager.setTargetBitrate(fraction);
+
     mPrevExpected = expected;
     mPrevNumBuffersReceived = mNumBuffersReceived;
     int32_t cumulativePacketLost = (int32_t)expected - mNumBuffersReceived;
 
+    ALOGI("UID %p expectedPkts %lld lostPkts %lld", this, (long long)intervalExpected, (long long)intervalPacketLost);
+
     uint8_t *data = buffer->data() + buffer->size();
 
     data[0] = 0x80 | 1;
@@ -321,10 +325,63 @@
     buffer->setRange(buffer->offset(), buffer->size() + 32);
 }
 
+void ARTPSource::addTMMBR(const sp<ABuffer> &buffer) {
+    if (buffer->size() + 32 > buffer->capacity()) {
+        ALOGW("RTCP buffer too small to accomodate RR.");
+        return;
+    }
+    if (mQualManager.mTargetBitrate <= 0)
+        return;
+
+    uint8_t *data = buffer->data() + buffer->size();
+
+    data[0] = 0x80 | 3; // TMMBR
+    data[1] = 205;      // TSFB
+    data[2] = 0;
+    data[3] = 4;        // total (4+1) * sizeof(int32_t) = 20 bytes
+    data[4] = kSourceID >> 24;
+    data[5] = (kSourceID >> 16) & 0xff;
+    data[6] = (kSourceID >> 8) & 0xff;
+    data[7] = kSourceID & 0xff;
+
+    *(int32_t*)(&data[8]) = 0;  // 4 bytes blank
+
+    data[12] = mID >> 24;
+    data[13] = (mID >> 16) & 0xff;
+    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
+    ALOGI("UE -> Op Req Rx bitrate : %d ", targetBitrate & 0xfffffff0);
+    for (exp=4 ; exp < 32 ; exp++)
+        if (((targetBitrate >> exp) & 0x01) != 0)
+            break;
+    mantissa = targetBitrate >> exp;
+
+    data[16] = ((exp << 2) & 0xfc) | ((mantissa & 0x18000) >> 15);
+    data[17] =                        (mantissa & 0x07f80) >> 7;
+    data[18] =                        (mantissa & 0x0007f) << 1;
+    data[19] = 40;              // 40 bytes overhead;
+
+    buffer->setRange(buffer->offset(), buffer->size() + 20);
+}
+
 void ARTPSource::setSelfID(const uint32_t selfID) {
     kSourceID = selfID;
 }
 
+void ARTPSource::setMinMaxBitrate(int32_t min, int32_t max) {
+    mQualManager.setMinMaxBitrate(min, max);
+}
+
+bool ARTPSource::isNeedToReport() {
+    int64_t intervalReceived = mNumBuffersReceived - mPrevNumBuffersReceived;
+    return (intervalReceived > 0) ? true : false;
+}
+
 void ARTPSource::noticeAbandonBuffer(int cnt) {
     mNumBuffersReceived -= cnt;
 }
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index 40f08f4..e4aa4c1 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -45,7 +45,11 @@
 
     void addReceiverReport(const sp<ABuffer> &buffer);
     void addFIR(const sp<ABuffer> &buffer);
+    void addTMMBR(const sp<ABuffer> &buffer);
     void setSelfID(const uint32_t selfID);
+    void setMinMaxBitrate(int32_t min, int32_t max);
+
+    bool isNeedToReport();
 
     void noticeAbandonBuffer(int cnt=1);
 
@@ -55,6 +59,36 @@
     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;
     uint32_t mPrevExpected;