Home | History | Annotate | Download | only in nuplayer
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "GenericSource"
     19 
     20 #include "GenericSource.h"
     21 
     22 #include "AnotherPacketSource.h"
     23 
     24 #include <media/IMediaHTTPService.h>
     25 #include <media/stagefright/foundation/ABuffer.h>
     26 #include <media/stagefright/foundation/ADebug.h>
     27 #include <media/stagefright/foundation/AMessage.h>
     28 #include <media/stagefright/DataSource.h>
     29 #include <media/stagefright/FileSource.h>
     30 #include <media/stagefright/MediaBuffer.h>
     31 #include <media/stagefright/MediaDefs.h>
     32 #include <media/stagefright/MediaExtractor.h>
     33 #include <media/stagefright/MediaSource.h>
     34 #include <media/stagefright/MetaData.h>
     35 #include <media/stagefright/Utils.h>
     36 #include "../../libstagefright/include/DRMExtractor.h"
     37 #include "../../libstagefright/include/NuCachedSource2.h"
     38 #include "../../libstagefright/include/WVMExtractor.h"
     39 #include "../../libstagefright/include/HTTPBase.h"
     40 
     41 namespace android {
     42 
     43 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
     44 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
     45 static const ssize_t kLowWaterMarkBytes = 40000;
     46 static const ssize_t kHighWaterMarkBytes = 200000;
     47 
     48 NuPlayer::GenericSource::GenericSource(
     49         const sp<AMessage> &notify,
     50         bool uidValid,
     51         uid_t uid)
     52     : Source(notify),
     53       mAudioTimeUs(0),
     54       mAudioLastDequeueTimeUs(0),
     55       mVideoTimeUs(0),
     56       mVideoLastDequeueTimeUs(0),
     57       mFetchSubtitleDataGeneration(0),
     58       mFetchTimedTextDataGeneration(0),
     59       mDurationUs(0ll),
     60       mAudioIsVorbis(false),
     61       mIsWidevine(false),
     62       mIsSecure(false),
     63       mIsStreaming(false),
     64       mUIDValid(uidValid),
     65       mUID(uid),
     66       mFd(-1),
     67       mDrmManagerClient(NULL),
     68       mMetaDataSize(-1ll),
     69       mBitrate(-1ll),
     70       mPollBufferingGeneration(0),
     71       mPendingReadBufferTypes(0),
     72       mBuffering(false),
     73       mPrepareBuffering(false) {
     74     resetDataSource();
     75     DataSource::RegisterDefaultSniffers();
     76 }
     77 
     78 void NuPlayer::GenericSource::resetDataSource() {
     79     mHTTPService.clear();
     80     mHttpSource.clear();
     81     mUri.clear();
     82     mUriHeaders.clear();
     83     if (mFd >= 0) {
     84         close(mFd);
     85         mFd = -1;
     86     }
     87     mOffset = 0;
     88     mLength = 0;
     89     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
     90     mDecryptHandle = NULL;
     91     mDrmManagerClient = NULL;
     92     mStarted = false;
     93     mStopRead = true;
     94 }
     95 
     96 status_t NuPlayer::GenericSource::setDataSource(
     97         const sp<IMediaHTTPService> &httpService,
     98         const char *url,
     99         const KeyedVector<String8, String8> *headers) {
    100     resetDataSource();
    101 
    102     mHTTPService = httpService;
    103     mUri = url;
    104 
    105     if (headers) {
    106         mUriHeaders = *headers;
    107     }
    108 
    109     // delay data source creation to prepareAsync() to avoid blocking
    110     // the calling thread in setDataSource for any significant time.
    111     return OK;
    112 }
    113 
    114 status_t NuPlayer::GenericSource::setDataSource(
    115         int fd, int64_t offset, int64_t length) {
    116     resetDataSource();
    117 
    118     mFd = dup(fd);
    119     mOffset = offset;
    120     mLength = length;
    121 
    122     // delay data source creation to prepareAsync() to avoid blocking
    123     // the calling thread in setDataSource for any significant time.
    124     return OK;
    125 }
    126 
    127 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
    128     return mFileMeta;
    129 }
    130 
    131 status_t NuPlayer::GenericSource::initFromDataSource() {
    132     sp<MediaExtractor> extractor;
    133 
    134     CHECK(mDataSource != NULL);
    135 
    136     if (mIsWidevine) {
    137         String8 mimeType;
    138         float confidence;
    139         sp<AMessage> dummy;
    140         bool success;
    141 
    142         success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
    143         if (!success
    144                 || strcasecmp(
    145                     mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
    146             ALOGE("unsupported widevine mime: %s", mimeType.string());
    147             return UNKNOWN_ERROR;
    148         }
    149 
    150         mWVMExtractor = new WVMExtractor(mDataSource);
    151         mWVMExtractor->setAdaptiveStreamingMode(true);
    152         if (mUIDValid) {
    153             mWVMExtractor->setUID(mUID);
    154         }
    155         extractor = mWVMExtractor;
    156     } else {
    157         extractor = MediaExtractor::Create(mDataSource,
    158                 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
    159     }
    160 
    161     if (extractor == NULL) {
    162         return UNKNOWN_ERROR;
    163     }
    164 
    165     if (extractor->getDrmFlag()) {
    166         checkDrmStatus(mDataSource);
    167     }
    168 
    169     mFileMeta = extractor->getMetaData();
    170     if (mFileMeta != NULL) {
    171         int64_t duration;
    172         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
    173             mDurationUs = duration;
    174         }
    175 
    176         if (!mIsWidevine) {
    177             // Check mime to see if we actually have a widevine source.
    178             // If the data source is not URL-type (eg. file source), we
    179             // won't be able to tell until now.
    180             const char *fileMime;
    181             if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
    182                     && !strncasecmp(fileMime, "video/wvm", 9)) {
    183                 mIsWidevine = true;
    184                 if (!mUri.empty()) {
    185                   // streaming, but the app forgot to specify widevine:// url
    186                   mWVMExtractor = static_cast<WVMExtractor *>(extractor.get());
    187                   mWVMExtractor->setAdaptiveStreamingMode(true);
    188                   if (mUIDValid) {
    189                     mWVMExtractor->setUID(mUID);
    190                   }
    191                 }
    192             }
    193         }
    194     }
    195 
    196     int32_t totalBitrate = 0;
    197 
    198     size_t numtracks = extractor->countTracks();
    199     if (numtracks == 0) {
    200         return UNKNOWN_ERROR;
    201     }
    202 
    203     for (size_t i = 0; i < numtracks; ++i) {
    204         sp<MediaSource> track = extractor->getTrack(i);
    205 
    206         sp<MetaData> meta = extractor->getTrackMetaData(i);
    207 
    208         const char *mime;
    209         CHECK(meta->findCString(kKeyMIMEType, &mime));
    210 
    211         // Do the string compare immediately with "mime",
    212         // we can't assume "mime" would stay valid after another
    213         // extractor operation, some extractors might modify meta
    214         // during getTrack() and make it invalid.
    215         if (!strncasecmp(mime, "audio/", 6)) {
    216             if (mAudioTrack.mSource == NULL) {
    217                 mAudioTrack.mIndex = i;
    218                 mAudioTrack.mSource = track;
    219                 mAudioTrack.mPackets =
    220                     new AnotherPacketSource(mAudioTrack.mSource->getFormat());
    221 
    222                 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
    223                     mAudioIsVorbis = true;
    224                 } else {
    225                     mAudioIsVorbis = false;
    226                 }
    227             }
    228         } else if (!strncasecmp(mime, "video/", 6)) {
    229             if (mVideoTrack.mSource == NULL) {
    230                 mVideoTrack.mIndex = i;
    231                 mVideoTrack.mSource = track;
    232                 mVideoTrack.mPackets =
    233                     new AnotherPacketSource(mVideoTrack.mSource->getFormat());
    234 
    235                 // check if the source requires secure buffers
    236                 int32_t secure;
    237                 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
    238                         && secure) {
    239                     mIsSecure = true;
    240                     if (mUIDValid) {
    241                         extractor->setUID(mUID);
    242                     }
    243                 }
    244             }
    245         }
    246 
    247         if (track != NULL) {
    248             mSources.push(track);
    249             int64_t durationUs;
    250             if (meta->findInt64(kKeyDuration, &durationUs)) {
    251                 if (durationUs > mDurationUs) {
    252                     mDurationUs = durationUs;
    253                 }
    254             }
    255 
    256             int32_t bitrate;
    257             if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
    258                 totalBitrate += bitrate;
    259             } else {
    260                 totalBitrate = -1;
    261             }
    262         }
    263     }
    264 
    265     mBitrate = totalBitrate;
    266 
    267     return OK;
    268 }
    269 
    270 status_t NuPlayer::GenericSource::startSources() {
    271     // Start the selected A/V tracks now before we start buffering.
    272     // Widevine sources might re-initialize crypto when starting, if we delay
    273     // this to start(), all data buffered during prepare would be wasted.
    274     // (We don't actually start reading until start().)
    275     if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
    276         ALOGE("failed to start audio track!");
    277         return UNKNOWN_ERROR;
    278     }
    279 
    280     if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
    281         ALOGE("failed to start video track!");
    282         return UNKNOWN_ERROR;
    283     }
    284 
    285     return OK;
    286 }
    287 
    288 void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
    289     dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
    290     if (mDecryptHandle != NULL) {
    291         CHECK(mDrmManagerClient);
    292         if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
    293             sp<AMessage> msg = dupNotify();
    294             msg->setInt32("what", kWhatDrmNoLicense);
    295             msg->post();
    296         }
    297     }
    298 }
    299 
    300 int64_t NuPlayer::GenericSource::getLastReadPosition() {
    301     if (mAudioTrack.mSource != NULL) {
    302         return mAudioTimeUs;
    303     } else if (mVideoTrack.mSource != NULL) {
    304         return mVideoTimeUs;
    305     } else {
    306         return 0;
    307     }
    308 }
    309 
    310 status_t NuPlayer::GenericSource::setBuffers(
    311         bool audio, Vector<MediaBuffer *> &buffers) {
    312     if (mIsSecure && !audio) {
    313         return mVideoTrack.mSource->setBuffers(buffers);
    314     }
    315     return INVALID_OPERATION;
    316 }
    317 
    318 NuPlayer::GenericSource::~GenericSource() {
    319     if (mLooper != NULL) {
    320         mLooper->unregisterHandler(id());
    321         mLooper->stop();
    322     }
    323     resetDataSource();
    324 }
    325 
    326 void NuPlayer::GenericSource::prepareAsync() {
    327     if (mLooper == NULL) {
    328         mLooper = new ALooper;
    329         mLooper->setName("generic");
    330         mLooper->start();
    331 
    332         mLooper->registerHandler(this);
    333     }
    334 
    335     sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
    336     msg->post();
    337 }
    338 
    339 void NuPlayer::GenericSource::onPrepareAsync() {
    340     // delayed data source creation
    341     if (mDataSource == NULL) {
    342         // set to false first, if the extractor
    343         // comes back as secure, set it to true then.
    344         mIsSecure = false;
    345 
    346         if (!mUri.empty()) {
    347             const char* uri = mUri.c_str();
    348             mIsWidevine = !strncasecmp(uri, "widevine://", 11);
    349 
    350             if (!strncasecmp("http://", uri, 7)
    351                     || !strncasecmp("https://", uri, 8)
    352                     || mIsWidevine) {
    353                 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
    354                 if (mHttpSource == NULL) {
    355                     ALOGE("Failed to create http source!");
    356                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
    357                     return;
    358                 }
    359             }
    360 
    361             mDataSource = DataSource::CreateFromURI(
    362                    mHTTPService, uri, &mUriHeaders, &mContentType,
    363                    static_cast<HTTPBase *>(mHttpSource.get()));
    364         } else {
    365             mIsWidevine = false;
    366 
    367             mDataSource = new FileSource(mFd, mOffset, mLength);
    368             mFd = -1;
    369         }
    370 
    371         if (mDataSource == NULL) {
    372             ALOGE("Failed to create data source!");
    373             notifyPreparedAndCleanup(UNKNOWN_ERROR);
    374             return;
    375         }
    376 
    377         if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
    378             mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
    379         }
    380 
    381         // For widevine or other cached streaming cases, we need to wait for
    382         // enough buffering before reporting prepared.
    383         // Note that even when URL doesn't start with widevine://, mIsWidevine
    384         // could still be set to true later, if the streaming or file source
    385         // is sniffed to be widevine. We don't want to buffer for file source
    386         // in that case, so must check the flag now.
    387         mIsStreaming = (mIsWidevine || mCachedSource != NULL);
    388     }
    389 
    390     // check initial caching status
    391     status_t err = prefillCacheIfNecessary();
    392     if (err != OK) {
    393         if (err == -EAGAIN) {
    394             (new AMessage(kWhatPrepareAsync, id()))->post(200000);
    395         } else {
    396             ALOGE("Failed to prefill data cache!");
    397             notifyPreparedAndCleanup(UNKNOWN_ERROR);
    398         }
    399         return;
    400     }
    401 
    402     // init extrator from data source
    403     err = initFromDataSource();
    404 
    405     if (err != OK) {
    406         ALOGE("Failed to init from data source!");
    407         notifyPreparedAndCleanup(err);
    408         return;
    409     }
    410 
    411     if (mVideoTrack.mSource != NULL) {
    412         sp<MetaData> meta = doGetFormatMeta(false /* audio */);
    413         sp<AMessage> msg = new AMessage;
    414         err = convertMetaDataToMessage(meta, &msg);
    415         if(err != OK) {
    416             notifyPreparedAndCleanup(err);
    417             return;
    418         }
    419         notifyVideoSizeChanged(msg);
    420     }
    421 
    422     notifyFlagsChanged(
    423             (mIsSecure ? FLAG_SECURE : 0)
    424             | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
    425             | FLAG_CAN_PAUSE
    426             | FLAG_CAN_SEEK_BACKWARD
    427             | FLAG_CAN_SEEK_FORWARD
    428             | FLAG_CAN_SEEK);
    429 
    430     if (mIsSecure) {
    431         // secure decoders must be instantiated before starting widevine source
    432         sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, id());
    433         notifyInstantiateSecureDecoders(reply);
    434     } else {
    435         finishPrepareAsync();
    436     }
    437 }
    438 
    439 void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
    440     if (err != OK) {
    441         ALOGE("Failed to instantiate secure decoders!");
    442         notifyPreparedAndCleanup(err);
    443         return;
    444     }
    445     finishPrepareAsync();
    446 }
    447 
    448 void NuPlayer::GenericSource::finishPrepareAsync() {
    449     status_t err = startSources();
    450     if (err != OK) {
    451         ALOGE("Failed to init start data source!");
    452         notifyPreparedAndCleanup(err);
    453         return;
    454     }
    455 
    456     if (mIsStreaming) {
    457         mPrepareBuffering = true;
    458 
    459         ensureCacheIsFetching();
    460         restartPollBuffering();
    461     } else {
    462         notifyPrepared();
    463     }
    464 }
    465 
    466 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
    467     if (err != OK) {
    468         mMetaDataSize = -1ll;
    469         mContentType = "";
    470         mSniffedMIME = "";
    471         mDataSource.clear();
    472         mCachedSource.clear();
    473         mHttpSource.clear();
    474         mBitrate = -1;
    475 
    476         cancelPollBuffering();
    477     }
    478     notifyPrepared(err);
    479 }
    480 
    481 status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
    482     CHECK(mDataSource != NULL);
    483 
    484     if (mCachedSource == NULL) {
    485         // no prefill if the data source is not cached
    486         return OK;
    487     }
    488 
    489     // We're not doing this for streams that appear to be audio-only
    490     // streams to ensure that even low bandwidth streams start
    491     // playing back fairly instantly.
    492     if (!strncasecmp(mContentType.string(), "audio/", 6)) {
    493         return OK;
    494     }
    495 
    496     // We're going to prefill the cache before trying to instantiate
    497     // the extractor below, as the latter is an operation that otherwise
    498     // could block on the datasource for a significant amount of time.
    499     // During that time we'd be unable to abort the preparation phase
    500     // without this prefill.
    501 
    502     // Initially make sure we have at least 192 KB for the sniff
    503     // to complete without blocking.
    504     static const size_t kMinBytesForSniffing = 192 * 1024;
    505     static const size_t kDefaultMetaSize = 200000;
    506 
    507     status_t finalStatus;
    508 
    509     size_t cachedDataRemaining =
    510             mCachedSource->approxDataRemaining(&finalStatus);
    511 
    512     if (finalStatus != OK || (mMetaDataSize >= 0
    513             && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
    514         ALOGV("stop caching, status %d, "
    515                 "metaDataSize %lld, cachedDataRemaining %zu",
    516                 finalStatus, mMetaDataSize, cachedDataRemaining);
    517         return OK;
    518     }
    519 
    520     ALOGV("now cached %zu bytes of data", cachedDataRemaining);
    521 
    522     if (mMetaDataSize < 0
    523             && cachedDataRemaining >= kMinBytesForSniffing) {
    524         String8 tmp;
    525         float confidence;
    526         sp<AMessage> meta;
    527         if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
    528             return UNKNOWN_ERROR;
    529         }
    530 
    531         // We successfully identified the file's extractor to
    532         // be, remember this mime type so we don't have to
    533         // sniff it again when we call MediaExtractor::Create()
    534         mSniffedMIME = tmp.string();
    535 
    536         if (meta == NULL
    537                 || !meta->findInt64("meta-data-size",
    538                         reinterpret_cast<int64_t*>(&mMetaDataSize))) {
    539             mMetaDataSize = kDefaultMetaSize;
    540         }
    541 
    542         if (mMetaDataSize < 0ll) {
    543             ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
    544             return UNKNOWN_ERROR;
    545         }
    546     }
    547 
    548     return -EAGAIN;
    549 }
    550 
    551 void NuPlayer::GenericSource::start() {
    552     ALOGI("start");
    553 
    554     mStopRead = false;
    555     if (mAudioTrack.mSource != NULL) {
    556         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
    557     }
    558 
    559     if (mVideoTrack.mSource != NULL) {
    560         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
    561     }
    562 
    563     setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
    564     mStarted = true;
    565 
    566     (new AMessage(kWhatStart, id()))->post();
    567 }
    568 
    569 void NuPlayer::GenericSource::stop() {
    570     // nothing to do, just account for DRM playback status
    571     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
    572     mStarted = false;
    573     if (mIsWidevine || mIsSecure) {
    574         // For widevine or secure sources we need to prevent any further reads.
    575         sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
    576         sp<AMessage> response;
    577         (void) msg->postAndAwaitResponse(&response);
    578     }
    579 }
    580 
    581 void NuPlayer::GenericSource::pause() {
    582     // nothing to do, just account for DRM playback status
    583     setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
    584     mStarted = false;
    585 }
    586 
    587 void NuPlayer::GenericSource::resume() {
    588     // nothing to do, just account for DRM playback status
    589     setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
    590     mStarted = true;
    591 
    592     (new AMessage(kWhatResume, id()))->post();
    593 }
    594 
    595 void NuPlayer::GenericSource::disconnect() {
    596     if (mDataSource != NULL) {
    597         // disconnect data source
    598         if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
    599             static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
    600         }
    601     } else if (mHttpSource != NULL) {
    602         static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
    603     }
    604 }
    605 
    606 void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
    607     if (mDecryptHandle != NULL) {
    608         mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
    609     }
    610     mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
    611     mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
    612 }
    613 
    614 status_t NuPlayer::GenericSource::feedMoreTSData() {
    615     return OK;
    616 }
    617 
    618 void NuPlayer::GenericSource::schedulePollBuffering() {
    619     sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
    620     msg->setInt32("generation", mPollBufferingGeneration);
    621     msg->post(1000000ll);
    622 }
    623 
    624 void NuPlayer::GenericSource::cancelPollBuffering() {
    625     mBuffering = false;
    626     ++mPollBufferingGeneration;
    627 }
    628 
    629 void NuPlayer::GenericSource::restartPollBuffering() {
    630     if (mIsStreaming) {
    631         cancelPollBuffering();
    632         onPollBuffering();
    633     }
    634 }
    635 
    636 void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
    637     ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
    638 
    639     sp<AMessage> msg = dupNotify();
    640     msg->setInt32("what", kWhatBufferingUpdate);
    641     msg->setInt32("percentage", percentage);
    642     msg->post();
    643 }
    644 
    645 void NuPlayer::GenericSource::startBufferingIfNecessary() {
    646     ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
    647             mPrepareBuffering, mBuffering);
    648 
    649     if (mPrepareBuffering) {
    650         return;
    651     }
    652 
    653     if (!mBuffering) {
    654         mBuffering = true;
    655 
    656         ensureCacheIsFetching();
    657         sendCacheStats();
    658 
    659         sp<AMessage> notify = dupNotify();
    660         notify->setInt32("what", kWhatPauseOnBufferingStart);
    661         notify->post();
    662     }
    663 }
    664 
    665 void NuPlayer::GenericSource::stopBufferingIfNecessary() {
    666     ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
    667             mPrepareBuffering, mBuffering);
    668 
    669     if (mPrepareBuffering) {
    670         mPrepareBuffering = false;
    671         notifyPrepared();
    672         return;
    673     }
    674 
    675     if (mBuffering) {
    676         mBuffering = false;
    677 
    678         sendCacheStats();
    679 
    680         sp<AMessage> notify = dupNotify();
    681         notify->setInt32("what", kWhatResumeOnBufferingEnd);
    682         notify->post();
    683     }
    684 }
    685 
    686 void NuPlayer::GenericSource::sendCacheStats() {
    687     int32_t kbps = 0;
    688     status_t err = UNKNOWN_ERROR;
    689 
    690     if (mCachedSource != NULL) {
    691         err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
    692     } else if (mWVMExtractor != NULL) {
    693         err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
    694     }
    695 
    696     if (err == OK) {
    697         sp<AMessage> notify = dupNotify();
    698         notify->setInt32("what", kWhatCacheStats);
    699         notify->setInt32("bandwidth", kbps);
    700         notify->post();
    701     }
    702 }
    703 
    704 void NuPlayer::GenericSource::ensureCacheIsFetching() {
    705     if (mCachedSource != NULL) {
    706         mCachedSource->resumeFetchingIfNecessary();
    707     }
    708 }
    709 
    710 void NuPlayer::GenericSource::onPollBuffering() {
    711     status_t finalStatus = UNKNOWN_ERROR;
    712     int64_t cachedDurationUs = -1ll;
    713     ssize_t cachedDataRemaining = -1;
    714 
    715     if (mCachedSource != NULL) {
    716         cachedDataRemaining =
    717                 mCachedSource->approxDataRemaining(&finalStatus);
    718 
    719         if (finalStatus == OK) {
    720             off64_t size;
    721             int64_t bitrate = 0ll;
    722             if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
    723                 bitrate = size * 8000000ll / mDurationUs;
    724             } else if (mBitrate > 0) {
    725                 bitrate = mBitrate;
    726             }
    727             if (bitrate > 0) {
    728                 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
    729             }
    730         }
    731     } else if (mWVMExtractor != NULL) {
    732         cachedDurationUs
    733             = mWVMExtractor->getCachedDurationUs(&finalStatus);
    734     }
    735 
    736     if (finalStatus != OK) {
    737         ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
    738 
    739         if (finalStatus == ERROR_END_OF_STREAM) {
    740             notifyBufferingUpdate(100);
    741         }
    742 
    743         stopBufferingIfNecessary();
    744         return;
    745     } else if (cachedDurationUs >= 0ll) {
    746         if (mDurationUs > 0ll) {
    747             int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
    748             int percentage = 100.0 * cachedPosUs / mDurationUs;
    749             if (percentage > 100) {
    750                 percentage = 100;
    751             }
    752 
    753             notifyBufferingUpdate(percentage);
    754         }
    755 
    756         ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
    757                 cachedDurationUs / 1000000.0f);
    758 
    759         if (cachedDurationUs < kLowWaterMarkUs) {
    760             startBufferingIfNecessary();
    761         } else if (cachedDurationUs > kHighWaterMarkUs) {
    762             stopBufferingIfNecessary();
    763         }
    764     } else if (cachedDataRemaining >= 0) {
    765         ALOGV("onPollBuffering: cachedDataRemaining %d bytes",
    766                 cachedDataRemaining);
    767 
    768         if (cachedDataRemaining < kLowWaterMarkBytes) {
    769             startBufferingIfNecessary();
    770         } else if (cachedDataRemaining > kHighWaterMarkBytes) {
    771             stopBufferingIfNecessary();
    772         }
    773     }
    774 
    775     schedulePollBuffering();
    776 }
    777 
    778 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
    779     switch (msg->what()) {
    780       case kWhatPrepareAsync:
    781       {
    782           onPrepareAsync();
    783           break;
    784       }
    785       case kWhatFetchSubtitleData:
    786       {
    787           fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
    788                   mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
    789           break;
    790       }
    791 
    792       case kWhatFetchTimedTextData:
    793       {
    794           fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
    795                   mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
    796           break;
    797       }
    798 
    799       case kWhatSendSubtitleData:
    800       {
    801           sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
    802                   mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
    803           break;
    804       }
    805 
    806       case kWhatSendTimedTextData:
    807       {
    808           sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
    809                   mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
    810           break;
    811       }
    812 
    813       case kWhatChangeAVSource:
    814       {
    815           int32_t trackIndex;
    816           CHECK(msg->findInt32("trackIndex", &trackIndex));
    817           const sp<MediaSource> source = mSources.itemAt(trackIndex);
    818 
    819           Track* track;
    820           const char *mime;
    821           media_track_type trackType, counterpartType;
    822           sp<MetaData> meta = source->getFormat();
    823           meta->findCString(kKeyMIMEType, &mime);
    824           if (!strncasecmp(mime, "audio/", 6)) {
    825               track = &mAudioTrack;
    826               trackType = MEDIA_TRACK_TYPE_AUDIO;
    827               counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
    828           } else {
    829               CHECK(!strncasecmp(mime, "video/", 6));
    830               track = &mVideoTrack;
    831               trackType = MEDIA_TRACK_TYPE_VIDEO;
    832               counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
    833           }
    834 
    835 
    836           if (track->mSource != NULL) {
    837               track->mSource->stop();
    838           }
    839           track->mSource = source;
    840           track->mSource->start();
    841           track->mIndex = trackIndex;
    842 
    843           int64_t timeUs, actualTimeUs;
    844           const bool formatChange = true;
    845           if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
    846               timeUs = mAudioLastDequeueTimeUs;
    847           } else {
    848               timeUs = mVideoLastDequeueTimeUs;
    849           }
    850           readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
    851           readBuffer(counterpartType, -1, NULL, formatChange);
    852           ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
    853 
    854           break;
    855       }
    856 
    857       case kWhatStart:
    858       case kWhatResume:
    859       {
    860           restartPollBuffering();
    861           break;
    862       }
    863 
    864       case kWhatPollBuffering:
    865       {
    866           int32_t generation;
    867           CHECK(msg->findInt32("generation", &generation));
    868           if (generation == mPollBufferingGeneration) {
    869               onPollBuffering();
    870           }
    871           break;
    872       }
    873 
    874       case kWhatGetFormat:
    875       {
    876           onGetFormatMeta(msg);
    877           break;
    878       }
    879 
    880       case kWhatGetSelectedTrack:
    881       {
    882           onGetSelectedTrack(msg);
    883           break;
    884       }
    885 
    886       case kWhatSelectTrack:
    887       {
    888           onSelectTrack(msg);
    889           break;
    890       }
    891 
    892       case kWhatSeek:
    893       {
    894           onSeek(msg);
    895           break;
    896       }
    897 
    898       case kWhatReadBuffer:
    899       {
    900           onReadBuffer(msg);
    901           break;
    902       }
    903 
    904       case kWhatSecureDecodersInstantiated:
    905       {
    906           int32_t err;
    907           CHECK(msg->findInt32("err", &err));
    908           onSecureDecodersInstantiated(err);
    909           break;
    910       }
    911 
    912       case kWhatStopWidevine:
    913       {
    914           // mStopRead is only used for Widevine to prevent the video source
    915           // from being read while the associated video decoder is shutting down.
    916           mStopRead = true;
    917           if (mVideoTrack.mSource != NULL) {
    918               mVideoTrack.mPackets->clear();
    919           }
    920           sp<AMessage> response = new AMessage;
    921           uint32_t replyID;
    922           CHECK(msg->senderAwaitsResponse(&replyID));
    923           response->postReply(replyID);
    924           break;
    925       }
    926       default:
    927           Source::onMessageReceived(msg);
    928           break;
    929     }
    930 }
    931 
    932 void NuPlayer::GenericSource::fetchTextData(
    933         uint32_t sendWhat,
    934         media_track_type type,
    935         int32_t curGen,
    936         sp<AnotherPacketSource> packets,
    937         sp<AMessage> msg) {
    938     int32_t msgGeneration;
    939     CHECK(msg->findInt32("generation", &msgGeneration));
    940     if (msgGeneration != curGen) {
    941         // stale
    942         return;
    943     }
    944 
    945     int32_t avail;
    946     if (packets->hasBufferAvailable(&avail)) {
    947         return;
    948     }
    949 
    950     int64_t timeUs;
    951     CHECK(msg->findInt64("timeUs", &timeUs));
    952 
    953     int64_t subTimeUs;
    954     readBuffer(type, timeUs, &subTimeUs);
    955 
    956     int64_t delayUs = subTimeUs - timeUs;
    957     if (msg->what() == kWhatFetchSubtitleData) {
    958         const int64_t oneSecUs = 1000000ll;
    959         delayUs -= oneSecUs;
    960     }
    961     sp<AMessage> msg2 = new AMessage(sendWhat, id());
    962     msg2->setInt32("generation", msgGeneration);
    963     msg2->post(delayUs < 0 ? 0 : delayUs);
    964 }
    965 
    966 void NuPlayer::GenericSource::sendTextData(
    967         uint32_t what,
    968         media_track_type type,
    969         int32_t curGen,
    970         sp<AnotherPacketSource> packets,
    971         sp<AMessage> msg) {
    972     int32_t msgGeneration;
    973     CHECK(msg->findInt32("generation", &msgGeneration));
    974     if (msgGeneration != curGen) {
    975         // stale
    976         return;
    977     }
    978 
    979     int64_t subTimeUs;
    980     if (packets->nextBufferTime(&subTimeUs) != OK) {
    981         return;
    982     }
    983 
    984     int64_t nextSubTimeUs;
    985     readBuffer(type, -1, &nextSubTimeUs);
    986 
    987     sp<ABuffer> buffer;
    988     status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
    989     if (dequeueStatus == OK) {
    990         sp<AMessage> notify = dupNotify();
    991         notify->setInt32("what", what);
    992         notify->setBuffer("buffer", buffer);
    993         notify->post();
    994 
    995         const int64_t delayUs = nextSubTimeUs - subTimeUs;
    996         msg->post(delayUs < 0 ? 0 : delayUs);
    997     }
    998 }
    999 
   1000 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
   1001     sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
   1002     msg->setInt32("audio", audio);
   1003 
   1004     sp<AMessage> response;
   1005     void *format;
   1006     status_t err = msg->postAndAwaitResponse(&response);
   1007     if (err == OK && response != NULL) {
   1008         CHECK(response->findPointer("format", &format));
   1009         return (MetaData *)format;
   1010     } else {
   1011         return NULL;
   1012     }
   1013 }
   1014 
   1015 void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
   1016     int32_t audio;
   1017     CHECK(msg->findInt32("audio", &audio));
   1018 
   1019     sp<AMessage> response = new AMessage;
   1020     sp<MetaData> format = doGetFormatMeta(audio);
   1021     response->setPointer("format", format.get());
   1022 
   1023     uint32_t replyID;
   1024     CHECK(msg->senderAwaitsResponse(&replyID));
   1025     response->postReply(replyID);
   1026 }
   1027 
   1028 sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
   1029     sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
   1030 
   1031     if (source == NULL) {
   1032         return NULL;
   1033     }
   1034 
   1035     return source->getFormat();
   1036 }
   1037 
   1038 status_t NuPlayer::GenericSource::dequeueAccessUnit(
   1039         bool audio, sp<ABuffer> *accessUnit) {
   1040     Track *track = audio ? &mAudioTrack : &mVideoTrack;
   1041 
   1042     if (track->mSource == NULL) {
   1043         return -EWOULDBLOCK;
   1044     }
   1045 
   1046     if (mIsWidevine && !audio) {
   1047         // try to read a buffer as we may not have been able to the last time
   1048         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
   1049     }
   1050 
   1051     status_t finalResult;
   1052     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
   1053         if (finalResult == OK) {
   1054             postReadBuffer(
   1055                     audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
   1056             return -EWOULDBLOCK;
   1057         }
   1058         return finalResult;
   1059     }
   1060 
   1061     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
   1062 
   1063     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
   1064         postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
   1065     }
   1066 
   1067     if (result != OK) {
   1068         if (mSubtitleTrack.mSource != NULL) {
   1069             mSubtitleTrack.mPackets->clear();
   1070             mFetchSubtitleDataGeneration++;
   1071         }
   1072         if (mTimedTextTrack.mSource != NULL) {
   1073             mTimedTextTrack.mPackets->clear();
   1074             mFetchTimedTextDataGeneration++;
   1075         }
   1076         return result;
   1077     }
   1078 
   1079     int64_t timeUs;
   1080     status_t eosResult; // ignored
   1081     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
   1082     if (audio) {
   1083         mAudioLastDequeueTimeUs = timeUs;
   1084     } else {
   1085         mVideoLastDequeueTimeUs = timeUs;
   1086     }
   1087 
   1088     if (mSubtitleTrack.mSource != NULL
   1089             && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
   1090         sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
   1091         msg->setInt64("timeUs", timeUs);
   1092         msg->setInt32("generation", mFetchSubtitleDataGeneration);
   1093         msg->post();
   1094     }
   1095 
   1096     if (mTimedTextTrack.mSource != NULL
   1097             && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
   1098         sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
   1099         msg->setInt64("timeUs", timeUs);
   1100         msg->setInt32("generation", mFetchTimedTextDataGeneration);
   1101         msg->post();
   1102     }
   1103 
   1104     return result;
   1105 }
   1106 
   1107 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
   1108     *durationUs = mDurationUs;
   1109     return OK;
   1110 }
   1111 
   1112 size_t NuPlayer::GenericSource::getTrackCount() const {
   1113     return mSources.size();
   1114 }
   1115 
   1116 sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
   1117     size_t trackCount = mSources.size();
   1118     if (trackIndex >= trackCount) {
   1119         return NULL;
   1120     }
   1121 
   1122     sp<AMessage> format = new AMessage();
   1123     sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
   1124 
   1125     const char *mime;
   1126     CHECK(meta->findCString(kKeyMIMEType, &mime));
   1127 
   1128     int32_t trackType;
   1129     if (!strncasecmp(mime, "video/", 6)) {
   1130         trackType = MEDIA_TRACK_TYPE_VIDEO;
   1131     } else if (!strncasecmp(mime, "audio/", 6)) {
   1132         trackType = MEDIA_TRACK_TYPE_AUDIO;
   1133     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
   1134         trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
   1135     } else {
   1136         trackType = MEDIA_TRACK_TYPE_UNKNOWN;
   1137     }
   1138     format->setInt32("type", trackType);
   1139 
   1140     const char *lang;
   1141     if (!meta->findCString(kKeyMediaLanguage, &lang)) {
   1142         lang = "und";
   1143     }
   1144     format->setString("language", lang);
   1145 
   1146     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
   1147         format->setString("mime", mime);
   1148 
   1149         int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
   1150         meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
   1151         meta->findInt32(kKeyTrackIsDefault, &isDefault);
   1152         meta->findInt32(kKeyTrackIsForced, &isForced);
   1153 
   1154         format->setInt32("auto", !!isAutoselect);
   1155         format->setInt32("default", !!isDefault);
   1156         format->setInt32("forced", !!isForced);
   1157     }
   1158 
   1159     return format;
   1160 }
   1161 
   1162 ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
   1163     sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
   1164     msg->setInt32("type", type);
   1165 
   1166     sp<AMessage> response;
   1167     int32_t index;
   1168     status_t err = msg->postAndAwaitResponse(&response);
   1169     if (err == OK && response != NULL) {
   1170         CHECK(response->findInt32("index", &index));
   1171         return index;
   1172     } else {
   1173         return -1;
   1174     }
   1175 }
   1176 
   1177 void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
   1178     int32_t tmpType;
   1179     CHECK(msg->findInt32("type", &tmpType));
   1180     media_track_type type = (media_track_type)tmpType;
   1181 
   1182     sp<AMessage> response = new AMessage;
   1183     ssize_t index = doGetSelectedTrack(type);
   1184     response->setInt32("index", index);
   1185 
   1186     uint32_t replyID;
   1187     CHECK(msg->senderAwaitsResponse(&replyID));
   1188     response->postReply(replyID);
   1189 }
   1190 
   1191 ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
   1192     const Track *track = NULL;
   1193     switch (type) {
   1194     case MEDIA_TRACK_TYPE_VIDEO:
   1195         track = &mVideoTrack;
   1196         break;
   1197     case MEDIA_TRACK_TYPE_AUDIO:
   1198         track = &mAudioTrack;
   1199         break;
   1200     case MEDIA_TRACK_TYPE_TIMEDTEXT:
   1201         track = &mTimedTextTrack;
   1202         break;
   1203     case MEDIA_TRACK_TYPE_SUBTITLE:
   1204         track = &mSubtitleTrack;
   1205         break;
   1206     default:
   1207         break;
   1208     }
   1209 
   1210     if (track != NULL && track->mSource != NULL) {
   1211         return track->mIndex;
   1212     }
   1213 
   1214     return -1;
   1215 }
   1216 
   1217 status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
   1218     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
   1219     sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
   1220     msg->setInt32("trackIndex", trackIndex);
   1221     msg->setInt32("select", select);
   1222     msg->setInt64("timeUs", timeUs);
   1223 
   1224     sp<AMessage> response;
   1225     status_t err = msg->postAndAwaitResponse(&response);
   1226     if (err == OK && response != NULL) {
   1227         CHECK(response->findInt32("err", &err));
   1228     }
   1229 
   1230     return err;
   1231 }
   1232 
   1233 void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
   1234     int32_t trackIndex, select;
   1235     int64_t timeUs;
   1236     CHECK(msg->findInt32("trackIndex", &trackIndex));
   1237     CHECK(msg->findInt32("select", &select));
   1238     CHECK(msg->findInt64("timeUs", &timeUs));
   1239 
   1240     sp<AMessage> response = new AMessage;
   1241     status_t err = doSelectTrack(trackIndex, select, timeUs);
   1242     response->setInt32("err", err);
   1243 
   1244     uint32_t replyID;
   1245     CHECK(msg->senderAwaitsResponse(&replyID));
   1246     response->postReply(replyID);
   1247 }
   1248 
   1249 status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
   1250     if (trackIndex >= mSources.size()) {
   1251         return BAD_INDEX;
   1252     }
   1253 
   1254     if (!select) {
   1255         Track* track = NULL;
   1256         if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
   1257             track = &mSubtitleTrack;
   1258             mFetchSubtitleDataGeneration++;
   1259         } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
   1260             track = &mTimedTextTrack;
   1261             mFetchTimedTextDataGeneration++;
   1262         }
   1263         if (track == NULL) {
   1264             return INVALID_OPERATION;
   1265         }
   1266         track->mSource->stop();
   1267         track->mSource = NULL;
   1268         track->mPackets->clear();
   1269         return OK;
   1270     }
   1271 
   1272     const sp<MediaSource> source = mSources.itemAt(trackIndex);
   1273     sp<MetaData> meta = source->getFormat();
   1274     const char *mime;
   1275     CHECK(meta->findCString(kKeyMIMEType, &mime));
   1276     if (!strncasecmp(mime, "text/", 5)) {
   1277         bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
   1278         Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
   1279         if (track->mSource != NULL && track->mIndex == trackIndex) {
   1280             return OK;
   1281         }
   1282         track->mIndex = trackIndex;
   1283         if (track->mSource != NULL) {
   1284             track->mSource->stop();
   1285         }
   1286         track->mSource = mSources.itemAt(trackIndex);
   1287         track->mSource->start();
   1288         if (track->mPackets == NULL) {
   1289             track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
   1290         } else {
   1291             track->mPackets->clear();
   1292             track->mPackets->setFormat(track->mSource->getFormat());
   1293 
   1294         }
   1295 
   1296         if (isSubtitle) {
   1297             mFetchSubtitleDataGeneration++;
   1298         } else {
   1299             mFetchTimedTextDataGeneration++;
   1300         }
   1301 
   1302         status_t eosResult; // ignored
   1303         if (mSubtitleTrack.mSource != NULL
   1304                 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
   1305             sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
   1306             msg->setInt64("timeUs", timeUs);
   1307             msg->setInt32("generation", mFetchSubtitleDataGeneration);
   1308             msg->post();
   1309         }
   1310 
   1311         if (mTimedTextTrack.mSource != NULL
   1312                 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
   1313             sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
   1314             msg->setInt64("timeUs", timeUs);
   1315             msg->setInt32("generation", mFetchTimedTextDataGeneration);
   1316             msg->post();
   1317         }
   1318 
   1319         return OK;
   1320     } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
   1321         bool audio = !strncasecmp(mime, "audio/", 6);
   1322         Track *track = audio ? &mAudioTrack : &mVideoTrack;
   1323         if (track->mSource != NULL && track->mIndex == trackIndex) {
   1324             return OK;
   1325         }
   1326 
   1327         sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
   1328         msg->setInt32("trackIndex", trackIndex);
   1329         msg->post();
   1330         return OK;
   1331     }
   1332 
   1333     return INVALID_OPERATION;
   1334 }
   1335 
   1336 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
   1337     sp<AMessage> msg = new AMessage(kWhatSeek, id());
   1338     msg->setInt64("seekTimeUs", seekTimeUs);
   1339 
   1340     sp<AMessage> response;
   1341     status_t err = msg->postAndAwaitResponse(&response);
   1342     if (err == OK && response != NULL) {
   1343         CHECK(response->findInt32("err", &err));
   1344     }
   1345 
   1346     return err;
   1347 }
   1348 
   1349 void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
   1350     int64_t seekTimeUs;
   1351     CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
   1352 
   1353     sp<AMessage> response = new AMessage;
   1354     status_t err = doSeek(seekTimeUs);
   1355     response->setInt32("err", err);
   1356 
   1357     uint32_t replyID;
   1358     CHECK(msg->senderAwaitsResponse(&replyID));
   1359     response->postReply(replyID);
   1360 }
   1361 
   1362 status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
   1363     // If the Widevine source is stopped, do not attempt to read any
   1364     // more buffers.
   1365     if (mStopRead) {
   1366         return INVALID_OPERATION;
   1367     }
   1368     if (mVideoTrack.mSource != NULL) {
   1369         int64_t actualTimeUs;
   1370         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
   1371 
   1372         seekTimeUs = actualTimeUs;
   1373         mVideoLastDequeueTimeUs = seekTimeUs;
   1374     }
   1375 
   1376     if (mAudioTrack.mSource != NULL) {
   1377         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
   1378         mAudioLastDequeueTimeUs = seekTimeUs;
   1379     }
   1380 
   1381     setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
   1382     if (!mStarted) {
   1383         setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
   1384     }
   1385 
   1386     // If currently buffering, post kWhatBufferingEnd first, so that
   1387     // NuPlayer resumes. Otherwise, if cache hits high watermark
   1388     // before new polling happens, no one will resume the playback.
   1389     stopBufferingIfNecessary();
   1390     restartPollBuffering();
   1391 
   1392     return OK;
   1393 }
   1394 
   1395 sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
   1396         MediaBuffer* mb,
   1397         media_track_type trackType,
   1398         int64_t /* seekTimeUs */,
   1399         int64_t *actualTimeUs) {
   1400     bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
   1401     size_t outLength = mb->range_length();
   1402 
   1403     if (audio && mAudioIsVorbis) {
   1404         outLength += sizeof(int32_t);
   1405     }
   1406 
   1407     sp<ABuffer> ab;
   1408     if (mIsSecure && !audio) {
   1409         // data is already provided in the buffer
   1410         ab = new ABuffer(NULL, mb->range_length());
   1411         mb->add_ref();
   1412         ab->setMediaBufferBase(mb);
   1413     } else {
   1414         ab = new ABuffer(outLength);
   1415         memcpy(ab->data(),
   1416                (const uint8_t *)mb->data() + mb->range_offset(),
   1417                mb->range_length());
   1418     }
   1419 
   1420     if (audio && mAudioIsVorbis) {
   1421         int32_t numPageSamples;
   1422         if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
   1423             numPageSamples = -1;
   1424         }
   1425 
   1426         uint8_t* abEnd = ab->data() + mb->range_length();
   1427         memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
   1428     }
   1429 
   1430     sp<AMessage> meta = ab->meta();
   1431 
   1432     int64_t timeUs;
   1433     CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
   1434     meta->setInt64("timeUs", timeUs);
   1435 
   1436 #if 0
   1437     // Temporarily disable pre-roll till we have a full solution to handle
   1438     // both single seek and continous seek gracefully.
   1439     if (seekTimeUs > timeUs) {
   1440         sp<AMessage> extra = new AMessage;
   1441         extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
   1442         meta->setMessage("extra", extra);
   1443     }
   1444 #endif
   1445 
   1446     if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
   1447         const char *mime;
   1448         CHECK(mTimedTextTrack.mSource != NULL
   1449                 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
   1450         meta->setString("mime", mime);
   1451     }
   1452 
   1453     int64_t durationUs;
   1454     if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
   1455         meta->setInt64("durationUs", durationUs);
   1456     }
   1457 
   1458     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
   1459         meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
   1460     }
   1461 
   1462     if (actualTimeUs) {
   1463         *actualTimeUs = timeUs;
   1464     }
   1465 
   1466     mb->release();
   1467     mb = NULL;
   1468 
   1469     return ab;
   1470 }
   1471 
   1472 void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
   1473     Mutex::Autolock _l(mReadBufferLock);
   1474 
   1475     if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
   1476         mPendingReadBufferTypes |= (1 << trackType);
   1477         sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
   1478         msg->setInt32("trackType", trackType);
   1479         msg->post();
   1480     }
   1481 }
   1482 
   1483 void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
   1484     int32_t tmpType;
   1485     CHECK(msg->findInt32("trackType", &tmpType));
   1486     media_track_type trackType = (media_track_type)tmpType;
   1487     readBuffer(trackType);
   1488     {
   1489         // only protect the variable change, as readBuffer may
   1490         // take considerable time.
   1491         Mutex::Autolock _l(mReadBufferLock);
   1492         mPendingReadBufferTypes &= ~(1 << trackType);
   1493     }
   1494 }
   1495 
   1496 void NuPlayer::GenericSource::readBuffer(
   1497         media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
   1498     // Do not read data if Widevine source is stopped
   1499     if (mStopRead) {
   1500         return;
   1501     }
   1502     Track *track;
   1503     size_t maxBuffers = 1;
   1504     switch (trackType) {
   1505         case MEDIA_TRACK_TYPE_VIDEO:
   1506             track = &mVideoTrack;
   1507             if (mIsWidevine) {
   1508                 maxBuffers = 2;
   1509             }
   1510             break;
   1511         case MEDIA_TRACK_TYPE_AUDIO:
   1512             track = &mAudioTrack;
   1513             if (mIsWidevine) {
   1514                 maxBuffers = 8;
   1515             } else {
   1516                 maxBuffers = 64;
   1517             }
   1518             break;
   1519         case MEDIA_TRACK_TYPE_SUBTITLE:
   1520             track = &mSubtitleTrack;
   1521             break;
   1522         case MEDIA_TRACK_TYPE_TIMEDTEXT:
   1523             track = &mTimedTextTrack;
   1524             break;
   1525         default:
   1526             TRESPASS();
   1527     }
   1528 
   1529     if (track->mSource == NULL) {
   1530         return;
   1531     }
   1532 
   1533     if (actualTimeUs) {
   1534         *actualTimeUs = seekTimeUs;
   1535     }
   1536 
   1537     MediaSource::ReadOptions options;
   1538 
   1539     bool seeking = false;
   1540 
   1541     if (seekTimeUs >= 0) {
   1542         options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
   1543         seeking = true;
   1544     }
   1545 
   1546     if (mIsWidevine) {
   1547         options.setNonBlocking();
   1548     }
   1549 
   1550     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
   1551         MediaBuffer *mbuf;
   1552         status_t err = track->mSource->read(&mbuf, &options);
   1553 
   1554         options.clearSeekTo();
   1555 
   1556         if (err == OK) {
   1557             int64_t timeUs;
   1558             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
   1559             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
   1560                 mAudioTimeUs = timeUs;
   1561             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
   1562                 mVideoTimeUs = timeUs;
   1563             }
   1564 
   1565             // formatChange && seeking: track whose source is changed during selection
   1566             // formatChange && !seeking: track whose source is not changed during selection
   1567             // !formatChange: normal seek
   1568             if ((seeking || formatChange)
   1569                     && (trackType == MEDIA_TRACK_TYPE_AUDIO
   1570                     || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
   1571                 ATSParser::DiscontinuityType type = (formatChange && seeking)
   1572                         ? ATSParser::DISCONTINUITY_FORMATCHANGE
   1573                         : ATSParser::DISCONTINUITY_NONE;
   1574                 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
   1575             }
   1576 
   1577             sp<ABuffer> buffer = mediaBufferToABuffer(
   1578                     mbuf, trackType, seekTimeUs, actualTimeUs);
   1579             track->mPackets->queueAccessUnit(buffer);
   1580             formatChange = false;
   1581             seeking = false;
   1582             ++numBuffers;
   1583         } else if (err == WOULD_BLOCK) {
   1584             break;
   1585         } else if (err == INFO_FORMAT_CHANGED) {
   1586 #if 0
   1587             track->mPackets->queueDiscontinuity(
   1588                     ATSParser::DISCONTINUITY_FORMATCHANGE,
   1589                     NULL,
   1590                     false /* discard */);
   1591 #endif
   1592         } else {
   1593             track->mPackets->signalEOS(err);
   1594             break;
   1595         }
   1596     }
   1597 }
   1598 
   1599 }  // namespace android
   1600