delay data source creation for GenericSource prepare time

Bug: 16708180

Change-Id: I9d578ef5e2edaed50279d28d3831c68556468f39
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 9df3f53..1616448 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -21,6 +21,7 @@
 
 #include "AnotherPacketSource.h"
 
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -47,33 +48,48 @@
       mIsWidevine(false),
       mUIDValid(uidValid),
       mUID(uid) {
+    resetDataSource();
     DataSource::RegisterDefaultSniffers();
 }
 
-status_t NuPlayer::GenericSource::init(
+void NuPlayer::GenericSource::resetDataSource() {
+    mHTTPService.clear();
+    mUri.clear();
+    mUriHeaders.clear();
+    mFd = -1;
+    mOffset = 0;
+    mLength = 0;
+}
+
+status_t NuPlayer::GenericSource::setDataSource(
         const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
-    mIsWidevine = !strncasecmp(url, "widevine://", 11);
+    resetDataSource();
 
-    AString sniffedMIME;
+    mHTTPService = httpService;
+    mUri = url;
 
-    sp<DataSource> dataSource =
-        DataSource::CreateFromURI(httpService, url, headers, &sniffedMIME);
-
-    if (dataSource == NULL) {
-        return UNKNOWN_ERROR;
+    if (headers) {
+        mUriHeaders = *headers;
     }
 
-    return initFromDataSource(
-            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
+    // delay data source creation to prepareAsync() to avoid blocking
+    // the calling thread in setDataSource for any significant time.
+    return OK;
 }
 
-status_t NuPlayer::GenericSource::init(
+status_t NuPlayer::GenericSource::setDataSource(
         int fd, int64_t offset, int64_t length) {
-    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
+    resetDataSource();
 
-    return initFromDataSource(dataSource, NULL);
+    mFd = dup(fd);
+    mOffset = offset;
+    mLength = length;
+
+    // delay data source creation to prepareAsync() to avoid blocking
+    // the calling thread in setDataSource for any significant time.
+    return OK;
 }
 
 status_t NuPlayer::GenericSource::initFromDataSource(
@@ -143,7 +159,8 @@
 
                 // check if the source requires secure buffers
                 int32_t secure;
-                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) {
+                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
+                        && secure) {
                     mIsWidevine = true;
                     if (mUIDValid) {
                         extractor->setUID(mUID);
@@ -166,7 +183,8 @@
     return OK;
 }
 
-status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
+status_t NuPlayer::GenericSource::setBuffers(
+        bool audio, Vector<MediaBuffer *> &buffers) {
     if (mIsWidevine && !audio) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
@@ -177,6 +195,38 @@
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    // delayed data source creation
+    AString sniffedMIME;
+    sp<DataSource> dataSource;
+
+    if (!mUri.empty()) {
+        mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
+
+        dataSource = DataSource::CreateFromURI(
+               mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME);
+    } else {
+        // set to false first, if the extractor
+        // comes back as secure, set it to true then.
+        mIsWidevine = false;
+
+        dataSource = new FileSource(mFd, mOffset, mLength);
+    }
+
+    if (dataSource == NULL) {
+        ALOGE("Failed to create data source!");
+        notifyPrepared(UNKNOWN_ERROR);
+        return;
+    }
+
+    status_t err = initFromDataSource(
+            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
+
+    if (err != OK) {
+        ALOGE("Failed to init from data source!");
+        notifyPrepared(err);
+        return;
+    }
+
     if (mVideoTrack.mSource != NULL) {
         sp<MetaData> meta = mVideoTrack.mSource->getFormat();
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 76e628b..44d690e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -30,18 +30,19 @@
 struct AnotherPacketSource;
 struct ARTSPController;
 struct DataSource;
+struct IMediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
 
-    status_t init(
+    status_t setDataSource(
             const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers);
 
-    status_t init(int fd, int64_t offset, int64_t length);
+    status_t setDataSource(int fd, int64_t offset, int64_t length);
 
     virtual void prepareAsync();
 
@@ -96,6 +97,14 @@
     bool mIsWidevine;
     bool mUIDValid;
     uid_t mUID;
+    sp<IMediaHTTPService> mHTTPService;
+    AString mUri;
+    KeyedVector<String8, String8> mUriHeaders;
+    int mFd;
+    int64_t mOffset;
+    int64_t mLength;
+
+    void resetDataSource();
 
     status_t initFromDataSource(
             const sp<DataSource> &dataSource,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ba6fb7d..fe115c6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -232,12 +232,12 @@
         // The correct flags will be updated in Source::kWhatFlagsChanged
         // handler when  GenericSource is prepared.
 
-        status_t err = genericSource->init(httpService, url, headers);
+        status_t err = genericSource->setDataSource(httpService, url, headers);
 
         if (err == OK) {
             source = genericSource;
         } else {
-            ALOGE("Failed to initialize generic source!");
+            ALOGE("Failed to set data source!");
         }
     }
     msg->setObject("source", source);
@@ -252,10 +252,10 @@
     sp<GenericSource> source =
             new GenericSource(notify, mUIDValid, mUID);
 
-    status_t err = source->init(fd, offset, length);
+    status_t err = source->setDataSource(fd, offset, length);
 
     if (err != OK) {
-        ALOGE("Failed to initialize generic source!");
+        ALOGE("Failed to set data source!");
         source = NULL;
     }