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