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