Provide bandwidth estimation support in NuHTTPDataSource

Change-Id: Ic98d8cf147bbba60ec735e7ca200addb2bd09f29
related-to-bug: 2368598
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index 7aac447..133f225 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -5,6 +5,7 @@
 #include "include/NuHTTPDataSource.h"
 
 #include <cutils/properties.h>
+#include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaErrors.h>
 
@@ -68,6 +69,9 @@
       mOffset(0),
       mContentLength(0),
       mContentLengthValid(false),
+      mNumBandwidthHistoryItems(0),
+      mTotalTransferTimeUs(0),
+      mTotalTransferBytes(0),
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL) {
 }
@@ -189,6 +193,20 @@
             return ERROR_IO;
         }
 
+        {
+            string value;
+            if (mHTTP.find_header_value("Transfer-Encoding", &value)) {
+                // We don't currently support any transfer encodings.
+
+                mState = DISCONNECTED;
+                mHTTP.disconnect();
+
+                LOGE("We don't support '%s' transfer encoding.", value.c_str());
+
+                return ERROR_UNSUPPORTED;
+            }
+        }
+
         applyTimeoutResponse();
 
         if (offset == 0) {
@@ -254,6 +272,8 @@
 
     size_t numBytesRead = 0;
     while (numBytesRead < size) {
+        int64_t startTimeUs = ALooper::GetNowUs();
+
         ssize_t n =
             mHTTP.receive((uint8_t *)data + numBytesRead, size - numBytesRead);
 
@@ -261,6 +281,9 @@
             return n;
         }
 
+        int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+        addBandwidthMeasurement_l(n, delayUs);
+
         numBytesRead += (size_t)n;
 
         if (n == 0) {
@@ -345,6 +368,36 @@
     }
 }
 
+bool NuHTTPDataSource::estimateBandwidth(int32_t *bandwidth_bps) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mNumBandwidthHistoryItems < 10) {
+        return false;
+    }
+
+    *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+    return true;
+}
+
+void NuHTTPDataSource::addBandwidthMeasurement_l(
+        size_t numBytes, int64_t delayUs) {
+    BandwidthEntry entry;
+    entry.mDelayUs = delayUs;
+    entry.mNumBytes = numBytes;
+    mTotalTransferTimeUs += delayUs;
+    mTotalTransferBytes += numBytes;
+
+    mBandwidthHistory.push_back(entry);
+    if (++mNumBandwidthHistoryItems > 100) {
+        BandwidthEntry *entry = &*mBandwidthHistory.begin();
+        mTotalTransferTimeUs -= entry->mDelayUs;
+        mTotalTransferBytes -= entry->mNumBytes;
+        mBandwidthHistory.erase(mBandwidthHistory.begin());
+        --mNumBandwidthHistoryItems;
+    }
+}
+
 DecryptHandle* NuHTTPDataSource::DrmInitialization(DrmManagerClient* client) {
     if (client == NULL) {
         return NULL;
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 93b7a76..c707fdc 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -3,6 +3,7 @@
 #define NU_HTTP_DATA_SOURCE_H_
 
 #include <media/stagefright/DataSource.h>
+#include <utils/List.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
@@ -26,6 +27,10 @@
     virtual status_t getSize(off_t *size);
     virtual uint32_t flags();
 
+    // Returns true if bandwidth could successfully be estimated,
+    // false otherwise.
+    bool estimateBandwidth(int32_t *bandwidth_bps);
+
     virtual DecryptHandle* DrmInitialization(DrmManagerClient *client);
     virtual void getDrmInfo(DecryptHandle **handle, DrmManagerClient **client);
 
@@ -39,6 +44,11 @@
         CONNECTED
     };
 
+    struct BandwidthEntry {
+        int64_t mDelayUs;
+        size_t mNumBytes;
+    };
+
     Mutex mLock;
 
     State mState;
@@ -54,6 +64,11 @@
     off_t mContentLength;
     bool mContentLengthValid;
 
+    List<BandwidthEntry> mBandwidthHistory;
+    size_t mNumBandwidthHistoryItems;
+    int64_t mTotalTransferTimeUs;
+    size_t mTotalTransferBytes;
+
     DecryptHandle *mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
@@ -66,6 +81,7 @@
             off_t offset);
 
     void applyTimeoutResponse();
+    void addBandwidthMeasurement_l(size_t numBytes, int64_t delayUs);
 
     static void MakeFullHeaders(
             const KeyedVector<String8, String8> *overrides,