PlaylistFetcher.cpp revision 65e20ffc984c541a8119420f917493dd7b703f77
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 "PlaylistFetcher"
19#include <utils/Log.h>
20
21#include "PlaylistFetcher.h"
22
23#include "LiveDataSource.h"
24#include "LiveSession.h"
25#include "M3UParser.h"
26
27#include "include/avc_utils.h"
28#include "include/HTTPBase.h"
29#include "include/ID3.h"
30#include "mpeg2ts/AnotherPacketSource.h"
31
32#include <media/IStreamSource.h>
33#include <media/stagefright/foundation/ABitReader.h>
34#include <media/stagefright/foundation/ABuffer.h>
35#include <media/stagefright/foundation/ADebug.h>
36#include <media/stagefright/foundation/hexdump.h>
37#include <media/stagefright/FileSource.h>
38#include <media/stagefright/MediaDefs.h>
39#include <media/stagefright/MetaData.h>
40#include <media/stagefright/Utils.h>
41
42#include <ctype.h>
43#include <openssl/aes.h>
44#include <openssl/md5.h>
45
46namespace android {
47
48// static
49const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
50const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
51const int32_t PlaylistFetcher::kDownloadBlockSize = 192;
52const int32_t PlaylistFetcher::kNumSkipFrames = 10;
53
54PlaylistFetcher::PlaylistFetcher(
55        const sp<AMessage> &notify,
56        const sp<LiveSession> &session,
57        const char *uri)
58    : mNotify(notify),
59      mStartTimeUsNotify(notify->dup()),
60      mSession(session),
61      mURI(uri),
62      mStreamTypeMask(0),
63      mStartTimeUs(-1ll),
64      mMinStartTimeUs(0ll),
65      mStopParams(NULL),
66      mLastPlaylistFetchTimeUs(-1ll),
67      mSeqNumber(-1),
68      mNumRetries(0),
69      mStartup(true),
70      mPrepared(false),
71      mNextPTSTimeUs(-1ll),
72      mMonitorQueueGeneration(0),
73      mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
74      mFirstPTSValid(false),
75      mAbsoluteTimeAnchorUs(0ll) {
76    memset(mPlaylistHash, 0, sizeof(mPlaylistHash));
77    mStartTimeUsNotify->setInt32("what", kWhatStartedAt);
78    mStartTimeUsNotify->setInt32("streamMask", 0);
79}
80
81PlaylistFetcher::~PlaylistFetcher() {
82}
83
84int64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const {
85    CHECK(mPlaylist != NULL);
86
87    int32_t firstSeqNumberInPlaylist;
88    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
89                "media-sequence", &firstSeqNumberInPlaylist)) {
90        firstSeqNumberInPlaylist = 0;
91    }
92
93    int32_t lastSeqNumberInPlaylist =
94        firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
95
96    CHECK_GE(seqNumber, firstSeqNumberInPlaylist);
97    CHECK_LE(seqNumber, lastSeqNumberInPlaylist);
98
99    int64_t segmentStartUs = 0ll;
100    for (int32_t index = 0;
101            index < seqNumber - firstSeqNumberInPlaylist; ++index) {
102        sp<AMessage> itemMeta;
103        CHECK(mPlaylist->itemAt(
104                    index, NULL /* uri */, &itemMeta));
105
106        int64_t itemDurationUs;
107        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
108
109        segmentStartUs += itemDurationUs;
110    }
111
112    return segmentStartUs;
113}
114
115int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const {
116    int64_t nowUs = ALooper::GetNowUs();
117
118    if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) {
119        CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
120        return 0ll;
121    }
122
123    if (mPlaylist->isComplete()) {
124        return (~0llu >> 1);
125    }
126
127    int32_t targetDurationSecs;
128    CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
129
130    int64_t targetDurationUs = targetDurationSecs * 1000000ll;
131
132    int64_t minPlaylistAgeUs;
133
134    switch (mRefreshState) {
135        case INITIAL_MINIMUM_RELOAD_DELAY:
136        {
137            size_t n = mPlaylist->size();
138            if (n > 0) {
139                sp<AMessage> itemMeta;
140                CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta));
141
142                int64_t itemDurationUs;
143                CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
144
145                minPlaylistAgeUs = itemDurationUs;
146                break;
147            }
148
149            // fall through
150        }
151
152        case FIRST_UNCHANGED_RELOAD_ATTEMPT:
153        {
154            minPlaylistAgeUs = targetDurationUs / 2;
155            break;
156        }
157
158        case SECOND_UNCHANGED_RELOAD_ATTEMPT:
159        {
160            minPlaylistAgeUs = (targetDurationUs * 3) / 2;
161            break;
162        }
163
164        case THIRD_UNCHANGED_RELOAD_ATTEMPT:
165        {
166            minPlaylistAgeUs = targetDurationUs * 3;
167            break;
168        }
169
170        default:
171            TRESPASS();
172            break;
173    }
174
175    int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs;
176    return delayUs > 0ll ? delayUs : 0ll;
177}
178
179status_t PlaylistFetcher::decryptBuffer(
180        size_t playlistIndex, const sp<ABuffer> &buffer,
181        bool first) {
182    sp<AMessage> itemMeta;
183    bool found = false;
184    AString method;
185
186    for (ssize_t i = playlistIndex; i >= 0; --i) {
187        AString uri;
188        CHECK(mPlaylist->itemAt(i, &uri, &itemMeta));
189
190        if (itemMeta->findString("cipher-method", &method)) {
191            found = true;
192            break;
193        }
194    }
195
196    if (!found) {
197        method = "NONE";
198    }
199    buffer->meta()->setString("cipher-method", method.c_str());
200
201    if (method == "NONE") {
202        return OK;
203    } else if (!(method == "AES-128")) {
204        ALOGE("Unsupported cipher method '%s'", method.c_str());
205        return ERROR_UNSUPPORTED;
206    }
207
208    AString keyURI;
209    if (!itemMeta->findString("cipher-uri", &keyURI)) {
210        ALOGE("Missing key uri");
211        return ERROR_MALFORMED;
212    }
213
214    ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
215
216    sp<ABuffer> key;
217    if (index >= 0) {
218        key = mAESKeyForURI.valueAt(index);
219    } else {
220        ssize_t err = mSession->fetchFile(keyURI.c_str(), &key);
221
222        if (err < 0) {
223            ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
224            return ERROR_IO;
225        } else if (key->size() != 16) {
226            ALOGE("key file '%s' wasn't 16 bytes in size.", keyURI.c_str());
227            return ERROR_MALFORMED;
228        }
229
230        mAESKeyForURI.add(keyURI, key);
231    }
232
233    AES_KEY aes_key;
234    if (AES_set_decrypt_key(key->data(), 128, &aes_key) != 0) {
235        ALOGE("failed to set AES decryption key.");
236        return UNKNOWN_ERROR;
237    }
238
239    size_t n = buffer->size();
240    if (!n) {
241        return OK;
242    }
243    CHECK(n % 16 == 0);
244
245    if (first) {
246        // If decrypting the first block in a file, read the iv from the manifest
247        // or derive the iv from the file's sequence number.
248
249        AString iv;
250        if (itemMeta->findString("cipher-iv", &iv)) {
251            if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
252                    || iv.size() != 16 * 2 + 2) {
253                ALOGE("malformed cipher IV '%s'.", iv.c_str());
254                return ERROR_MALFORMED;
255            }
256
257            memset(mAESInitVec, 0, sizeof(mAESInitVec));
258            for (size_t i = 0; i < 16; ++i) {
259                char c1 = tolower(iv.c_str()[2 + 2 * i]);
260                char c2 = tolower(iv.c_str()[3 + 2 * i]);
261                if (!isxdigit(c1) || !isxdigit(c2)) {
262                    ALOGE("malformed cipher IV '%s'.", iv.c_str());
263                    return ERROR_MALFORMED;
264                }
265                uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
266                uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
267
268                mAESInitVec[i] = nibble1 << 4 | nibble2;
269            }
270        } else {
271            memset(mAESInitVec, 0, sizeof(mAESInitVec));
272            mAESInitVec[15] = mSeqNumber & 0xff;
273            mAESInitVec[14] = (mSeqNumber >> 8) & 0xff;
274            mAESInitVec[13] = (mSeqNumber >> 16) & 0xff;
275            mAESInitVec[12] = (mSeqNumber >> 24) & 0xff;
276        }
277    }
278
279    AES_cbc_encrypt(
280            buffer->data(), buffer->data(), buffer->size(),
281            &aes_key, mAESInitVec, AES_DECRYPT);
282
283    return OK;
284}
285
286status_t PlaylistFetcher::checkDecryptPadding(const sp<ABuffer> &buffer) {
287    status_t err;
288    AString method;
289    CHECK(buffer->meta()->findString("cipher-method", &method));
290    if (method == "NONE") {
291        return OK;
292    }
293
294    uint8_t padding = 0;
295    if (buffer->size() > 0) {
296        padding = buffer->data()[buffer->size() - 1];
297    }
298
299    if (padding > 16) {
300        return ERROR_MALFORMED;
301    }
302
303    for (size_t i = buffer->size() - padding; i < padding; i++) {
304        if (buffer->data()[i] != padding) {
305            return ERROR_MALFORMED;
306        }
307    }
308
309    buffer->setRange(buffer->offset(), buffer->size() - padding);
310    return OK;
311}
312
313void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) {
314    int64_t maxDelayUs = delayUsToRefreshPlaylist();
315    if (maxDelayUs < minDelayUs) {
316        maxDelayUs = minDelayUs;
317    }
318    if (delayUs > maxDelayUs) {
319        ALOGV("Need to refresh playlist in %lld", maxDelayUs);
320        delayUs = maxDelayUs;
321    }
322    sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
323    msg->setInt32("generation", mMonitorQueueGeneration);
324    msg->post(delayUs);
325}
326
327void PlaylistFetcher::cancelMonitorQueue() {
328    ++mMonitorQueueGeneration;
329}
330
331void PlaylistFetcher::startAsync(
332        const sp<AnotherPacketSource> &audioSource,
333        const sp<AnotherPacketSource> &videoSource,
334        const sp<AnotherPacketSource> &subtitleSource,
335        int64_t startTimeUs,
336        int64_t minStartTimeUs,
337        int32_t startSeqNumberHint) {
338    sp<AMessage> msg = new AMessage(kWhatStart, id());
339
340    uint32_t streamTypeMask = 0ul;
341
342    if (audioSource != NULL) {
343        msg->setPointer("audioSource", audioSource.get());
344        streamTypeMask |= LiveSession::STREAMTYPE_AUDIO;
345    }
346
347    if (videoSource != NULL) {
348        msg->setPointer("videoSource", videoSource.get());
349        streamTypeMask |= LiveSession::STREAMTYPE_VIDEO;
350    }
351
352    if (subtitleSource != NULL) {
353        msg->setPointer("subtitleSource", subtitleSource.get());
354        streamTypeMask |= LiveSession::STREAMTYPE_SUBTITLES;
355    }
356
357    msg->setInt32("streamTypeMask", streamTypeMask);
358    msg->setInt64("startTimeUs", startTimeUs);
359    msg->setInt64("minStartTimeUs", minStartTimeUs);
360    msg->setInt32("startSeqNumberHint", startSeqNumberHint);
361    msg->post();
362}
363
364void PlaylistFetcher::pauseAsync() {
365    (new AMessage(kWhatPause, id()))->post();
366}
367
368void PlaylistFetcher::stopAsync(bool selfTriggered) {
369    sp<AMessage> msg = new AMessage(kWhatStop, id());
370    msg->setInt32("selfTriggered", selfTriggered);
371    msg->post();
372}
373
374void PlaylistFetcher::resumeUntilAsync(const sp<AMessage> &params) {
375    AMessage* msg = new AMessage(kWhatResumeUntil, id());
376    msg->setMessage("params", params);
377    msg->post();
378}
379
380void PlaylistFetcher::onMessageReceived(const sp<AMessage> &msg) {
381    switch (msg->what()) {
382        case kWhatStart:
383        {
384            status_t err = onStart(msg);
385
386            sp<AMessage> notify = mNotify->dup();
387            notify->setInt32("what", kWhatStarted);
388            notify->setInt32("err", err);
389            notify->post();
390            break;
391        }
392
393        case kWhatPause:
394        {
395            onPause();
396
397            sp<AMessage> notify = mNotify->dup();
398            notify->setInt32("what", kWhatPaused);
399            notify->post();
400            break;
401        }
402
403        case kWhatStop:
404        {
405            onStop(msg);
406
407            sp<AMessage> notify = mNotify->dup();
408            notify->setInt32("what", kWhatStopped);
409            notify->post();
410            break;
411        }
412
413        case kWhatMonitorQueue:
414        case kWhatDownloadNext:
415        {
416            int32_t generation;
417            CHECK(msg->findInt32("generation", &generation));
418
419            if (generation != mMonitorQueueGeneration) {
420                // Stale event
421                break;
422            }
423
424            if (msg->what() == kWhatMonitorQueue) {
425                onMonitorQueue();
426            } else {
427                onDownloadNext();
428            }
429            break;
430        }
431
432        case kWhatResumeUntil:
433        {
434            onResumeUntil(msg);
435            break;
436        }
437
438        default:
439            TRESPASS();
440    }
441}
442
443status_t PlaylistFetcher::onStart(const sp<AMessage> &msg) {
444    mPacketSources.clear();
445
446    uint32_t streamTypeMask;
447    CHECK(msg->findInt32("streamTypeMask", (int32_t *)&streamTypeMask));
448
449    int64_t startTimeUs;
450    int32_t startSeqNumberHint;
451    CHECK(msg->findInt64("startTimeUs", &startTimeUs));
452    CHECK(msg->findInt64("minStartTimeUs", (int64_t *) &mMinStartTimeUs));
453    CHECK(msg->findInt32("startSeqNumberHint", &startSeqNumberHint));
454
455    if (streamTypeMask & LiveSession::STREAMTYPE_AUDIO) {
456        void *ptr;
457        CHECK(msg->findPointer("audioSource", &ptr));
458
459        mPacketSources.add(
460                LiveSession::STREAMTYPE_AUDIO,
461                static_cast<AnotherPacketSource *>(ptr));
462    }
463
464    if (streamTypeMask & LiveSession::STREAMTYPE_VIDEO) {
465        void *ptr;
466        CHECK(msg->findPointer("videoSource", &ptr));
467
468        mPacketSources.add(
469                LiveSession::STREAMTYPE_VIDEO,
470                static_cast<AnotherPacketSource *>(ptr));
471    }
472
473    if (streamTypeMask & LiveSession::STREAMTYPE_SUBTITLES) {
474        void *ptr;
475        CHECK(msg->findPointer("subtitleSource", &ptr));
476
477        mPacketSources.add(
478                LiveSession::STREAMTYPE_SUBTITLES,
479                static_cast<AnotherPacketSource *>(ptr));
480    }
481
482    mStreamTypeMask = streamTypeMask;
483    mStartTimeUs = startTimeUs;
484
485    if (mStartTimeUs >= 0ll) {
486        mSeqNumber = -1;
487        mStartup = true;
488        mPrepared = false;
489    }
490
491    if (startSeqNumberHint >= 0) {
492        mSeqNumber = startSeqNumberHint;
493    }
494
495    postMonitorQueue();
496
497    return OK;
498}
499
500void PlaylistFetcher::onPause() {
501    cancelMonitorQueue();
502}
503
504void PlaylistFetcher::onStop(const sp<AMessage> &msg) {
505    cancelMonitorQueue();
506
507    int32_t selfTriggered;
508    CHECK(msg->findInt32("selfTriggered", &selfTriggered));
509    if (!selfTriggered) {
510        // Self triggered stops only happen during switching, in which case we do not want
511        // to clear the discontinuities queued at the end of packet sources.
512        for (size_t i = 0; i < mPacketSources.size(); i++) {
513            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
514            packetSource->clear();
515        }
516    }
517
518    mPacketSources.clear();
519    mStreamTypeMask = 0;
520}
521
522// Resume until we have reached the boundary timestamps listed in `msg`; when
523// the remaining time is too short (within a resume threshold) stop immediately
524// instead.
525status_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) {
526    sp<AMessage> params;
527    CHECK(msg->findMessage("params", &params));
528
529    bool stop = false;
530    for (size_t i = 0; i < mPacketSources.size(); i++) {
531        sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
532
533        const char *stopKey;
534        int streamType = mPacketSources.keyAt(i);
535        switch (streamType) {
536        case LiveSession::STREAMTYPE_VIDEO:
537            stopKey = "timeUsVideo";
538            break;
539
540        case LiveSession::STREAMTYPE_AUDIO:
541            stopKey = "timeUsAudio";
542            break;
543
544        case LiveSession::STREAMTYPE_SUBTITLES:
545            stopKey = "timeUsSubtitle";
546            break;
547
548        default:
549            TRESPASS();
550        }
551
552        // Don't resume if we would stop within a resume threshold.
553        int64_t latestTimeUs = 0, stopTimeUs = 0;
554        sp<AMessage> latestMeta = packetSource->getLatestMeta();
555        if (latestMeta != NULL
556                && (latestMeta->findInt64("timeUs", &latestTimeUs)
557                && params->findInt64(stopKey, &stopTimeUs))) {
558            int64_t diffUs = stopTimeUs - latestTimeUs;
559            if (diffUs < resumeThreshold(latestMeta)) {
560                stop = true;
561            }
562        }
563    }
564
565    if (stop) {
566        for (size_t i = 0; i < mPacketSources.size(); i++) {
567            mPacketSources.valueAt(i)->queueAccessUnit(mSession->createFormatChangeBuffer());
568        }
569        stopAsync(/* selfTriggered = */ true);
570        return OK;
571    }
572
573    mStopParams = params;
574    postMonitorQueue();
575
576    return OK;
577}
578
579void PlaylistFetcher::notifyError(status_t err) {
580    sp<AMessage> notify = mNotify->dup();
581    notify->setInt32("what", kWhatError);
582    notify->setInt32("err", err);
583    notify->post();
584}
585
586void PlaylistFetcher::queueDiscontinuity(
587        ATSParser::DiscontinuityType type, const sp<AMessage> &extra) {
588    for (size_t i = 0; i < mPacketSources.size(); ++i) {
589        mPacketSources.valueAt(i)->queueDiscontinuity(type, extra);
590    }
591}
592
593void PlaylistFetcher::onMonitorQueue() {
594    bool downloadMore = false;
595    refreshPlaylist();
596
597    int32_t targetDurationSecs;
598    int64_t targetDurationUs = kMinBufferedDurationUs;
599    if (mPlaylist != NULL) {
600        CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
601        targetDurationUs = targetDurationSecs * 1000000ll;
602    }
603
604    // buffer at least 3 times the target duration, or up to 10 seconds
605    int64_t durationToBufferUs = targetDurationUs * 3;
606    if (durationToBufferUs > kMinBufferedDurationUs)  {
607        durationToBufferUs = kMinBufferedDurationUs;
608    }
609
610    int64_t bufferedDurationUs = 0ll;
611    status_t finalResult = NOT_ENOUGH_DATA;
612    if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
613        sp<AnotherPacketSource> packetSource =
614            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
615
616        bufferedDurationUs =
617                packetSource->getBufferedDurationUs(&finalResult);
618        finalResult = OK;
619    } else {
620        // Use max stream duration to prevent us from waiting on a non-existent stream;
621        // when we cannot make out from the manifest what streams are included in a playlist
622        // we might assume extra streams.
623        for (size_t i = 0; i < mPacketSources.size(); ++i) {
624            if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) {
625                continue;
626            }
627
628            int64_t bufferedStreamDurationUs =
629                mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult);
630            ALOGV("buffered %lld for stream %d",
631                    bufferedStreamDurationUs, mPacketSources.keyAt(i));
632            if (bufferedStreamDurationUs > bufferedDurationUs) {
633                bufferedDurationUs = bufferedStreamDurationUs;
634            }
635        }
636    }
637    downloadMore = (bufferedDurationUs < durationToBufferUs);
638
639    // signal start if buffered up at least the target size
640    if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) {
641        mPrepared = true;
642
643        ALOGV("prepared, buffered=%lld > %lld",
644                bufferedDurationUs, targetDurationUs);
645        sp<AMessage> msg = mNotify->dup();
646        msg->setInt32("what", kWhatTemporarilyDoneFetching);
647        msg->post();
648    }
649
650    if (finalResult == OK && downloadMore) {
651        ALOGV("monitoring, buffered=%lld < %lld",
652                bufferedDurationUs, durationToBufferUs);
653        // delay the next download slightly; hopefully this gives other concurrent fetchers
654        // a better chance to run.
655        // onDownloadNext();
656        sp<AMessage> msg = new AMessage(kWhatDownloadNext, id());
657        msg->setInt32("generation", mMonitorQueueGeneration);
658        msg->post(1000l);
659    } else {
660        // Nothing to do yet, try again in a second.
661
662        sp<AMessage> msg = mNotify->dup();
663        msg->setInt32("what", kWhatTemporarilyDoneFetching);
664        msg->post();
665
666        int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
667        ALOGV("pausing for %lld, buffered=%lld > %lld",
668                delayUs, bufferedDurationUs, durationToBufferUs);
669        // :TRICKY: need to enforce minimum delay because the delay to
670        // refresh the playlist will become 0
671        postMonitorQueue(delayUs, mPrepared ? targetDurationUs * 2 : 0);
672    }
673}
674
675status_t PlaylistFetcher::refreshPlaylist() {
676    if (delayUsToRefreshPlaylist() <= 0) {
677        bool unchanged;
678        sp<M3UParser> playlist = mSession->fetchPlaylist(
679                mURI.c_str(), mPlaylistHash, &unchanged);
680
681        if (playlist == NULL) {
682            if (unchanged) {
683                // We succeeded in fetching the playlist, but it was
684                // unchanged from the last time we tried.
685
686                if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) {
687                    mRefreshState = (RefreshState)(mRefreshState + 1);
688                }
689            } else {
690                ALOGE("failed to load playlist at url '%s'", mURI.c_str());
691                notifyError(ERROR_IO);
692                return ERROR_IO;
693            }
694        } else {
695            mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
696            mPlaylist = playlist;
697
698            if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
699                updateDuration();
700            }
701        }
702
703        mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
704    }
705    return OK;
706}
707
708// static
709bool PlaylistFetcher::bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer) {
710    return buffer->size() > 0 && buffer->data()[0] == 0x47;
711}
712
713void PlaylistFetcher::onDownloadNext() {
714    if (refreshPlaylist() != OK) {
715        return;
716    }
717
718    int32_t firstSeqNumberInPlaylist;
719    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
720                "media-sequence", &firstSeqNumberInPlaylist)) {
721        firstSeqNumberInPlaylist = 0;
722    }
723
724    bool seekDiscontinuity = false;
725    bool explicitDiscontinuity = false;
726
727    const int32_t lastSeqNumberInPlaylist =
728        firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
729
730    if (mStartup && mSeqNumber >= 0
731            && (mSeqNumber < firstSeqNumberInPlaylist || mSeqNumber > lastSeqNumberInPlaylist)) {
732        // in case we guessed wrong during reconfiguration, try fetching the latest content.
733        mSeqNumber = lastSeqNumberInPlaylist;
734    }
735
736    if (mSeqNumber < 0) {
737        CHECK_GE(mStartTimeUs, 0ll);
738
739        if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
740            mSeqNumber = getSeqNumberForTime(mStartTimeUs);
741            ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)",
742                    mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
743                    lastSeqNumberInPlaylist);
744        } else {
745            // If this is a live session, start 3 segments from the end.
746            mSeqNumber = lastSeqNumberInPlaylist - 3;
747            if (mSeqNumber < firstSeqNumberInPlaylist) {
748                mSeqNumber = firstSeqNumberInPlaylist;
749            }
750            ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)",
751                    mSeqNumber, firstSeqNumberInPlaylist,
752                    lastSeqNumberInPlaylist);
753        }
754
755        mStartTimeUs = -1ll;
756    }
757
758    if (mSeqNumber < firstSeqNumberInPlaylist
759            || mSeqNumber > lastSeqNumberInPlaylist) {
760        if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
761            ++mNumRetries;
762
763            if (mSeqNumber > lastSeqNumberInPlaylist) {
764                // refresh in increasing fraction (1/2, 1/3, ...) of the
765                // playlist's target duration or 3 seconds, whichever is less
766                int32_t targetDurationSecs;
767                CHECK(mPlaylist->meta()->findInt32(
768                        "target-duration", &targetDurationSecs));
769                int64_t delayUs = mPlaylist->size() * targetDurationSecs *
770                        1000000ll / (1 + mNumRetries);
771                if (delayUs > kMaxMonitorDelayUs) {
772                    delayUs = kMaxMonitorDelayUs;
773                }
774                ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)",
775                        mSeqNumber, firstSeqNumberInPlaylist,
776                        lastSeqNumberInPlaylist, delayUs, mNumRetries);
777                postMonitorQueue(delayUs);
778                return;
779            }
780
781            // we've missed the boat, let's start from the lowest sequence
782            // number available and signal a discontinuity.
783
784            ALOGI("We've missed the boat, restarting playback."
785                  "  mStartup=%d, was  looking for %d in %d-%d",
786                    mStartup, mSeqNumber, firstSeqNumberInPlaylist,
787                    lastSeqNumberInPlaylist);
788            mSeqNumber = lastSeqNumberInPlaylist - 3;
789            if (mSeqNumber < firstSeqNumberInPlaylist) {
790                mSeqNumber = firstSeqNumberInPlaylist;
791            }
792            explicitDiscontinuity = true;
793
794            // fall through
795        } else {
796            ALOGE("Cannot find sequence number %d in playlist "
797                 "(contains %d - %d)",
798                 mSeqNumber, firstSeqNumberInPlaylist,
799                 firstSeqNumberInPlaylist + mPlaylist->size() - 1);
800
801            notifyError(ERROR_END_OF_STREAM);
802            return;
803        }
804    }
805
806    mNumRetries = 0;
807
808    AString uri;
809    sp<AMessage> itemMeta;
810    CHECK(mPlaylist->itemAt(
811                mSeqNumber - firstSeqNumberInPlaylist,
812                &uri,
813                &itemMeta));
814
815    int32_t val;
816    if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
817        explicitDiscontinuity = true;
818    }
819
820    int64_t range_offset, range_length;
821    if (!itemMeta->findInt64("range-offset", &range_offset)
822            || !itemMeta->findInt64("range-length", &range_length)) {
823        range_offset = 0;
824        range_length = -1;
825    }
826
827    ALOGV("fetching segment %d from (%d .. %d)",
828          mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist);
829
830    ALOGV("fetching '%s'", uri.c_str());
831
832    sp<DataSource> source;
833    sp<ABuffer> buffer, tsBuffer;
834    // decrypt a junk buffer to prefetch key; since a session uses only one http connection,
835    // this avoids interleaved connections to the key and segment file.
836    {
837        sp<ABuffer> junk = new ABuffer(16);
838        junk->setRange(0, 16);
839        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk,
840                true /* first */);
841        if (err != OK) {
842            notifyError(err);
843            return;
844        }
845    }
846
847    // block-wise download
848    ssize_t bytesRead;
849    do {
850        bytesRead = mSession->fetchFile(
851                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source);
852
853        if (bytesRead < 0) {
854            status_t err = bytesRead;
855            ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
856            notifyError(err);
857            return;
858        }
859
860        CHECK(buffer != NULL);
861
862        size_t size = buffer->size();
863        // Set decryption range.
864        buffer->setRange(size - bytesRead, bytesRead);
865        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer,
866                buffer->offset() == 0 /* first */);
867        // Unset decryption range.
868        buffer->setRange(0, size);
869
870        if (err != OK) {
871            ALOGE("decryptBuffer failed w/ error %d", err);
872
873            notifyError(err);
874            return;
875        }
876
877        if (mStartup || seekDiscontinuity || explicitDiscontinuity) {
878            // Signal discontinuity.
879
880            if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
881                // If this was a live event this made no sense since
882                // we don't have access to all the segment before the current
883                // one.
884                mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber);
885            }
886
887            if (seekDiscontinuity || explicitDiscontinuity) {
888                ALOGI("queueing discontinuity (seek=%d, explicit=%d)",
889                     seekDiscontinuity, explicitDiscontinuity);
890
891                queueDiscontinuity(
892                        explicitDiscontinuity
893                            ? ATSParser::DISCONTINUITY_FORMATCHANGE
894                            : ATSParser::DISCONTINUITY_SEEK,
895                        NULL /* extra */);
896            }
897        }
898
899        err = OK;
900        if (bufferStartsWithTsSyncByte(buffer)) {
901            // Incremental extraction is only supported for MPEG2 transport streams.
902            if (tsBuffer == NULL) {
903                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
904                tsBuffer->setRange(0, 0);
905            } else if (tsBuffer->capacity() != buffer->capacity()) {
906                size_t tsOff = tsBuffer->offset(), tsSize = tsBuffer->size();
907                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
908                tsBuffer->setRange(tsOff, tsSize);
909            }
910            tsBuffer->setRange(tsBuffer->offset(), tsBuffer->size() + bytesRead);
911
912            err = extractAndQueueAccessUnitsFromTs(tsBuffer);
913        }
914
915        if (err == -EAGAIN) {
916            // bad starting sequence number hint
917            postMonitorQueue();
918            return;
919        }
920
921        if (err == ERROR_OUT_OF_RANGE) {
922            // reached stopping point
923            stopAsync(/* selfTriggered = */ true);
924            return;
925        }
926
927        if (err != OK) {
928            notifyError(err);
929            return;
930        }
931
932        mStartup = false;
933    } while (bytesRead != 0);
934
935    if (bufferStartsWithTsSyncByte(buffer)) {
936        // If we still don't see a stream after fetching a full ts segment mark it as
937        // nonexistent.
938        const size_t kNumTypes = ATSParser::NUM_SOURCE_TYPES;
939        ATSParser::SourceType srcTypes[kNumTypes] =
940                { ATSParser::VIDEO, ATSParser::AUDIO };
941        LiveSession::StreamType streamTypes[kNumTypes] =
942                { LiveSession::STREAMTYPE_VIDEO, LiveSession::STREAMTYPE_AUDIO };
943
944        for (size_t i = 0; i < kNumTypes; i++) {
945            ATSParser::SourceType srcType = srcTypes[i];
946            LiveSession::StreamType streamType = streamTypes[i];
947
948            sp<AnotherPacketSource> source =
949                static_cast<AnotherPacketSource *>(
950                    mTSParser->getSource(srcType).get());
951
952            if (source == NULL) {
953                ALOGW("MPEG2 Transport stream does not contain %s data.",
954                      srcType == ATSParser::VIDEO ? "video" : "audio");
955
956                mStreamTypeMask &= ~streamType;
957                mPacketSources.removeItem(streamType);
958            }
959        }
960
961    }
962
963    if (checkDecryptPadding(buffer) != OK) {
964        ALOGE("Incorrect padding bytes after decryption.");
965        notifyError(ERROR_MALFORMED);
966        return;
967    }
968
969    status_t err = OK;
970    if (tsBuffer != NULL) {
971        AString method;
972        CHECK(buffer->meta()->findString("cipher-method", &method));
973        if ((tsBuffer->size() > 0 && method == "NONE")
974                || tsBuffer->size() > 16) {
975            ALOGE("MPEG2 transport stream is not an even multiple of 188 "
976                    "bytes in length.");
977            notifyError(ERROR_MALFORMED);
978            return;
979        }
980    }
981
982    // bulk extract non-ts files
983    if (tsBuffer == NULL) {
984      err = extractAndQueueAccessUnits(buffer, itemMeta);
985    }
986
987    if (err != OK) {
988        notifyError(err);
989        return;
990    }
991
992    ++mSeqNumber;
993
994    postMonitorQueue();
995}
996
997int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const {
998    int32_t firstSeqNumberInPlaylist;
999    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
1000                "media-sequence", &firstSeqNumberInPlaylist)) {
1001        firstSeqNumberInPlaylist = 0;
1002    }
1003
1004    size_t index = 0;
1005    int64_t segmentStartUs = 0;
1006    while (index < mPlaylist->size()) {
1007        sp<AMessage> itemMeta;
1008        CHECK(mPlaylist->itemAt(
1009                    index, NULL /* uri */, &itemMeta));
1010
1011        int64_t itemDurationUs;
1012        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1013
1014        if (timeUs < segmentStartUs + itemDurationUs) {
1015            break;
1016        }
1017
1018        segmentStartUs += itemDurationUs;
1019        ++index;
1020    }
1021
1022    if (index >= mPlaylist->size()) {
1023        index = mPlaylist->size() - 1;
1024    }
1025
1026    return firstSeqNumberInPlaylist + index;
1027}
1028
1029status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer) {
1030    if (mTSParser == NULL) {
1031        // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers.
1032        mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
1033    }
1034
1035    if (mNextPTSTimeUs >= 0ll) {
1036        sp<AMessage> extra = new AMessage;
1037        // Since we are using absolute timestamps, signal an offset of 0 to prevent
1038        // ATSParser from skewing the timestamps of access units.
1039        extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0);
1040
1041        mTSParser->signalDiscontinuity(
1042                ATSParser::DISCONTINUITY_SEEK, extra);
1043
1044        mNextPTSTimeUs = -1ll;
1045    }
1046
1047    size_t offset = 0;
1048    while (offset + 188 <= buffer->size()) {
1049        status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188);
1050
1051        if (err != OK) {
1052            return err;
1053        }
1054
1055        offset += 188;
1056    }
1057    // setRange to indicate consumed bytes.
1058    buffer->setRange(buffer->offset() + offset, buffer->size() - offset);
1059
1060    status_t err = OK;
1061    for (size_t i = mPacketSources.size(); i-- > 0;) {
1062        sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
1063
1064        const char *key;
1065        ATSParser::SourceType type;
1066        const LiveSession::StreamType stream = mPacketSources.keyAt(i);
1067        switch (stream) {
1068            case LiveSession::STREAMTYPE_VIDEO:
1069                type = ATSParser::VIDEO;
1070                key = "timeUsVideo";
1071                break;
1072
1073            case LiveSession::STREAMTYPE_AUDIO:
1074                type = ATSParser::AUDIO;
1075                key = "timeUsAudio";
1076                break;
1077
1078            case LiveSession::STREAMTYPE_SUBTITLES:
1079            {
1080                ALOGE("MPEG2 Transport streams do not contain subtitles.");
1081                return ERROR_MALFORMED;
1082                break;
1083            }
1084
1085            default:
1086                TRESPASS();
1087        }
1088
1089        sp<AnotherPacketSource> source =
1090            static_cast<AnotherPacketSource *>(
1091                    mTSParser->getSource(type).get());
1092
1093        if (source == NULL) {
1094            continue;
1095        }
1096
1097        int64_t timeUs;
1098        sp<ABuffer> accessUnit;
1099        status_t finalResult;
1100        while (source->hasBufferAvailable(&finalResult)
1101                && source->dequeueAccessUnit(&accessUnit) == OK) {
1102
1103            CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
1104            if (mMinStartTimeUs > 0) {
1105                if (timeUs < mMinStartTimeUs) {
1106                    // TODO untested path
1107                    // try a later ts
1108                    int32_t targetDuration;
1109                    mPlaylist->meta()->findInt32("target-duration", &targetDuration);
1110                    int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration;
1111                    if (incr == 0) {
1112                        // increment mSeqNumber by at least one
1113                        incr = 1;
1114                    }
1115                    mSeqNumber += incr;
1116                    err = -EAGAIN;
1117                    break;
1118                } else {
1119                    int64_t startTimeUs;
1120                    if (mStartTimeUsNotify != NULL
1121                            && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) {
1122                        mStartTimeUsNotify->setInt64(key, timeUs);
1123
1124                        uint32_t streamMask = 0;
1125                        mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask);
1126                        streamMask |= mPacketSources.keyAt(i);
1127                        mStartTimeUsNotify->setInt32("streamMask", streamMask);
1128
1129                        if (streamMask == mStreamTypeMask) {
1130                            mStartTimeUsNotify->post();
1131                            mStartTimeUsNotify.clear();
1132                        }
1133                    }
1134                }
1135            }
1136
1137            if (mStopParams != NULL) {
1138                // Queue discontinuity in original stream.
1139                int64_t stopTimeUs;
1140                if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) {
1141                    packetSource->queueAccessUnit(mSession->createFormatChangeBuffer());
1142                    mStreamTypeMask &= ~stream;
1143                    mPacketSources.removeItemsAt(i);
1144                    break;
1145                }
1146            }
1147
1148            // Note that we do NOT dequeue any discontinuities except for format change.
1149
1150            // for simplicity, store a reference to the format in each unit
1151            sp<MetaData> format = source->getFormat();
1152            if (format != NULL) {
1153                accessUnit->meta()->setObject("format", format);
1154            }
1155
1156            // Stash the sequence number so we can hint future playlist where to start at.
1157            accessUnit->meta()->setInt32("seq", mSeqNumber);
1158            packetSource->queueAccessUnit(accessUnit);
1159        }
1160
1161        if (err != OK) {
1162            break;
1163        }
1164    }
1165
1166    if (err != OK) {
1167        for (size_t i = mPacketSources.size(); i-- > 0;) {
1168            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
1169            packetSource->clear();
1170        }
1171        return err;
1172    }
1173
1174    if (!mStreamTypeMask) {
1175        // Signal gap is filled between original and new stream.
1176        ALOGV("ERROR OUT OF RANGE");
1177        return ERROR_OUT_OF_RANGE;
1178    }
1179
1180    return OK;
1181}
1182
1183status_t PlaylistFetcher::extractAndQueueAccessUnits(
1184        const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
1185    if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) {
1186        if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) {
1187            ALOGE("This stream only contains subtitles.");
1188            return ERROR_MALFORMED;
1189        }
1190
1191        const sp<AnotherPacketSource> packetSource =
1192            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
1193
1194        int64_t durationUs;
1195        CHECK(itemMeta->findInt64("durationUs", &durationUs));
1196        buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber));
1197        buffer->meta()->setInt64("durationUs", durationUs);
1198        buffer->meta()->setInt32("seq", mSeqNumber);
1199
1200        packetSource->queueAccessUnit(buffer);
1201        return OK;
1202    }
1203
1204    if (mNextPTSTimeUs >= 0ll) {
1205        mFirstPTSValid = false;
1206        mAbsoluteTimeAnchorUs = mNextPTSTimeUs;
1207        mNextPTSTimeUs = -1ll;
1208    }
1209
1210    // This better be an ISO 13818-7 (AAC) or ISO 13818-1 (MPEG) audio
1211    // stream prefixed by an ID3 tag.
1212
1213    bool firstID3Tag = true;
1214    uint64_t PTS = 0;
1215
1216    for (;;) {
1217        // Make sure to skip all ID3 tags preceding the audio data.
1218        // At least one must be present to provide the PTS timestamp.
1219
1220        ID3 id3(buffer->data(), buffer->size(), true /* ignoreV1 */);
1221        if (!id3.isValid()) {
1222            if (firstID3Tag) {
1223                ALOGE("Unable to parse ID3 tag.");
1224                return ERROR_MALFORMED;
1225            } else {
1226                break;
1227            }
1228        }
1229
1230        if (firstID3Tag) {
1231            bool found = false;
1232
1233            ID3::Iterator it(id3, "PRIV");
1234            while (!it.done()) {
1235                size_t length;
1236                const uint8_t *data = it.getData(&length);
1237
1238                static const char *kMatchName =
1239                    "com.apple.streaming.transportStreamTimestamp";
1240                static const size_t kMatchNameLen = strlen(kMatchName);
1241
1242                if (length == kMatchNameLen + 1 + 8
1243                        && !strncmp((const char *)data, kMatchName, kMatchNameLen)) {
1244                    found = true;
1245                    PTS = U64_AT(&data[kMatchNameLen + 1]);
1246                }
1247
1248                it.next();
1249            }
1250
1251            if (!found) {
1252                ALOGE("Unable to extract transportStreamTimestamp from ID3 tag.");
1253                return ERROR_MALFORMED;
1254            }
1255        }
1256
1257        // skip the ID3 tag
1258        buffer->setRange(
1259                buffer->offset() + id3.rawSize(), buffer->size() - id3.rawSize());
1260
1261        firstID3Tag = false;
1262    }
1263
1264    if (!mFirstPTSValid) {
1265        mFirstPTSValid = true;
1266        mFirstPTS = PTS;
1267    }
1268    PTS -= mFirstPTS;
1269
1270    int64_t timeUs = (PTS * 100ll) / 9ll + mAbsoluteTimeAnchorUs;
1271
1272    if (mStreamTypeMask != LiveSession::STREAMTYPE_AUDIO) {
1273        ALOGW("This stream only contains audio data!");
1274
1275        mStreamTypeMask &= LiveSession::STREAMTYPE_AUDIO;
1276
1277        if (mStreamTypeMask == 0) {
1278            return OK;
1279        }
1280    }
1281
1282    sp<AnotherPacketSource> packetSource =
1283        mPacketSources.valueFor(LiveSession::STREAMTYPE_AUDIO);
1284
1285    if (packetSource->getFormat() == NULL && buffer->size() >= 7) {
1286        ABitReader bits(buffer->data(), buffer->size());
1287
1288        // adts_fixed_header
1289
1290        CHECK_EQ(bits.getBits(12), 0xfffu);
1291        bits.skipBits(3);  // ID, layer
1292        bool protection_absent = bits.getBits(1) != 0;
1293
1294        unsigned profile = bits.getBits(2);
1295        CHECK_NE(profile, 3u);
1296        unsigned sampling_freq_index = bits.getBits(4);
1297        bits.getBits(1);  // private_bit
1298        unsigned channel_configuration = bits.getBits(3);
1299        CHECK_NE(channel_configuration, 0u);
1300        bits.skipBits(2);  // original_copy, home
1301
1302        sp<MetaData> meta = MakeAACCodecSpecificData(
1303                profile, sampling_freq_index, channel_configuration);
1304
1305        meta->setInt32(kKeyIsADTS, true);
1306
1307        packetSource->setFormat(meta);
1308    }
1309
1310    int64_t numSamples = 0ll;
1311    int32_t sampleRate;
1312    CHECK(packetSource->getFormat()->findInt32(kKeySampleRate, &sampleRate));
1313
1314    size_t offset = 0;
1315    while (offset < buffer->size()) {
1316        const uint8_t *adtsHeader = buffer->data() + offset;
1317        CHECK_LT(offset + 5, buffer->size());
1318
1319        unsigned aac_frame_length =
1320            ((adtsHeader[3] & 3) << 11)
1321            | (adtsHeader[4] << 3)
1322            | (adtsHeader[5] >> 5);
1323
1324        if (aac_frame_length == 0) {
1325            const uint8_t *id3Header = adtsHeader;
1326            if (!memcmp(id3Header, "ID3", 3)) {
1327                ID3 id3(id3Header, buffer->size() - offset, true);
1328                if (id3.isValid()) {
1329                    offset += id3.rawSize();
1330                    continue;
1331                };
1332            }
1333            return ERROR_MALFORMED;
1334        }
1335
1336        CHECK_LE(offset + aac_frame_length, buffer->size());
1337
1338        sp<ABuffer> unit = new ABuffer(aac_frame_length);
1339        memcpy(unit->data(), adtsHeader, aac_frame_length);
1340
1341        int64_t unitTimeUs = timeUs + numSamples * 1000000ll / sampleRate;
1342        unit->meta()->setInt64("timeUs", unitTimeUs);
1343
1344        // Each AAC frame encodes 1024 samples.
1345        numSamples += 1024;
1346
1347        unit->meta()->setInt32("seq", mSeqNumber);
1348        packetSource->queueAccessUnit(unit);
1349
1350        offset += aac_frame_length;
1351    }
1352
1353    return OK;
1354}
1355
1356void PlaylistFetcher::updateDuration() {
1357    int64_t durationUs = 0ll;
1358    for (size_t index = 0; index < mPlaylist->size(); ++index) {
1359        sp<AMessage> itemMeta;
1360        CHECK(mPlaylist->itemAt(
1361                    index, NULL /* uri */, &itemMeta));
1362
1363        int64_t itemDurationUs;
1364        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1365
1366        durationUs += itemDurationUs;
1367    }
1368
1369    sp<AMessage> msg = mNotify->dup();
1370    msg->setInt32("what", kWhatDurationUpdate);
1371    msg->setInt64("durationUs", durationUs);
1372    msg->post();
1373}
1374
1375int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) {
1376    int64_t durationUs, threshold;
1377    if (msg->findInt64("durationUs", &durationUs)) {
1378        return kNumSkipFrames * durationUs;
1379    }
1380
1381    sp<RefBase> obj;
1382    msg->findObject("format", &obj);
1383    MetaData *format = static_cast<MetaData *>(obj.get());
1384
1385    const char *mime;
1386    CHECK(format->findCString(kKeyMIMEType, &mime));
1387    bool audio = !strncasecmp(mime, "audio/", 6);
1388    if (audio) {
1389        // Assumes 1000 samples per frame.
1390        int32_t sampleRate;
1391        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1392        return kNumSkipFrames  /* frames */ * 1000 /* samples */
1393                * (1000000 / sampleRate) /* sample duration (us) */;
1394    } else {
1395        int32_t frameRate;
1396        if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
1397            return kNumSkipFrames * (1000000 / frameRate);
1398        }
1399    }
1400
1401    return 500000ll;
1402}
1403
1404}  // namespace android
1405