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