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