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