PlaylistFetcher.cpp revision 7a39abac839092298cd184c5996dc82010d60a20
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 %d from (%d .. %d)",
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 %d from (%d .. %d)",
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: %d from (%d .. %d), "
775                      "monitor in %lld (retry=%d)",
776                        mSeqNumber, firstSeqNumberInPlaylist,
777                        lastSeqNumberInPlaylist, delayUs, mNumRetries);
778                postMonitorQueue(delayUs);
779                return;
780            }
781
782            // we've missed the boat, let's start from the lowest sequence
783            // number available and signal a discontinuity.
784
785            ALOGI("We've missed the boat, restarting playback."
786                  "  mStartup=%d, was  looking for %d in %d-%d",
787                    mStartup, mSeqNumber, firstSeqNumberInPlaylist,
788                    lastSeqNumberInPlaylist);
789            mSeqNumber = lastSeqNumberInPlaylist - 3;
790            if (mSeqNumber < firstSeqNumberInPlaylist) {
791                mSeqNumber = firstSeqNumberInPlaylist;
792            }
793            explicitDiscontinuity = true;
794
795            // fall through
796        } else {
797            ALOGE("Cannot find sequence number %d in playlist "
798                 "(contains %d - %d)",
799                 mSeqNumber, firstSeqNumberInPlaylist,
800                 firstSeqNumberInPlaylist + mPlaylist->size() - 1);
801
802            notifyError(ERROR_END_OF_STREAM);
803            return;
804        }
805    }
806
807    mNumRetries = 0;
808
809    AString uri;
810    sp<AMessage> itemMeta;
811    CHECK(mPlaylist->itemAt(
812                mSeqNumber - firstSeqNumberInPlaylist,
813                &uri,
814                &itemMeta));
815
816    int32_t val;
817    if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
818        explicitDiscontinuity = true;
819    }
820
821    int64_t range_offset, range_length;
822    if (!itemMeta->findInt64("range-offset", &range_offset)
823            || !itemMeta->findInt64("range-length", &range_length)) {
824        range_offset = 0;
825        range_length = -1;
826    }
827
828    ALOGV("fetching segment %d from (%d .. %d)",
829          mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist);
830
831    ALOGV("fetching '%s'", uri.c_str());
832
833    sp<DataSource> source;
834    sp<ABuffer> buffer, tsBuffer;
835    // decrypt a junk buffer to prefetch key; since a session uses only one http connection,
836    // this avoids interleaved connections to the key and segment file.
837    {
838        sp<ABuffer> junk = new ABuffer(16);
839        junk->setRange(0, 16);
840        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk,
841                true /* first */);
842        if (err != OK) {
843            notifyError(err);
844            return;
845        }
846    }
847
848    // block-wise download
849    ssize_t bytesRead;
850    do {
851        bytesRead = mSession->fetchFile(
852                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source);
853
854        if (bytesRead < 0) {
855            status_t err = bytesRead;
856            ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
857            notifyError(err);
858            return;
859        }
860
861        CHECK(buffer != NULL);
862
863        size_t size = buffer->size();
864        // Set decryption range.
865        buffer->setRange(size - bytesRead, bytesRead);
866        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer,
867                buffer->offset() == 0 /* first */);
868        // Unset decryption range.
869        buffer->setRange(0, size);
870
871        if (err != OK) {
872            ALOGE("decryptBuffer failed w/ error %d", err);
873
874            notifyError(err);
875            return;
876        }
877
878        if (mStartup || seekDiscontinuity || explicitDiscontinuity) {
879            // Signal discontinuity.
880
881            if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
882                // If this was a live event this made no sense since
883                // we don't have access to all the segment before the current
884                // one.
885                mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber);
886            }
887
888            if (seekDiscontinuity || explicitDiscontinuity) {
889                ALOGI("queueing discontinuity (seek=%d, explicit=%d)",
890                     seekDiscontinuity, explicitDiscontinuity);
891
892                queueDiscontinuity(
893                        explicitDiscontinuity
894                            ? ATSParser::DISCONTINUITY_FORMATCHANGE
895                            : ATSParser::DISCONTINUITY_SEEK,
896                        NULL /* extra */);
897            }
898        }
899
900        err = OK;
901        if (bufferStartsWithTsSyncByte(buffer)) {
902            // Incremental extraction is only supported for MPEG2 transport streams.
903            if (tsBuffer == NULL) {
904                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
905                tsBuffer->setRange(0, 0);
906            } else if (tsBuffer->capacity() != buffer->capacity()) {
907                size_t tsOff = tsBuffer->offset(), tsSize = tsBuffer->size();
908                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
909                tsBuffer->setRange(tsOff, tsSize);
910            }
911            tsBuffer->setRange(tsBuffer->offset(), tsBuffer->size() + bytesRead);
912
913            err = extractAndQueueAccessUnitsFromTs(tsBuffer);
914        }
915
916        if (err == -EAGAIN) {
917            // bad starting sequence number hint
918            postMonitorQueue();
919            return;
920        }
921
922        if (err == ERROR_OUT_OF_RANGE) {
923            // reached stopping point
924            stopAsync(/* selfTriggered = */ true);
925            return;
926        }
927
928        if (err != OK) {
929            notifyError(err);
930            return;
931        }
932
933        mStartup = false;
934    } while (bytesRead != 0);
935
936    if (bufferStartsWithTsSyncByte(buffer)) {
937        // If we still don't see a stream after fetching a full ts segment mark it as
938        // nonexistent.
939        const size_t kNumTypes = ATSParser::NUM_SOURCE_TYPES;
940        ATSParser::SourceType srcTypes[kNumTypes] =
941                { ATSParser::VIDEO, ATSParser::AUDIO };
942        LiveSession::StreamType streamTypes[kNumTypes] =
943                { LiveSession::STREAMTYPE_VIDEO, LiveSession::STREAMTYPE_AUDIO };
944
945        for (size_t i = 0; i < kNumTypes; i++) {
946            ATSParser::SourceType srcType = srcTypes[i];
947            LiveSession::StreamType streamType = streamTypes[i];
948
949            sp<AnotherPacketSource> source =
950                static_cast<AnotherPacketSource *>(
951                    mTSParser->getSource(srcType).get());
952
953            if (source == NULL) {
954                ALOGW("MPEG2 Transport stream does not contain %s data.",
955                      srcType == ATSParser::VIDEO ? "video" : "audio");
956
957                mStreamTypeMask &= ~streamType;
958                mPacketSources.removeItem(streamType);
959            }
960        }
961
962    }
963
964    if (checkDecryptPadding(buffer) != OK) {
965        ALOGE("Incorrect padding bytes after decryption.");
966        notifyError(ERROR_MALFORMED);
967        return;
968    }
969
970    status_t err = OK;
971    if (tsBuffer != NULL) {
972        AString method;
973        CHECK(buffer->meta()->findString("cipher-method", &method));
974        if ((tsBuffer->size() > 0 && method == "NONE")
975                || tsBuffer->size() > 16) {
976            ALOGE("MPEG2 transport stream is not an even multiple of 188 "
977                    "bytes in length.");
978            notifyError(ERROR_MALFORMED);
979            return;
980        }
981    }
982
983    // bulk extract non-ts files
984    if (tsBuffer == NULL) {
985      err = extractAndQueueAccessUnits(buffer, itemMeta);
986    }
987
988    if (err != OK) {
989        notifyError(err);
990        return;
991    }
992
993    ++mSeqNumber;
994
995    postMonitorQueue();
996}
997
998int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const {
999    int32_t firstSeqNumberInPlaylist;
1000    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
1001                "media-sequence", &firstSeqNumberInPlaylist)) {
1002        firstSeqNumberInPlaylist = 0;
1003    }
1004
1005    size_t index = 0;
1006    int64_t segmentStartUs = 0;
1007    while (index < mPlaylist->size()) {
1008        sp<AMessage> itemMeta;
1009        CHECK(mPlaylist->itemAt(
1010                    index, NULL /* uri */, &itemMeta));
1011
1012        int64_t itemDurationUs;
1013        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1014
1015        if (timeUs < segmentStartUs + itemDurationUs) {
1016            break;
1017        }
1018
1019        segmentStartUs += itemDurationUs;
1020        ++index;
1021    }
1022
1023    if (index >= mPlaylist->size()) {
1024        index = mPlaylist->size() - 1;
1025    }
1026
1027    return firstSeqNumberInPlaylist + index;
1028}
1029
1030status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer) {
1031    if (mTSParser == NULL) {
1032        // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers.
1033        mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
1034    }
1035
1036    if (mNextPTSTimeUs >= 0ll) {
1037        sp<AMessage> extra = new AMessage;
1038        // Since we are using absolute timestamps, signal an offset of 0 to prevent
1039        // ATSParser from skewing the timestamps of access units.
1040        extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0);
1041
1042        mTSParser->signalDiscontinuity(
1043                ATSParser::DISCONTINUITY_SEEK, extra);
1044
1045        mNextPTSTimeUs = -1ll;
1046    }
1047
1048    size_t offset = 0;
1049    while (offset + 188 <= buffer->size()) {
1050        status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188);
1051
1052        if (err != OK) {
1053            return err;
1054        }
1055
1056        offset += 188;
1057    }
1058    // setRange to indicate consumed bytes.
1059    buffer->setRange(buffer->offset() + offset, buffer->size() - offset);
1060
1061    status_t err = OK;
1062    for (size_t i = mPacketSources.size(); i-- > 0;) {
1063        sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
1064
1065        const char *key;
1066        ATSParser::SourceType type;
1067        const LiveSession::StreamType stream = mPacketSources.keyAt(i);
1068        switch (stream) {
1069            case LiveSession::STREAMTYPE_VIDEO:
1070                type = ATSParser::VIDEO;
1071                key = "timeUsVideo";
1072                break;
1073
1074            case LiveSession::STREAMTYPE_AUDIO:
1075                type = ATSParser::AUDIO;
1076                key = "timeUsAudio";
1077                break;
1078
1079            case LiveSession::STREAMTYPE_SUBTITLES:
1080            {
1081                ALOGE("MPEG2 Transport streams do not contain subtitles.");
1082                return ERROR_MALFORMED;
1083                break;
1084            }
1085
1086            default:
1087                TRESPASS();
1088        }
1089
1090        sp<AnotherPacketSource> source =
1091            static_cast<AnotherPacketSource *>(
1092                    mTSParser->getSource(type).get());
1093
1094        if (source == NULL) {
1095            continue;
1096        }
1097
1098        int64_t timeUs;
1099        sp<ABuffer> accessUnit;
1100        status_t finalResult;
1101        while (source->hasBufferAvailable(&finalResult)
1102                && source->dequeueAccessUnit(&accessUnit) == OK) {
1103
1104            CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
1105            if (mMinStartTimeUs > 0) {
1106                if (timeUs < mMinStartTimeUs) {
1107                    // TODO untested path
1108                    // try a later ts
1109                    int32_t targetDuration;
1110                    mPlaylist->meta()->findInt32("target-duration", &targetDuration);
1111                    int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration;
1112                    if (incr == 0) {
1113                        // increment mSeqNumber by at least one
1114                        incr = 1;
1115                    }
1116                    mSeqNumber += incr;
1117                    err = -EAGAIN;
1118                    break;
1119                } else {
1120                    int64_t startTimeUs;
1121                    if (mStartTimeUsNotify != NULL
1122                            && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) {
1123                        mStartTimeUsNotify->setInt64(key, timeUs);
1124
1125                        uint32_t streamMask = 0;
1126                        mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask);
1127                        streamMask |= mPacketSources.keyAt(i);
1128                        mStartTimeUsNotify->setInt32("streamMask", streamMask);
1129
1130                        if (streamMask == mStreamTypeMask) {
1131                            mStartTimeUsNotify->post();
1132                            mStartTimeUsNotify.clear();
1133                        }
1134                    }
1135                }
1136            }
1137
1138            if (mStopParams != NULL) {
1139                // Queue discontinuity in original stream.
1140                int64_t stopTimeUs;
1141                if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) {
1142                    packetSource->queueAccessUnit(mSession->createFormatChangeBuffer());
1143                    mStreamTypeMask &= ~stream;
1144                    mPacketSources.removeItemsAt(i);
1145                    break;
1146                }
1147            }
1148
1149            // Note that we do NOT dequeue any discontinuities except for format change.
1150
1151            // for simplicity, store a reference to the format in each unit
1152            sp<MetaData> format = source->getFormat();
1153            if (format != NULL) {
1154                accessUnit->meta()->setObject("format", format);
1155            }
1156
1157            // Stash the sequence number so we can hint future playlist where to start at.
1158            accessUnit->meta()->setInt32("seq", mSeqNumber);
1159            packetSource->queueAccessUnit(accessUnit);
1160        }
1161
1162        if (err != OK) {
1163            break;
1164        }
1165    }
1166
1167    if (err != OK) {
1168        for (size_t i = mPacketSources.size(); i-- > 0;) {
1169            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
1170            packetSource->clear();
1171        }
1172        return err;
1173    }
1174
1175    if (!mStreamTypeMask) {
1176        // Signal gap is filled between original and new stream.
1177        ALOGV("ERROR OUT OF RANGE");
1178        return ERROR_OUT_OF_RANGE;
1179    }
1180
1181    return OK;
1182}
1183
1184status_t PlaylistFetcher::extractAndQueueAccessUnits(
1185        const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
1186    if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) {
1187        if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) {
1188            ALOGE("This stream only contains subtitles.");
1189            return ERROR_MALFORMED;
1190        }
1191
1192        const sp<AnotherPacketSource> packetSource =
1193            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
1194
1195        int64_t durationUs;
1196        CHECK(itemMeta->findInt64("durationUs", &durationUs));
1197        buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber));
1198        buffer->meta()->setInt64("durationUs", durationUs);
1199        buffer->meta()->setInt32("seq", mSeqNumber);
1200
1201        packetSource->queueAccessUnit(buffer);
1202        return OK;
1203    }
1204
1205    if (mNextPTSTimeUs >= 0ll) {
1206        mFirstPTSValid = false;
1207        mAbsoluteTimeAnchorUs = mNextPTSTimeUs;
1208        mNextPTSTimeUs = -1ll;
1209    }
1210
1211    // This better be an ISO 13818-7 (AAC) or ISO 13818-1 (MPEG) audio
1212    // stream prefixed by an ID3 tag.
1213
1214    bool firstID3Tag = true;
1215    uint64_t PTS = 0;
1216
1217    for (;;) {
1218        // Make sure to skip all ID3 tags preceding the audio data.
1219        // At least one must be present to provide the PTS timestamp.
1220
1221        ID3 id3(buffer->data(), buffer->size(), true /* ignoreV1 */);
1222        if (!id3.isValid()) {
1223            if (firstID3Tag) {
1224                ALOGE("Unable to parse ID3 tag.");
1225                return ERROR_MALFORMED;
1226            } else {
1227                break;
1228            }
1229        }
1230
1231        if (firstID3Tag) {
1232            bool found = false;
1233
1234            ID3::Iterator it(id3, "PRIV");
1235            while (!it.done()) {
1236                size_t length;
1237                const uint8_t *data = it.getData(&length);
1238
1239                static const char *kMatchName =
1240                    "com.apple.streaming.transportStreamTimestamp";
1241                static const size_t kMatchNameLen = strlen(kMatchName);
1242
1243                if (length == kMatchNameLen + 1 + 8
1244                        && !strncmp((const char *)data, kMatchName, kMatchNameLen)) {
1245                    found = true;
1246                    PTS = U64_AT(&data[kMatchNameLen + 1]);
1247                }
1248
1249                it.next();
1250            }
1251
1252            if (!found) {
1253                ALOGE("Unable to extract transportStreamTimestamp from ID3 tag.");
1254                return ERROR_MALFORMED;
1255            }
1256        }
1257
1258        // skip the ID3 tag
1259        buffer->setRange(
1260                buffer->offset() + id3.rawSize(), buffer->size() - id3.rawSize());
1261
1262        firstID3Tag = false;
1263    }
1264
1265    if (!mFirstPTSValid) {
1266        mFirstPTSValid = true;
1267        mFirstPTS = PTS;
1268    }
1269    PTS -= mFirstPTS;
1270
1271    int64_t timeUs = (PTS * 100ll) / 9ll + mAbsoluteTimeAnchorUs;
1272
1273    if (mStreamTypeMask != LiveSession::STREAMTYPE_AUDIO) {
1274        ALOGW("This stream only contains audio data!");
1275
1276        mStreamTypeMask &= LiveSession::STREAMTYPE_AUDIO;
1277
1278        if (mStreamTypeMask == 0) {
1279            return OK;
1280        }
1281    }
1282
1283    sp<AnotherPacketSource> packetSource =
1284        mPacketSources.valueFor(LiveSession::STREAMTYPE_AUDIO);
1285
1286    if (packetSource->getFormat() == NULL && buffer->size() >= 7) {
1287        ABitReader bits(buffer->data(), buffer->size());
1288
1289        // adts_fixed_header
1290
1291        CHECK_EQ(bits.getBits(12), 0xfffu);
1292        bits.skipBits(3);  // ID, layer
1293        bool protection_absent = bits.getBits(1) != 0;
1294
1295        unsigned profile = bits.getBits(2);
1296        CHECK_NE(profile, 3u);
1297        unsigned sampling_freq_index = bits.getBits(4);
1298        bits.getBits(1);  // private_bit
1299        unsigned channel_configuration = bits.getBits(3);
1300        CHECK_NE(channel_configuration, 0u);
1301        bits.skipBits(2);  // original_copy, home
1302
1303        sp<MetaData> meta = MakeAACCodecSpecificData(
1304                profile, sampling_freq_index, channel_configuration);
1305
1306        meta->setInt32(kKeyIsADTS, true);
1307
1308        packetSource->setFormat(meta);
1309    }
1310
1311    int64_t numSamples = 0ll;
1312    int32_t sampleRate;
1313    CHECK(packetSource->getFormat()->findInt32(kKeySampleRate, &sampleRate));
1314
1315    size_t offset = 0;
1316    while (offset < buffer->size()) {
1317        const uint8_t *adtsHeader = buffer->data() + offset;
1318        CHECK_LT(offset + 5, buffer->size());
1319
1320        unsigned aac_frame_length =
1321            ((adtsHeader[3] & 3) << 11)
1322            | (adtsHeader[4] << 3)
1323            | (adtsHeader[5] >> 5);
1324
1325        if (aac_frame_length == 0) {
1326            const uint8_t *id3Header = adtsHeader;
1327            if (!memcmp(id3Header, "ID3", 3)) {
1328                ID3 id3(id3Header, buffer->size() - offset, true);
1329                if (id3.isValid()) {
1330                    offset += id3.rawSize();
1331                    continue;
1332                };
1333            }
1334            return ERROR_MALFORMED;
1335        }
1336
1337        CHECK_LE(offset + aac_frame_length, buffer->size());
1338
1339        sp<ABuffer> unit = new ABuffer(aac_frame_length);
1340        memcpy(unit->data(), adtsHeader, aac_frame_length);
1341
1342        int64_t unitTimeUs = timeUs + numSamples * 1000000ll / sampleRate;
1343        unit->meta()->setInt64("timeUs", unitTimeUs);
1344
1345        // Each AAC frame encodes 1024 samples.
1346        numSamples += 1024;
1347
1348        unit->meta()->setInt32("seq", mSeqNumber);
1349        packetSource->queueAccessUnit(unit);
1350
1351        offset += aac_frame_length;
1352    }
1353
1354    return OK;
1355}
1356
1357void PlaylistFetcher::updateDuration() {
1358    int64_t durationUs = 0ll;
1359    for (size_t index = 0; index < mPlaylist->size(); ++index) {
1360        sp<AMessage> itemMeta;
1361        CHECK(mPlaylist->itemAt(
1362                    index, NULL /* uri */, &itemMeta));
1363
1364        int64_t itemDurationUs;
1365        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1366
1367        durationUs += itemDurationUs;
1368    }
1369
1370    sp<AMessage> msg = mNotify->dup();
1371    msg->setInt32("what", kWhatDurationUpdate);
1372    msg->setInt64("durationUs", durationUs);
1373    msg->post();
1374}
1375
1376int64_t PlaylistFetcher::resumeThreshold(const sp<AMessage> &msg) {
1377    int64_t durationUs, threshold;
1378    if (msg->findInt64("durationUs", &durationUs)) {
1379        return kNumSkipFrames * durationUs;
1380    }
1381
1382    sp<RefBase> obj;
1383    msg->findObject("format", &obj);
1384    MetaData *format = static_cast<MetaData *>(obj.get());
1385
1386    const char *mime;
1387    CHECK(format->findCString(kKeyMIMEType, &mime));
1388    bool audio = !strncasecmp(mime, "audio/", 6);
1389    if (audio) {
1390        // Assumes 1000 samples per frame.
1391        int32_t sampleRate;
1392        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
1393        return kNumSkipFrames  /* frames */ * 1000 /* samples */
1394                * (1000000 / sampleRate) /* sample duration (us) */;
1395    } else {
1396        int32_t frameRate;
1397        if (format->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
1398            return kNumSkipFrames * (1000000 / frameRate);
1399        }
1400    }
1401
1402    return 500000ll;
1403}
1404
1405}  // namespace android
1406