Split datasource out of libstagefright

into libdatasource, which contains:
  DataSourceFactory
  (Clear)FileSource
  (Clear)MediaHTTP
  DataURISource
  HTTPBase
  NuCachedSource2

This is needed to break a circular dependency in an upcoming CL.

Test: build, boot

Change-Id: I34d9937235c78f18f51b18945342a0743e209577
diff --git a/media/libdatasource/Android.bp b/media/libdatasource/Android.bp
new file mode 100644
index 0000000..dd8ef74
--- /dev/null
+++ b/media/libdatasource/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+    name: "libdatasource",
+
+    srcs: [
+        "ClearFileSource.cpp",
+        "ClearMediaHTTP.cpp",
+        "DataSourceFactory.cpp",
+        "DataURISource.cpp",
+        "FileSource.cpp",
+        "HTTPBase.cpp",
+        "MediaHTTP.cpp",
+        "NuCachedSource2.cpp",
+    ],
+
+    aidl: {
+        local_include_dirs: ["aidl"],
+        export_aidl_headers: true,
+    },
+
+    header_libs: [
+        "libstagefright_headers",
+        "media_ndk_headers",
+        "libmedia_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libstagefright_headers",
+        "media_ndk_headers",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libdrmframework",
+        "libutils",
+        "libstagefright_foundation",
+        "libdl",
+    ],
+
+    static_libs: [
+        "libc_malloc_debug_backtrace",  // for memory heap analysis
+        "libmedia_midiiowrapper",
+    ],
+
+    local_include_dirs: [
+        "include",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libdatasource/ClearFileSource.cpp b/media/libdatasource/ClearFileSource.cpp
new file mode 100644
index 0000000..afafa23
--- /dev/null
+++ b/media/libdatasource/ClearFileSource.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ClearFileSource"
+#include <utils/Log.h>
+
+#include <datasource/ClearFileSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/FoundationUtils.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+ClearFileSource::ClearFileSource(const char *filename)
+    : mFd(-1),
+      mOffset(0),
+      mLength(-1),
+      mName("<null>") {
+
+    if (filename) {
+        mName = String8::format("FileSource(%s)", filename);
+    }
+    ALOGV("%s", filename);
+    mFd = open(filename, O_LARGEFILE | O_RDONLY);
+
+    if (mFd >= 0) {
+        mLength = lseek64(mFd, 0, SEEK_END);
+    } else {
+        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
+    }
+}
+
+ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
+    : mFd(fd),
+      mOffset(offset),
+      mLength(length),
+      mName("<null>") {
+    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
+    if (mOffset < 0) {
+        mOffset = 0;
+    }
+    if (mLength < 0) {
+        mLength = 0;
+    }
+    if (mLength > INT64_MAX - mOffset) {
+        mLength = INT64_MAX - mOffset;
+    }
+    struct stat s;
+    if (fstat(fd, &s) == 0) {
+        if (mOffset > s.st_size) {
+            mOffset = s.st_size;
+            mLength = 0;
+        }
+        if (mOffset + mLength > s.st_size) {
+            mLength = s.st_size - mOffset;
+        }
+    }
+    if (mOffset != offset || mLength != length) {
+        ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
+                (long long) offset, (long long) length,
+                (long long) mOffset, (long long) mLength);
+    }
+
+    mName = String8::format(
+            "FileSource(fd(%s), %lld, %lld)",
+            nameForFd(fd).c_str(),
+            (long long) mOffset,
+            (long long) mLength);
+
+}
+
+ClearFileSource::~ClearFileSource() {
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
+    }
+}
+
+status_t ClearFileSource::initCheck() const {
+    return mFd >= 0 ? OK : NO_INIT;
+}
+
+ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    if (mLength >= 0) {
+        if (offset >= mLength) {
+            return 0;  // read beyond EOF.
+        }
+        uint64_t numAvailable = mLength - offset;
+        if ((uint64_t)size > numAvailable) {
+            size = numAvailable;
+        }
+    }
+    return readAt_l(offset, data, size);
+}
+
+ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
+    off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
+    if (result == -1) {
+        ALOGE("seek to %lld failed", (long long)(offset + mOffset));
+        return UNKNOWN_ERROR;
+    }
+
+    return ::read(mFd, data, size);
+}
+
+status_t ClearFileSource::getSize(off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    *size = mLength;
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libdatasource/ClearMediaHTTP.cpp b/media/libdatasource/ClearMediaHTTP.cpp
new file mode 100644
index 0000000..7249c84
--- /dev/null
+++ b/media/libdatasource/ClearMediaHTTP.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ClearMediaHTTP"
+#include <utils/Log.h>
+
+#include <datasource/ClearMediaHTTP.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/FoundationUtils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
+    : mInitCheck((conn != NULL) ? OK : NO_INIT),
+      mHTTPConnection(conn),
+      mCachedSizeValid(false),
+      mCachedSize(0ll) {
+}
+
+ClearMediaHTTP::~ClearMediaHTTP() {
+}
+
+status_t ClearMediaHTTP::connect(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t /* offset */) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    KeyedVector<String8, String8> extHeaders;
+    if (headers != NULL) {
+        extHeaders = *headers;
+    }
+
+    if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
+        extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
+    }
+
+    mLastURI = uri;
+    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+    // as part of the above assignment. Ensure no accidental later use.
+    uri = NULL;
+
+    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
+
+    mLastHeaders = extHeaders;
+
+    mCachedSizeValid = false;
+
+    if (success) {
+        AString sanitized = uriDebugString(mLastURI);
+        mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
+    }
+
+    return success ? OK : UNKNOWN_ERROR;
+}
+
+void ClearMediaHTTP::close() {
+    disconnect();
+}
+
+void ClearMediaHTTP::disconnect() {
+    mName = String8("ClearMediaHTTP(<disconnected>)");
+    if (mInitCheck != OK) {
+        return;
+    }
+
+    mHTTPConnection->disconnect();
+}
+
+status_t ClearMediaHTTP::initCheck() const {
+    return mInitCheck;
+}
+
+ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    size_t numBytesRead = 0;
+    while (numBytesRead < size) {
+        size_t copy = size - numBytesRead;
+
+        if (copy > 64 * 1024) {
+            // limit the buffer sizes transferred across binder boundaries
+            // to avoid spurious transaction failures.
+            copy = 64 * 1024;
+        }
+
+        ssize_t n = mHTTPConnection->readAt(
+                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+        if (n < 0) {
+            return n;
+        } else if (n == 0) {
+            break;
+        }
+
+        numBytesRead += n;
+    }
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    addBandwidthMeasurement(numBytesRead, delayUs);
+
+    return numBytesRead;
+}
+
+status_t ClearMediaHTTP::getSize(off64_t *size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    // Caching the returned size so that it stays valid even after a
+    // disconnect. NuCachedSource2 relies on this.
+
+    if (!mCachedSizeValid) {
+        mCachedSize = mHTTPConnection->getSize();
+        mCachedSizeValid = true;
+    }
+
+    *size = mCachedSize;
+
+    return *size < 0 ? *size : static_cast<status_t>(OK);
+}
+
+uint32_t ClearMediaHTTP::flags() {
+    return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
+    return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+
+String8 ClearMediaHTTP::getUri() {
+    if (mInitCheck != OK) {
+        return String8::empty();
+    }
+
+    String8 uri;
+    if (OK == mHTTPConnection->getUri(&uri)) {
+        return uri;
+    }
+    return String8(mLastURI.c_str());
+}
+
+String8 ClearMediaHTTP::getMIMEType() const {
+    if (mInitCheck != OK) {
+        return String8("application/octet-stream");
+    }
+
+    String8 mimeType;
+    status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+    if (err != OK) {
+        return String8("application/octet-stream");
+    }
+
+    return mimeType;
+}
+
+}  // namespace android
diff --git a/media/libdatasource/DataSourceFactory.cpp b/media/libdatasource/DataSourceFactory.cpp
new file mode 100644
index 0000000..8c772dd
--- /dev/null
+++ b/media/libdatasource/DataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+
+#include <datasource/DataSourceFactory.h>
+#include <datasource/DataURISource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/FileSource.h>
+#include <datasource/MediaHTTP.h>
+#include <datasource/NuCachedSource2.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> DataSourceFactory::CreateFromURI(
+        const sp<MediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        String8 *contentType,
+        HTTPBase *httpSource) {
+    if (contentType != NULL) {
+        *contentType = "";
+    }
+
+    sp<DataSource> source;
+    if (!strncasecmp("file://", uri, 7)) {
+        source = new FileSource(uri + 7);
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+        if (httpService == NULL) {
+            ALOGE("Invalid http service!");
+            return NULL;
+        }
+
+        if (httpSource == NULL) {
+            sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+            if (conn == NULL) {
+                ALOGE("Failed to make http connection from http service!");
+                return NULL;
+            }
+            httpSource = new MediaHTTP(conn);
+        }
+
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark = false;
+        KeyedVector<String8, String8> nonCacheSpecificHeaders;
+        if (headers != NULL) {
+            nonCacheSpecificHeaders = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &nonCacheSpecificHeaders,
+                    &cacheConfig,
+                    &disconnectAtHighwatermark);
+        }
+
+        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+            ALOGE("Failed to connect http source!");
+            return NULL;
+        }
+
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
+        }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = DataURISource::Create(uri);
+    } else {
+        // Assume it's a filename.
+        source = new FileSource(uri);
+    }
+
+    if (source == NULL || source->initCheck() != OK) {
+        return NULL;
+    }
+
+    return source;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+    sp<FileSource> source = new FileSource(fd, offset, length);
+    return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        return NULL;
+    } else {
+        return new MediaHTTP(conn);
+    }
+}
+
+}  // namespace android
diff --git a/media/libdatasource/DataURISource.cpp b/media/libdatasource/DataURISource.cpp
new file mode 100644
index 0000000..216f3d0
--- /dev/null
+++ b/media/libdatasource/DataURISource.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+#include <datasource/DataURISource.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+
+namespace android {
+
+// static
+sp<DataURISource> DataURISource::Create(const char *uri) {
+    if (strncasecmp("data:", uri, 5)) {
+        return NULL;
+    }
+
+    const char *commaPos = strrchr(uri, ',');
+
+    if (commaPos == NULL) {
+        return NULL;
+    }
+
+    sp<ABuffer> buffer;
+
+    AString tmp(&uri[5], commaPos - &uri[5]);
+
+    if (tmp.endsWith(";base64")) {
+
+        // strip all CR and LF characters.
+        const char *src = commaPos+1;
+        int len = strlen(src) + 1;
+        char *cleansed = (char *) malloc(len);
+        if (cleansed == NULL) return NULL;
+        char *keeping = cleansed;
+        int left = len;
+        for (int i = 0; i < len ; i++)
+        {
+            const char c = *src++;
+            if (c == '\r' || c == '\n') {
+                continue;
+            }
+            *keeping++ = c;
+            left--;
+        }
+        memset(keeping, 0, left);
+
+        AString encoded(cleansed);
+        free(cleansed);
+
+        buffer = decodeBase64(encoded);
+
+        if (buffer == NULL) {
+            ALOGE("Malformed base64 encoded content found.");
+            return NULL;
+        }
+    } else {
+#if 0
+        size_t dataLen = strlen(uri) - tmp.size() - 6;
+        buffer = new ABuffer(dataLen);
+        memcpy(buffer->data(), commaPos + 1, dataLen);
+
+        // unescape
+#else
+        // MediaPlayer doesn't care for this right now as we don't
+        // play any text-based media.
+        return NULL;
+#endif
+    }
+
+    // We don't really care about charset or mime type.
+
+    return new DataURISource(buffer);
+}
+
+DataURISource::DataURISource(const sp<ABuffer> &buffer)
+    : mBuffer(buffer) {
+}
+
+DataURISource::~DataURISource() {
+}
+
+status_t DataURISource::initCheck() const {
+    return OK;
+}
+
+ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) {
+    if ((offset < 0) || (offset >= (off64_t)mBuffer->size())) {
+        return 0;
+    }
+
+    size_t copy = mBuffer->size() - offset;
+    if (copy > size) {
+        copy = size;
+    }
+
+    memcpy(data, mBuffer->data() + offset, copy);
+
+    return copy;
+}
+
+status_t DataURISource::getSize(off64_t *size) {
+    *size = mBuffer->size();
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libdatasource/FileSource.cpp b/media/libdatasource/FileSource.cpp
new file mode 100644
index 0000000..65780e3
--- /dev/null
+++ b/media/libdatasource/FileSource.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 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_NDEBUG 0
+#define LOG_TAG "FileSource"
+#include <utils/Log.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+FileSource::FileSource(const char *filename)
+    : ClearFileSource(filename),
+      mDecryptHandle(NULL),
+      mDrmManagerClient(NULL),
+      mDrmBufOffset(0),
+      mDrmBufSize(0),
+      mDrmBuf(NULL){
+}
+
+FileSource::FileSource(int fd, int64_t offset, int64_t length)
+    : ClearFileSource(fd, offset, length),
+      mDecryptHandle(NULL),
+      mDrmManagerClient(NULL),
+      mDrmBufOffset(0),
+      mDrmBufSize(0),
+      mDrmBuf(NULL) {
+}
+
+FileSource::~FileSource() {
+    if (mDrmBuf != NULL) {
+        delete[] mDrmBuf;
+        mDrmBuf = NULL;
+    }
+
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+
+    if (mDrmManagerClient != NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+}
+
+ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mLength >= 0) {
+        if (offset >= mLength) {
+            return 0;  // read beyond EOF.
+        }
+        uint64_t numAvailable = mLength - offset;
+        if ((uint64_t)size > numAvailable) {
+            size = numAvailable;
+        }
+    }
+
+    if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
+            == mDecryptHandle->decryptApiType) {
+        return readAtDRM_l(offset, data, size);
+   } else {
+        return readAt_l(offset, data, size);
+    }
+}
+
+sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
+    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                mFd, mOffset, mLength, mime);
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
+    size_t DRM_CACHE_SIZE = 1024;
+    if (mDrmBuf == NULL) {
+        mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
+    }
+
+    if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
+            && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
+        /* Use buffered data */
+        memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
+        return size;
+    } else if (size <= DRM_CACHE_SIZE) {
+        /* Buffer new data */
+        mDrmBufOffset =  offset + mOffset;
+        mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
+                DRM_CACHE_SIZE, offset + mOffset);
+        if (mDrmBufSize > 0) {
+            int64_t dataRead = 0;
+            dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
+            memcpy(data, (void*)mDrmBuf, dataRead);
+            return dataRead;
+        } else {
+            return mDrmBufSize;
+        }
+    } else {
+        /* Too big chunk to cache. Call DRM directly */
+        return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
+    }
+}
+
+/* static */
+bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
+    std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
+    sp<DecryptHandle> decryptHandle =
+            drmClient->openDecryptSession(fd, offset, length, mime);
+    bool requiresDrm = false;
+    if (decryptHandle != nullptr) {
+        requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
+        drmClient->closeDecryptSession(decryptHandle);
+    }
+    return requiresDrm;
+}
+
+}  // namespace android
diff --git a/media/libdatasource/HTTPBase.cpp b/media/libdatasource/HTTPBase.cpp
new file mode 100644
index 0000000..ef29c48
--- /dev/null
+++ b/media/libdatasource/HTTPBase.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 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_NDEBUG 0
+#define LOG_TAG "HTTPBase"
+#include <utils/Log.h>
+
+#include <datasource/HTTPBase.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include <cutils/properties.h>
+#include <cutils/qtaguid.h>
+
+namespace android {
+
+HTTPBase::HTTPBase()
+    : mNumBandwidthHistoryItems(0),
+      mTotalTransferTimeUs(0),
+      mTotalTransferBytes(0),
+      mMaxBandwidthHistoryItems(100),
+      mPrevBandwidthMeasureTimeUs(0),
+      mPrevEstimatedBandWidthKbps(0),
+      mBandWidthCollectFreqMs(5000) {
+    mName = String8("HTTPBase(<disconnected>)");
+}
+
+void HTTPBase::addBandwidthMeasurement(
+        size_t numBytes, int64_t delayUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    BandwidthEntry entry;
+    entry.mDelayUs = delayUs;
+    entry.mNumBytes = numBytes;
+    mTotalTransferTimeUs += delayUs;
+    mTotalTransferBytes += numBytes;
+
+    mBandwidthHistory.push_back(entry);
+    if (++mNumBandwidthHistoryItems > mMaxBandwidthHistoryItems) {
+        BandwidthEntry *entry = &*mBandwidthHistory.begin();
+        mTotalTransferTimeUs -= entry->mDelayUs;
+        mTotalTransferBytes -= entry->mNumBytes;
+        mBandwidthHistory.erase(mBandwidthHistory.begin());
+        --mNumBandwidthHistoryItems;
+
+        int64_t timeNowUs = ALooper::GetNowUs();
+        if (timeNowUs - mPrevBandwidthMeasureTimeUs >=
+                mBandWidthCollectFreqMs * 1000LL) {
+
+            if (mPrevBandwidthMeasureTimeUs != 0) {
+                mPrevEstimatedBandWidthKbps =
+                    (mTotalTransferBytes * 8E3 / mTotalTransferTimeUs);
+            }
+            mPrevBandwidthMeasureTimeUs = timeNowUs;
+        }
+    }
+
+}
+
+bool HTTPBase::estimateBandwidth(int32_t *bandwidth_bps) {
+    Mutex::Autolock autoLock(mLock);
+
+    // Do not do bandwidth estimation if we don't have enough samples, or
+    // total bytes download are too small (<64K).
+    // Bandwidth estimation from these samples can often shoot up and cause
+    // unwanted bw adaption behaviors.
+    if (mNumBandwidthHistoryItems < 2 || mTotalTransferBytes < 65536) {
+        return false;
+    }
+
+    *bandwidth_bps = ((double)mTotalTransferBytes * 8E6 / mTotalTransferTimeUs);
+
+    return true;
+}
+
+status_t HTTPBase::getEstimatedBandwidthKbps(int32_t *kbps) {
+    Mutex::Autolock autoLock(mLock);
+    *kbps = mPrevEstimatedBandWidthKbps;
+    return OK;
+}
+
+status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (freqMs < kMinBandwidthCollectFreqMs
+            || freqMs > kMaxBandwidthCollectFreqMs) {
+
+        ALOGE("frequency (%d ms) is out of range [1000, 60000]", freqMs);
+        return BAD_VALUE;
+    }
+
+    ALOGI("frequency set to %d ms", freqMs);
+    mBandWidthCollectFreqMs = freqMs;
+    return OK;
+}
+
+void HTTPBase::setBandwidthHistorySize(size_t numHistoryItems) {
+    mMaxBandwidthHistoryItems = numHistoryItems;
+}
+
+}  // namespace android
diff --git a/media/libdatasource/MediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp
new file mode 100644
index 0000000..e57510d
--- /dev/null
+++ b/media/libdatasource/MediaHTTP.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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_NDEBUG 0
+#define LOG_TAG "MediaHTTP"
+#include <utils/Log.h>
+
+#include <datasource/MediaHTTP.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/FoundationUtils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
+    : ClearMediaHTTP(conn),
+      mDrmManagerClient(NULL) {
+}
+
+MediaHTTP::~MediaHTTP() {
+    clearDRMState_l();
+}
+
+// DRM...
+
+sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                String8(mLastURI.c_str()), mime);
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+void MediaHTTP::clearDRMState_l() {
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+}
+
+}  // namespace android
diff --git a/media/libdatasource/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
new file mode 100644
index 0000000..7f5ae61
--- /dev/null
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NuCachedSource2"
+#include <utils/Log.h>
+
+#include <datasource/NuCachedSource2.h>
+#include <datasource/HTTPBase.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+struct PageCache {
+    explicit PageCache(size_t pageSize);
+    ~PageCache();
+
+    struct Page {
+        void *mData;
+        size_t mSize;
+    };
+
+    Page *acquirePage();
+    void releasePage(Page *page);
+
+    void appendPage(Page *page);
+    size_t releaseFromStart(size_t maxBytes);
+
+    size_t totalSize() const {
+        return mTotalSize;
+    }
+
+    void copy(size_t from, void *data, size_t size);
+
+private:
+    size_t mPageSize;
+    size_t mTotalSize;
+
+    List<Page *> mActivePages;
+    List<Page *> mFreePages;
+
+    void freePages(List<Page *> *list);
+
+    DISALLOW_EVIL_CONSTRUCTORS(PageCache);
+};
+
+PageCache::PageCache(size_t pageSize)
+    : mPageSize(pageSize),
+      mTotalSize(0) {
+}
+
+PageCache::~PageCache() {
+    freePages(&mActivePages);
+    freePages(&mFreePages);
+}
+
+void PageCache::freePages(List<Page *> *list) {
+    List<Page *>::iterator it = list->begin();
+    while (it != list->end()) {
+        Page *page = *it;
+
+        free(page->mData);
+        delete page;
+        page = NULL;
+
+        ++it;
+    }
+}
+
+PageCache::Page *PageCache::acquirePage() {
+    if (!mFreePages.empty()) {
+        List<Page *>::iterator it = mFreePages.begin();
+        Page *page = *it;
+        mFreePages.erase(it);
+
+        return page;
+    }
+
+    Page *page = new Page;
+    page->mData = malloc(mPageSize);
+    page->mSize = 0;
+
+    return page;
+}
+
+void PageCache::releasePage(Page *page) {
+    page->mSize = 0;
+    mFreePages.push_back(page);
+}
+
+void PageCache::appendPage(Page *page) {
+    mTotalSize += page->mSize;
+    mActivePages.push_back(page);
+}
+
+size_t PageCache::releaseFromStart(size_t maxBytes) {
+    size_t bytesReleased = 0;
+
+    while (maxBytes > 0 && !mActivePages.empty()) {
+        List<Page *>::iterator it = mActivePages.begin();
+
+        Page *page = *it;
+
+        if (maxBytes < page->mSize) {
+            break;
+        }
+
+        mActivePages.erase(it);
+
+        maxBytes -= page->mSize;
+        bytesReleased += page->mSize;
+
+        releasePage(page);
+    }
+
+    mTotalSize -= bytesReleased;
+    return bytesReleased;
+}
+
+void PageCache::copy(size_t from, void *data, size_t size) {
+    ALOGV("copy from %zu size %zu", from, size);
+
+    if (size == 0) {
+        return;
+    }
+
+    CHECK_LE(from + size, mTotalSize);
+
+    size_t offset = 0;
+    List<Page *>::iterator it = mActivePages.begin();
+    while (from >= offset + (*it)->mSize) {
+        offset += (*it)->mSize;
+        ++it;
+    }
+
+    size_t delta = from - offset;
+    size_t avail = (*it)->mSize - delta;
+
+    if (avail >= size) {
+        memcpy(data, (const uint8_t *)(*it)->mData + delta, size);
+        return;
+    }
+
+    memcpy(data, (const uint8_t *)(*it)->mData + delta, avail);
+    ++it;
+    data = (uint8_t *)data + avail;
+    size -= avail;
+
+    while (size > 0) {
+        size_t copy = (*it)->mSize;
+        if (copy > size) {
+            copy = size;
+        }
+        memcpy(data, (*it)->mData, copy);
+        data = (uint8_t *)data + copy;
+        size -= copy;
+        ++it;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+NuCachedSource2::NuCachedSource2(
+        const sp<DataSource> &source,
+        const char *cacheConfig,
+        bool disconnectAtHighwatermark)
+    : mSource(source),
+      mReflector(new AHandlerReflector<NuCachedSource2>(this)),
+      mLooper(new ALooper),
+      mCache(new PageCache(kPageSize)),
+      mCacheOffset(0),
+      mFinalStatus(OK),
+      mLastAccessPos(0),
+      mFetching(true),
+      mDisconnecting(false),
+      mLastFetchTimeUs(-1),
+      mNumRetriesLeft(kMaxNumRetries),
+      mHighwaterThresholdBytes(kDefaultHighWaterThreshold),
+      mLowwaterThresholdBytes(kDefaultLowWaterThreshold),
+      mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs),
+      mDisconnectAtHighwatermark(disconnectAtHighwatermark) {
+    // We are NOT going to support disconnect-at-highwatermark indefinitely
+    // and we are not guaranteeing support for client-specified cache
+    // parameters. Both of these are temporary measures to solve a specific
+    // problem that will be solved in a better way going forward.
+
+    updateCacheParamsFromSystemProperty();
+
+    if (cacheConfig != NULL) {
+        updateCacheParamsFromString(cacheConfig);
+    }
+
+    if (mDisconnectAtHighwatermark) {
+        // Makes no sense to disconnect and do keep-alives...
+        mKeepAliveIntervalUs = 0;
+    }
+
+    mLooper->setName("NuCachedSource2");
+    mLooper->registerHandler(mReflector);
+
+    // Since it may not be obvious why our looper thread needs to be
+    // able to call into java since it doesn't appear to do so at all...
+    // IMediaHTTPConnection may be (and most likely is) implemented in JAVA
+    // and a local JAVA IBinder will call directly into JNI methods.
+    // So whenever we call DataSource::readAt it may end up in a call to
+    // IMediaHTTPConnection::readAt and therefore call back into JAVA.
+    mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
+
+    mName = String8::format("NuCachedSource2(%s)", mSource->toString().string());
+}
+
+NuCachedSource2::~NuCachedSource2() {
+    mLooper->stop();
+    mLooper->unregisterHandler(mReflector->id());
+
+    delete mCache;
+    mCache = NULL;
+}
+
+// static
+sp<NuCachedSource2> NuCachedSource2::Create(
+        const sp<DataSource> &source,
+        const char *cacheConfig,
+        bool disconnectAtHighwatermark) {
+    sp<NuCachedSource2> instance = new NuCachedSource2(
+            source, cacheConfig, disconnectAtHighwatermark);
+    Mutex::Autolock autoLock(instance->mLock);
+    (new AMessage(kWhatFetchMore, instance->mReflector))->post();
+    return instance;
+}
+
+status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
+    if (mSource->flags() & kIsHTTPBasedSource) {
+        HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
+        return source->getEstimatedBandwidthKbps(kbps);
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+void NuCachedSource2::close() {
+    disconnect();
+}
+
+void NuCachedSource2::disconnect() {
+    if (mSource->flags() & kIsHTTPBasedSource) {
+        ALOGV("disconnecting HTTPBasedSource");
+
+        {
+            Mutex::Autolock autoLock(mLock);
+            // set mDisconnecting to true, if a fetch returns after
+            // this, the source will be marked as EOS.
+            mDisconnecting = true;
+
+            // explicitly signal mCondition so that the pending readAt()
+            // will immediately return
+            mCondition.signal();
+        }
+
+        // explicitly disconnect from the source, to allow any
+        // pending reads to return more promptly
+        static_cast<HTTPBase *>(mSource.get())->disconnect();
+    }
+}
+
+status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) {
+    if (mSource->flags() & kIsHTTPBasedSource) {
+        HTTPBase *source = static_cast<HTTPBase *>(mSource.get());
+        return source->setBandwidthStatCollectFreq(freqMs);
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+status_t NuCachedSource2::initCheck() const {
+    return mSource->initCheck();
+}
+
+status_t NuCachedSource2::getSize(off64_t *size) {
+    return mSource->getSize(size);
+}
+
+uint32_t NuCachedSource2::flags() {
+    // Remove HTTP related flags since NuCachedSource2 is not HTTP-based.
+    uint32_t flags = mSource->flags() & ~(kWantsPrefetching | kIsHTTPBasedSource);
+    return (flags | kIsCachingDataSource);
+}
+
+void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatFetchMore:
+        {
+            onFetch();
+            break;
+        }
+
+        case kWhatRead:
+        {
+            onRead(msg);
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+void NuCachedSource2::fetchInternal() {
+    ALOGV("fetchInternal");
+
+    bool reconnect = false;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+        CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
+
+        if (mFinalStatus != OK) {
+            --mNumRetriesLeft;
+
+            reconnect = true;
+        }
+    }
+
+    if (reconnect) {
+        status_t err =
+            mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
+
+        Mutex::Autolock autoLock(mLock);
+
+        if (mDisconnecting) {
+            mNumRetriesLeft = 0;
+            mFinalStatus = ERROR_END_OF_STREAM;
+            return;
+        } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
+            // These are errors that are not likely to go away even if we
+            // retry, i.e. the server doesn't support range requests or similar.
+            mNumRetriesLeft = 0;
+            return;
+        } else if (err != OK) {
+            ALOGI("The attempt to reconnect failed, %d retries remaining",
+                 mNumRetriesLeft);
+
+            return;
+        }
+    }
+
+    PageCache::Page *page = mCache->acquirePage();
+
+    ssize_t n = mSource->readAt(
+            mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (n == 0 || mDisconnecting) {
+        ALOGI("caching reached eos.");
+
+        mNumRetriesLeft = 0;
+        mFinalStatus = ERROR_END_OF_STREAM;
+
+        mCache->releasePage(page);
+    } else if (n < 0) {
+        mFinalStatus = n;
+        if (n == ERROR_UNSUPPORTED || n == -EPIPE) {
+            // These are errors that are not likely to go away even if we
+            // retry, i.e. the server doesn't support range requests or similar.
+            mNumRetriesLeft = 0;
+        }
+
+        ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft);
+        mCache->releasePage(page);
+    } else {
+        if (mFinalStatus != OK) {
+            ALOGI("retrying a previously failed read succeeded.");
+        }
+        mNumRetriesLeft = kMaxNumRetries;
+        mFinalStatus = OK;
+
+        page->mSize = n;
+        mCache->appendPage(page);
+    }
+}
+
+void NuCachedSource2::onFetch() {
+    ALOGV("onFetch");
+
+    if (mFinalStatus != OK && mNumRetriesLeft == 0) {
+        ALOGV("EOS reached, done prefetching for now");
+        mFetching = false;
+    }
+
+    bool keepAlive =
+        !mFetching
+            && mFinalStatus == OK
+            && mKeepAliveIntervalUs > 0
+            && ALooper::GetNowUs() >= mLastFetchTimeUs + mKeepAliveIntervalUs;
+
+    if (mFetching || keepAlive) {
+        if (keepAlive) {
+            ALOGI("Keep alive");
+        }
+
+        fetchInternal();
+
+        mLastFetchTimeUs = ALooper::GetNowUs();
+
+        if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) {
+            ALOGI("Cache full, done prefetching for now");
+            mFetching = false;
+
+            if (mDisconnectAtHighwatermark
+                    && (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
+                ALOGV("Disconnecting at high watermark");
+                static_cast<HTTPBase *>(mSource.get())->disconnect();
+                mFinalStatus = -EAGAIN;
+            }
+        }
+    } else {
+        Mutex::Autolock autoLock(mLock);
+        restartPrefetcherIfNecessary_l();
+    }
+
+    int64_t delayUs;
+    if (mFetching) {
+        if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+            // We failed this time and will try again in 3 seconds.
+            delayUs = 3000000LL;
+        } else {
+            delayUs = 0;
+        }
+    } else {
+        delayUs = 100000LL;
+    }
+
+    (new AMessage(kWhatFetchMore, mReflector))->post(delayUs);
+}
+
+void NuCachedSource2::onRead(const sp<AMessage> &msg) {
+    ALOGV("onRead");
+
+    int64_t offset;
+    CHECK(msg->findInt64("offset", &offset));
+
+    void *data;
+    CHECK(msg->findPointer("data", &data));
+
+    size_t size;
+    CHECK(msg->findSize("size", &size));
+
+    ssize_t result = readInternal(offset, data, size);
+
+    if (result == -EAGAIN) {
+        msg->post(50000);
+        return;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    if (mDisconnecting) {
+        mCondition.signal();
+        return;
+    }
+
+    CHECK(mAsyncResult == NULL);
+
+    mAsyncResult = new AMessage;
+    mAsyncResult->setInt32("result", result);
+
+    mCondition.signal();
+}
+
+void NuCachedSource2::restartPrefetcherIfNecessary_l(
+        bool ignoreLowWaterThreshold, bool force) {
+    static const size_t kGrayArea = 1024 * 1024;
+
+    if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
+        return;
+    }
+
+    if (!ignoreLowWaterThreshold && !force
+            && mCacheOffset + mCache->totalSize() - mLastAccessPos
+                >= mLowwaterThresholdBytes) {
+        return;
+    }
+
+    size_t maxBytes = mLastAccessPos - mCacheOffset;
+
+    if (!force) {
+        if (maxBytes < kGrayArea) {
+            return;
+        }
+
+        maxBytes -= kGrayArea;
+    }
+
+    size_t actualBytes = mCache->releaseFromStart(maxBytes);
+    mCacheOffset += actualBytes;
+
+    ALOGI("restarting prefetcher, totalSize = %zu", mCache->totalSize());
+    mFetching = true;
+}
+
+ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
+    Mutex::Autolock autoSerializer(mSerializer);
+
+    ALOGV("readAt offset %lld, size %zu", (long long)offset, size);
+
+    Mutex::Autolock autoLock(mLock);
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    // If the request can be completely satisfied from the cache, do so.
+
+    if (offset >= mCacheOffset
+            && offset + size <= mCacheOffset + mCache->totalSize()) {
+        size_t delta = offset - mCacheOffset;
+        mCache->copy(delta, data, size);
+
+        mLastAccessPos = offset + size;
+
+        return size;
+    }
+
+    sp<AMessage> msg = new AMessage(kWhatRead, mReflector);
+    msg->setInt64("offset", offset);
+    msg->setPointer("data", data);
+    msg->setSize("size", size);
+
+    CHECK(mAsyncResult == NULL);
+    msg->post();
+
+    while (mAsyncResult == NULL && !mDisconnecting) {
+        mCondition.wait(mLock);
+    }
+
+    if (mDisconnecting) {
+        mAsyncResult.clear();
+        return ERROR_END_OF_STREAM;
+    }
+
+    int32_t result;
+    CHECK(mAsyncResult->findInt32("result", &result));
+
+    mAsyncResult.clear();
+
+    if (result > 0) {
+        mLastAccessPos = offset + result;
+    }
+
+    return (ssize_t)result;
+}
+
+size_t NuCachedSource2::cachedSize() {
+    Mutex::Autolock autoLock(mLock);
+    return mCacheOffset + mCache->totalSize();
+}
+
+status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+    status_t finalStatus = UNKNOWN_ERROR;
+    *size = approxDataRemaining_l(offset, &finalStatus);
+    return finalStatus;
+}
+
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+    Mutex::Autolock autoLock(mLock);
+    return approxDataRemaining_l(mLastAccessPos, finalStatus);
+}
+
+size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
+    *finalStatus = mFinalStatus;
+
+    if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+        // Pretend that everything is fine until we're out of retries.
+        *finalStatus = OK;
+    }
+
+    offset = offset >= 0 ? offset : mLastAccessPos;
+    off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
+    if (offset < lastBytePosCached) {
+        return lastBytePosCached - offset;
+    }
+    return 0;
+}
+
+ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
+    CHECK_LE(size, (size_t)mHighwaterThresholdBytes);
+
+    ALOGV("readInternal offset %lld size %zu", (long long)offset, size);
+
+    Mutex::Autolock autoLock(mLock);
+
+    // If we're disconnecting, return EOS and don't access *data pointer.
+    // data could be on the stack of the caller to NuCachedSource2::readAt(),
+    // which may have exited already.
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    if (!mFetching) {
+        mLastAccessPos = offset;
+        restartPrefetcherIfNecessary_l(
+                false, // ignoreLowWaterThreshold
+                true); // force
+    }
+
+    if (offset < mCacheOffset
+            || offset >= (off64_t)(mCacheOffset + mCache->totalSize())) {
+        static const off64_t kPadding = 256 * 1024;
+
+        // In the presence of multiple decoded streams, once of them will
+        // trigger this seek request, the other one will request data "nearby"
+        // soon, adjust the seek position so that that subsequent request
+        // does not trigger another seek.
+        off64_t seekOffset = (offset > kPadding) ? offset - kPadding : 0;
+
+        seekInternal_l(seekOffset);
+    }
+
+    size_t delta = offset - mCacheOffset;
+
+    if (mFinalStatus != OK && mNumRetriesLeft == 0) {
+        if (delta >= mCache->totalSize()) {
+            return mFinalStatus;
+        }
+
+        size_t avail = mCache->totalSize() - delta;
+
+        if (avail > size) {
+            avail = size;
+        }
+
+        mCache->copy(delta, data, avail);
+
+        return avail;
+    }
+
+    if (offset + size <= mCacheOffset + mCache->totalSize()) {
+        mCache->copy(delta, data, size);
+
+        return size;
+    }
+
+    ALOGV("deferring read");
+
+    return -EAGAIN;
+}
+
+status_t NuCachedSource2::seekInternal_l(off64_t offset) {
+    mLastAccessPos = offset;
+
+    if (offset >= mCacheOffset
+            && offset <= (off64_t)(mCacheOffset + mCache->totalSize())) {
+        return OK;
+    }
+
+    ALOGI("new range: offset= %lld", (long long)offset);
+
+    mCacheOffset = offset;
+
+    size_t totalSize = mCache->totalSize();
+    CHECK_EQ(mCache->releaseFromStart(totalSize), totalSize);
+
+    mNumRetriesLeft = kMaxNumRetries;
+    mFetching = true;
+
+    return OK;
+}
+
+void NuCachedSource2::resumeFetchingIfNecessary() {
+    Mutex::Autolock autoLock(mLock);
+
+    restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
+}
+
+sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) {
+    return mSource->DrmInitialization(mime);
+}
+
+String8 NuCachedSource2::getUri() {
+    return mSource->getUri();
+}
+
+String8 NuCachedSource2::getMIMEType() const {
+    return mSource->getMIMEType();
+}
+
+void NuCachedSource2::updateCacheParamsFromSystemProperty() {
+    char value[PROPERTY_VALUE_MAX];
+    if (!property_get("media.stagefright.cache-params", value, NULL)) {
+        return;
+    }
+
+    updateCacheParamsFromString(value);
+}
+
+void NuCachedSource2::updateCacheParamsFromString(const char *s) {
+    ssize_t lowwaterMarkKb, highwaterMarkKb;
+    int keepAliveSecs;
+
+    if (sscanf(s, "%zd/%zd/%d",
+               &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
+        ALOGE("Failed to parse cache parameters from '%s'.", s);
+        return;
+    }
+
+    if (lowwaterMarkKb >= 0) {
+        mLowwaterThresholdBytes = lowwaterMarkKb * 1024;
+    } else {
+        mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+    }
+
+    if (highwaterMarkKb >= 0) {
+        mHighwaterThresholdBytes = highwaterMarkKb * 1024;
+    } else {
+        mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+    }
+
+    if (mLowwaterThresholdBytes >= mHighwaterThresholdBytes) {
+        ALOGE("Illegal low/highwater marks specified, reverting to defaults.");
+
+        mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+        mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+    }
+
+    if (keepAliveSecs >= 0) {
+        mKeepAliveIntervalUs = keepAliveSecs * 1000000LL;
+    } else {
+        mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
+    }
+
+    ALOGV("lowwater = %zu bytes, highwater = %zu bytes, keepalive = %lld us",
+         mLowwaterThresholdBytes,
+         mHighwaterThresholdBytes,
+         (long long)mKeepAliveIntervalUs);
+}
+
+// static
+void NuCachedSource2::RemoveCacheSpecificHeaders(
+        KeyedVector<String8, String8> *headers,
+        String8 *cacheConfig,
+        bool *disconnectAtHighwatermark) {
+    *cacheConfig = String8();
+    *disconnectAtHighwatermark = false;
+
+    if (headers == NULL) {
+        return;
+    }
+
+    ssize_t index;
+    if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) {
+        *cacheConfig = headers->valueAt(index);
+
+        headers->removeItemsAt(index);
+
+        ALOGV("Using special cache config '%s'", cacheConfig->string());
+    }
+
+    if ((index = headers->indexOfKey(
+                    String8("x-disconnect-at-highwatermark"))) >= 0) {
+        *disconnectAtHighwatermark = true;
+        headers->removeItemsAt(index);
+
+        ALOGV("Client requested disconnection at highwater mark");
+    }
+}
+
+}  // namespace android
diff --git a/media/libdatasource/include/datasource/ClearFileSource.h b/media/libdatasource/include/datasource/ClearFileSource.h
new file mode 100644
index 0000000..be83748
--- /dev/null
+++ b/media/libdatasource/include/datasource/ClearFileSource.h
@@ -0,0 +1,68 @@
+/*
+ * 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 CLEAR_FILE_SOURCE_H_
+
+#define CLEAR_FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ClearFileSource : public DataSource {
+public:
+    ClearFileSource(const char *filename);
+    // ClearFileSource takes ownership and will close the fd
+    ClearFileSource(int fd, int64_t offset, int64_t length);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags() {
+        return kIsLocalFileSource;
+    }
+
+    virtual String8 toString() {
+        return mName;
+    }
+
+protected:
+    virtual ~ClearFileSource();
+    virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
+    int mFd;
+    int64_t mOffset;
+    int64_t mLength;
+    Mutex mLock;
+
+private:
+    String8 mName;
+
+    ClearFileSource(const ClearFileSource &);
+    ClearFileSource &operator=(const ClearFileSource &);
+};
+
+}  // namespace android
+
+#endif  // CLEAR_FILE_SOURCE_H_
+
diff --git a/media/libdatasource/include/datasource/ClearMediaHTTP.h b/media/libdatasource/include/datasource/ClearMediaHTTP.h
new file mode 100644
index 0000000..5440a3a
--- /dev/null
+++ b/media/libdatasource/include/datasource/ClearMediaHTTP.h
@@ -0,0 +1,73 @@
+/*
+ * 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 CLEAR_MEDIA_HTTP_H_
+
+#define CLEAR_MEDIA_HTTP_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "HTTPBase.h"
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+struct ClearMediaHTTP : public HTTPBase {
+    ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    virtual void close();
+
+    virtual void disconnect();
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags();
+
+    virtual status_t reconnectAtOffset(off64_t offset);
+
+protected:
+    virtual ~ClearMediaHTTP();
+
+    virtual String8 getUri();
+    virtual String8 getMIMEType() const;
+
+    AString mLastURI;
+
+private:
+    status_t mInitCheck;
+    sp<MediaHTTPConnection> mHTTPConnection;
+
+    KeyedVector<String8, String8> mLastHeaders;
+
+    bool mCachedSizeValid;
+    off64_t mCachedSize;
+
+    DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
+};
+
+}  // namespace android
+
+#endif  // CLEAR_MEDIA_HTTP_H_
diff --git a/media/libdatasource/include/datasource/DataSourceFactory.h b/media/libdatasource/include/datasource/DataSourceFactory.h
new file mode 100644
index 0000000..6e313d3
--- /dev/null
+++ b/media/libdatasource/include/datasource/DataSourceFactory.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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 DATA_SOURCE_FACTORY_H_
+
+#define DATA_SOURCE_FACTORY_H_
+
+#include <media/DataSource.h>
+#include <sys/types.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class DataSourceFactory {
+public:
+    static sp<DataSource> CreateFromURI(
+            const sp<MediaHTTPService> &httpService,
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_FACTORY_H_
diff --git a/media/libdatasource/include/datasource/DataURISource.h b/media/libdatasource/include/datasource/DataURISource.h
new file mode 100644
index 0000000..cf8d68e
--- /dev/null
+++ b/media/libdatasource/include/datasource/DataURISource.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 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 DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct DataURISource : public DataSource {
+    static sp<DataURISource> Create(const char *uri);
+
+    virtual status_t initCheck() const;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+
+protected:
+    virtual ~DataURISource();
+
+private:
+    sp<ABuffer> mBuffer;
+
+    DataURISource(const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(DataURISource);
+};
+
+}  // namespace android
+
+#endif  // DATA_URI_SOURCE_H_
+
diff --git a/media/libdatasource/include/datasource/FileSource.h b/media/libdatasource/include/datasource/FileSource.h
new file mode 100644
index 0000000..9249842
--- /dev/null
+++ b/media/libdatasource/include/datasource/FileSource.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 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 FILE_SOURCE_H_
+
+#define FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <datasource/ClearFileSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+
+namespace android {
+
+class FileSource : public ClearFileSource {
+public:
+    FileSource(const char *filename);
+    // FileSource takes ownership and will close the fd
+    FileSource(int fd, int64_t offset, int64_t length);
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
+
+    static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
+
+protected:
+    virtual ~FileSource();
+
+private:
+    /*for DRM*/
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+    int64_t mDrmBufOffset;
+    ssize_t mDrmBufSize;
+    unsigned char *mDrmBuf;
+
+    ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
+
+    FileSource(const FileSource &);
+    FileSource &operator=(const FileSource &);
+};
+
+}  // namespace android
+
+#endif  // FILE_SOURCE_H_
+
diff --git a/media/libdatasource/include/datasource/HTTPBase.h b/media/libdatasource/include/datasource/HTTPBase.h
new file mode 100644
index 0000000..8b20187
--- /dev/null
+++ b/media/libdatasource/include/datasource/HTTPBase.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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 HTTP_BASE_H_
+
+#define HTTP_BASE_H_
+
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct HTTPBase : public DataSource {
+    enum Flags {
+        // Don't log any URLs.
+        kFlagIncognito = 1
+    };
+
+    HTTPBase();
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers = NULL,
+            off64_t offset = 0) = 0;
+
+    virtual void disconnect() = 0;
+
+    // Returns true if bandwidth could successfully be estimated,
+    // false otherwise.
+    virtual bool estimateBandwidth(int32_t *bandwidth_bps);
+
+    virtual status_t getEstimatedBandwidthKbps(int32_t *kbps);
+
+    virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
+
+    virtual void setBandwidthHistorySize(size_t numHistoryItems);
+
+    virtual String8 toString() {
+        return mName;
+    }
+
+protected:
+    virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
+    String8 mName;
+
+private:
+    struct BandwidthEntry {
+        int64_t mDelayUs;
+        size_t mNumBytes;
+    };
+
+    Mutex mLock;
+
+    List<BandwidthEntry> mBandwidthHistory;
+    size_t mNumBandwidthHistoryItems;
+    int64_t mTotalTransferTimeUs;
+    size_t mTotalTransferBytes;
+    size_t mMaxBandwidthHistoryItems;
+
+    enum {
+        kMinBandwidthCollectFreqMs = 1000,   // 1 second
+        kMaxBandwidthCollectFreqMs = 60000,  // one minute
+    };
+
+    int64_t mPrevBandwidthMeasureTimeUs;
+    int32_t mPrevEstimatedBandWidthKbps;
+    int32_t mBandWidthCollectFreqMs;
+
+    DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
+};
+
+}  // namespace android
+
+#endif  // HTTP_BASE_H_
diff --git a/media/libdatasource/include/datasource/MediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h
new file mode 100644
index 0000000..60252ce
--- /dev/null
+++ b/media/libdatasource/include/datasource/MediaHTTP.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 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 MEDIA_HTTP_H_
+
+#define MEDIA_HTTP_H_
+
+#include <datasource/ClearMediaHTTP.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+struct MediaHTTP : public ClearMediaHTTP {
+    MediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+protected:
+    virtual ~MediaHTTP();
+
+    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
+
+private:
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+
+    void clearDRMState_l();
+
+    DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_HTTP_H_
diff --git a/media/libdatasource/include/datasource/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
new file mode 100644
index 0000000..596efb8
--- /dev/null
+++ b/media/libdatasource/include/datasource/NuCachedSource2.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 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 NU_CACHED_SOURCE_2_H_
+
+#define NU_CACHED_SOURCE_2_H_
+
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+
+namespace android {
+
+struct ALooper;
+struct PageCache;
+
+struct NuCachedSource2 : public DataSource {
+    static sp<NuCachedSource2> Create(
+            const sp<DataSource> &source,
+            const char *cacheConfig = NULL,
+            bool disconnectAtHighwatermark = false);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual void close();
+
+    virtual void disconnect();
+
+    virtual status_t getSize(off64_t *size);
+    virtual uint32_t flags();
+
+    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
+    virtual String8 getUri();
+
+    virtual String8 getMIMEType() const;
+
+    virtual String8 toString() {
+        return mName;
+    }
+
+    status_t getAvailableSize(off64_t offset, off64_t *size);
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    size_t cachedSize();
+    size_t approxDataRemaining(status_t *finalStatus) const;
+
+    void resumeFetchingIfNecessary();
+
+    // The following methods are supported only if the
+    // data source is HTTP-based; otherwise, ERROR_UNSUPPORTED
+    // is returned.
+    status_t getEstimatedBandwidthKbps(int32_t *kbps);
+    status_t setCacheStatCollectFreq(int32_t freqMs);
+
+    static void RemoveCacheSpecificHeaders(
+            KeyedVector<String8, String8> *headers,
+            String8 *cacheConfig,
+            bool *disconnectAtHighwatermark);
+
+protected:
+    virtual ~NuCachedSource2();
+
+private:
+    friend struct AHandlerReflector<NuCachedSource2>;
+
+    NuCachedSource2(
+            const sp<DataSource> &source,
+            const char *cacheConfig,
+            bool disconnectAtHighwatermark);
+
+    enum {
+        kPageSize                       = 65536,
+        kDefaultHighWaterThreshold      = 20 * 1024 * 1024,
+        kDefaultLowWaterThreshold       = 4 * 1024 * 1024,
+
+        // Read data after a 15 sec timeout whether we're actively
+        // fetching or not.
+        kDefaultKeepAliveIntervalUs     = 15000000,
+    };
+
+    enum {
+        kWhatFetchMore  = 'fetc',
+        kWhatRead       = 'read',
+    };
+
+    enum {
+        kMaxNumRetries = 10,
+    };
+
+    sp<DataSource> mSource;
+    sp<AHandlerReflector<NuCachedSource2> > mReflector;
+    sp<ALooper> mLooper;
+    String8 mName;
+
+    Mutex mSerializer;
+    mutable Mutex mLock;
+    Condition mCondition;
+
+    PageCache *mCache;
+    off64_t mCacheOffset;
+    status_t mFinalStatus;
+    off64_t mLastAccessPos;
+    sp<AMessage> mAsyncResult;
+    bool mFetching;
+    bool mDisconnecting;
+    int64_t mLastFetchTimeUs;
+
+    int32_t mNumRetriesLeft;
+
+    size_t mHighwaterThresholdBytes;
+    size_t mLowwaterThresholdBytes;
+
+    // If the keep-alive interval is 0, keep-alives are disabled.
+    int64_t mKeepAliveIntervalUs;
+
+    bool mDisconnectAtHighwatermark;
+
+    void onMessageReceived(const sp<AMessage> &msg);
+    void onFetch();
+    void onRead(const sp<AMessage> &msg);
+
+    void fetchInternal();
+    ssize_t readInternal(off64_t offset, void *data, size_t size);
+    status_t seekInternal_l(off64_t offset);
+
+    size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
+
+    void restartPrefetcherIfNecessary_l(
+            bool ignoreLowWaterThreshold = false, bool force = false);
+
+    void updateCacheParamsFromSystemProperty();
+    void updateCacheParamsFromString(const char *s);
+
+    DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
+};
+
+}  // namespace android
+
+#endif  // NU_CACHED_SOURCE_2_H_