PlaylistFetcher.cpp revision a722375a32e9a0febc3770513647dc32bf88ccc0
114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber/*
214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * Copyright (C) 2012 The Android Open Source Project
314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *
414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * you may not use this file except in compliance with the License.
614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * You may obtain a copy of the License at
714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *
814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *
1014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * Unless required by applicable law or agreed to in writing, software
1114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * See the License for the specific language governing permissions and
1414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber * limitations under the License.
1514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber */
1614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber//#define LOG_NDEBUG 0
1814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#define LOG_TAG "PlaylistFetcher"
1914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <utils/Log.h>
200852843d304006e3ab333081fddda13b07193de8Robert Shih#include <utils/misc.h>
2114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "PlaylistFetcher.h"
235abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang#include "HTTPDownloader.h"
2414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "LiveSession.h"
2514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "M3UParser.h"
2614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "include/avc_utils.h"
2714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "include/ID3.h"
2814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "mpeg2ts/AnotherPacketSource.h"
2914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
3014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/foundation/ABitReader.h>
3114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
3214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/foundation/ADebug.h>
3314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/MediaDefs.h>
3414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/MetaData.h>
3514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/Utils.h>
3614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
3714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <ctype.h>
38b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross#include <inttypes.h>
3914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <openssl/aes.h>
4014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4125f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang#define FLOGV(fmt, ...) ALOGV("[fetcher-%d] " fmt, mFetcherID, ##__VA_ARGS__)
4225f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang#define FSLOGV(stream, fmt, ...) ALOGV("[fetcher-%d] [%s] " fmt, mFetcherID, \
4325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang         LiveSession::getNameForStream(stream), ##__VA_ARGS__)
4425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
4514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubernamespace android {
4614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// static
487c8708046117e03c0d38006bdd9685139df3ac6bChong Zhangconst int64_t PlaylistFetcher::kMinBufferedDurationUs = 30000000ll;
49e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnarconst int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
50a93fd2be99d21629bed504b9b7df035fc2f54562Leena Winterrowd// LCM of 188 (size of a TS packet) & 1k works well
51a93fd2be99d21629bed504b9b7df035fc2f54562Leena Winterrowdconst int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024;
5214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
53a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangstruct PlaylistFetcher::DownloadState : public RefBase {
54a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    DownloadState();
55a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    void resetState();
56a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    bool hasSavedState() const;
57a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    void restoreState(
58a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            AString &uri,
59a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<AMessage> &itemMeta,
60a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<ABuffer> &buffer,
61a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<ABuffer> &tsBuffer,
62a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            int32_t &firstSeqNumberInPlaylist,
63a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            int32_t &lastSeqNumberInPlaylist);
64a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    void saveState(
65a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            AString &uri,
66a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<AMessage> &itemMeta,
67a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<ABuffer> &buffer,
68a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            sp<ABuffer> &tsBuffer,
69a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            int32_t &firstSeqNumberInPlaylist,
70a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            int32_t &lastSeqNumberInPlaylist);
71a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
72a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangprivate:
73a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    bool mHasSavedState;
74a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    AString mUri;
75a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<AMessage> mItemMeta;
76a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<ABuffer> mBuffer;
77a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<ABuffer> mTsBuffer;
78a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int32_t mFirstSeqNumberInPlaylist;
79a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int32_t mLastSeqNumberInPlaylist;
80a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang};
81a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
82a48d372833ccec13c96ece9efcc226e8beac7f59Chong ZhangPlaylistFetcher::DownloadState::DownloadState() {
83a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    resetState();
84a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
85a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
86a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangbool PlaylistFetcher::DownloadState::hasSavedState() const {
87a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    return mHasSavedState;
88a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
89a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
90a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangvoid PlaylistFetcher::DownloadState::resetState() {
91a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mHasSavedState = false;
92a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
93a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mUri.clear();
94a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mItemMeta = NULL;
95a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mBuffer = NULL;
96a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mTsBuffer = NULL;
97a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mFirstSeqNumberInPlaylist = 0;
98a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mLastSeqNumberInPlaylist = 0;
99a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
100a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
101a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangvoid PlaylistFetcher::DownloadState::restoreState(
102a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        AString &uri,
103a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<AMessage> &itemMeta,
104a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<ABuffer> &buffer,
105a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<ABuffer> &tsBuffer,
106a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &firstSeqNumberInPlaylist,
107a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &lastSeqNumberInPlaylist) {
108a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (!mHasSavedState) {
109a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return;
110a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
111a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
112a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    uri = mUri;
113a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    itemMeta = mItemMeta;
114a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    buffer = mBuffer;
115a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    tsBuffer = mTsBuffer;
116a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    firstSeqNumberInPlaylist = mFirstSeqNumberInPlaylist;
117a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    lastSeqNumberInPlaylist = mLastSeqNumberInPlaylist;
118a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
119a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    resetState();
120a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
121a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
122a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangvoid PlaylistFetcher::DownloadState::saveState(
123a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        AString &uri,
124a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<AMessage> &itemMeta,
125a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<ABuffer> &buffer,
126a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<ABuffer> &tsBuffer,
127a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &firstSeqNumberInPlaylist,
128a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &lastSeqNumberInPlaylist) {
129a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mHasSavedState = true;
130a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
131a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mUri = uri;
132a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mItemMeta = itemMeta;
133a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mBuffer = buffer;
134a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mTsBuffer = tsBuffer;
135a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mFirstSeqNumberInPlaylist = firstSeqNumberInPlaylist;
136a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mLastSeqNumberInPlaylist = lastSeqNumberInPlaylist;
137a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
138a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
13914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas HuberPlaylistFetcher::PlaylistFetcher(
14014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<AMessage> &notify,
14114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<LiveSession> &session,
142b44ce2f84691559672cfaf6bb8fd3a9ac43904f2Robert Shih        const char *uri,
14325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        int32_t id,
144b44ce2f84691559672cfaf6bb8fd3a9ac43904f2Robert Shih        int32_t subtitleGeneration)
14514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    : mNotify(notify),
14614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mSession(session),
14714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mURI(uri),
14825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang      mFetcherID(id),
14914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mStreamTypeMask(0),
15014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mStartTimeUs(-1ll),
151309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih      mSegmentStartTimeUs(-1ll),
152309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih      mDiscontinuitySeq(-1ll),
153309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih      mStartTimeUsRelative(false),
15414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mLastPlaylistFetchTimeUs(-1ll),
155978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang      mPlaylistTimeUs(-1ll),
15614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mSeqNumber(-1),
15714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mNumRetries(0),
15814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mStartup(true),
1597c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang      mIDRFound(false),
160a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang      mSeekMode(LiveSession::kSeekModeExactPosition),
161c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang      mTimeChangeSignaled(false),
16214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mNextPTSTimeUs(-1ll),
16314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mMonitorQueueGeneration(0),
164b44ce2f84691559672cfaf6bb8fd3a9ac43904f2Robert Shih      mSubtitleGeneration(subtitleGeneration),
165c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang      mLastDiscontinuitySeq(-1ll),
16614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
16714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mFirstPTSValid(false),
168a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang      mFirstTimeUs(-1ll),
169a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang      mVideoBuffer(new AnotherPacketSource(NULL)),
170a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang      mThresholdRatio(-1.0f),
1710852843d304006e3ab333081fddda13b07193de8Robert Shih      mDownloadState(new DownloadState()),
1720852843d304006e3ab333081fddda13b07193de8Robert Shih      mHasMetadata(false) {
17314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    memset(mPlaylistHash, 0, sizeof(mPlaylistHash));
1745abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    mHTTPDownloader = mSession->getHTTPDownloader();
17514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
17614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
17714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas HuberPlaylistFetcher::~PlaylistFetcher() {
17814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
17914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
18025f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhangint32_t PlaylistFetcher::getFetcherID() const {
18125f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang    return mFetcherID;
18225f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang}
18325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
18414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberint64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const {
18514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK(mPlaylist != NULL);
18614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
187978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int32_t firstSeqNumberInPlaylist, lastSeqNumberInPlaylist;
188978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    mPlaylist->getSeqNumberRange(
189978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            &firstSeqNumberInPlaylist, &lastSeqNumberInPlaylist);
19014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
19114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK_GE(seqNumber, firstSeqNumberInPlaylist);
19214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK_LE(seqNumber, lastSeqNumberInPlaylist);
19314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
19414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t segmentStartUs = 0ll;
19514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (int32_t index = 0;
19614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            index < seqNumber - firstSeqNumberInPlaylist; ++index) {
19714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        sp<AMessage> itemMeta;
19814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(mPlaylist->itemAt(
19914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    index, NULL /* uri */, &itemMeta));
20014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
20114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        int64_t itemDurationUs;
20214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
20314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
20414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        segmentStartUs += itemDurationUs;
20514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
20614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
20714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return segmentStartUs;
20814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
20914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2107c8708046117e03c0d38006bdd9685139df3ac6bChong Zhangint64_t PlaylistFetcher::getSegmentDurationUs(int32_t seqNumber) const {
2117c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    CHECK(mPlaylist != NULL);
2127c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
213978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int32_t firstSeqNumberInPlaylist, lastSeqNumberInPlaylist;
214978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    mPlaylist->getSeqNumberRange(
215978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            &firstSeqNumberInPlaylist, &lastSeqNumberInPlaylist);
2167c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
2177c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    CHECK_GE(seqNumber, firstSeqNumberInPlaylist);
2187c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    CHECK_LE(seqNumber, lastSeqNumberInPlaylist);
2197c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
2207c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    int32_t index = seqNumber - firstSeqNumberInPlaylist;
2217c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    sp<AMessage> itemMeta;
2227c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    CHECK(mPlaylist->itemAt(
2237c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                index, NULL /* uri */, &itemMeta));
2247c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
2257c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    int64_t itemDurationUs;
2267c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
2277c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
2287c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    return itemDurationUs;
2297c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang}
2307c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
231e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnarint64_t PlaylistFetcher::delayUsToRefreshPlaylist() const {
232e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    int64_t nowUs = ALooper::GetNowUs();
233e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar
234e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) {
23514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
236e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar        return 0ll;
237e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    }
238e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar
239e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (mPlaylist->isComplete()) {
240e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar        return (~0llu >> 1);
24114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
24214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
243978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int64_t targetDurationUs = mPlaylist->getTargetDuration();
24414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
24514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t minPlaylistAgeUs;
24614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
24714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    switch (mRefreshState) {
24814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case INITIAL_MINIMUM_RELOAD_DELAY:
24914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
25014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            size_t n = mPlaylist->size();
25114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (n > 0) {
25214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                sp<AMessage> itemMeta;
25314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta));
25414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
25514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                int64_t itemDurationUs;
25614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
25714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
25814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                minPlaylistAgeUs = itemDurationUs;
25914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                break;
26014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
26114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
26214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            // fall through
26314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
26414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
26514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case FIRST_UNCHANGED_RELOAD_ATTEMPT:
26614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
26714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            minPlaylistAgeUs = targetDurationUs / 2;
26814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
26914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
27014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
27114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case SECOND_UNCHANGED_RELOAD_ATTEMPT:
27214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
27314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            minPlaylistAgeUs = (targetDurationUs * 3) / 2;
27414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
27514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
27614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
27714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case THIRD_UNCHANGED_RELOAD_ATTEMPT:
27814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
27914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            minPlaylistAgeUs = targetDurationUs * 3;
28014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
28114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
28214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
28314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        default:
28414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            TRESPASS();
28514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
28614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
28714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
288e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs;
289e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    return delayUs > 0ll ? delayUs : 0ll;
29014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
29114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
29214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t PlaylistFetcher::decryptBuffer(
293ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        size_t playlistIndex, const sp<ABuffer> &buffer,
294ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        bool first) {
29514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AMessage> itemMeta;
29614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool found = false;
29714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString method;
29814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
29914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (ssize_t i = playlistIndex; i >= 0; --i) {
30014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString uri;
30114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(mPlaylist->itemAt(i, &uri, &itemMeta));
30214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
30314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (itemMeta->findString("cipher-method", &method)) {
30414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            found = true;
30514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
30614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
30714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
30814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
30914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!found) {
31014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        method = "NONE";
31114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
312ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    buffer->meta()->setString("cipher-method", method.c_str());
31314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
31414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (method == "NONE") {
31514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return OK;
31614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else if (!(method == "AES-128")) {
31714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGE("Unsupported cipher method '%s'", method.c_str());
31814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_UNSUPPORTED;
31914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
32014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
32114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString keyURI;
32214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!itemMeta->findString("cipher-uri", &keyURI)) {
32314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGE("Missing key uri");
32414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_MALFORMED;
32514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
32614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
32714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t index = mAESKeyForURI.indexOfKey(keyURI);
32814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
32914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<ABuffer> key;
33014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (index >= 0) {
33114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        key = mAESKeyForURI.valueAt(index);
33214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else {
3335abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        ssize_t err = mHTTPDownloader->fetchFile(keyURI.c_str(), &key);
33414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
3355abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (err == ERROR_NOT_CONNECTED) {
3365abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return ERROR_NOT_CONNECTED;
3375abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        } else if (err < 0) {
33814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
33914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_IO;
34014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (key->size() != 16) {
34114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("key file '%s' wasn't 16 bytes in size.", keyURI.c_str());
34214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
34314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
34414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
34514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mAESKeyForURI.add(keyURI, key);
34614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
34714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
34814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AES_KEY aes_key;
34914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (AES_set_decrypt_key(key->data(), 128, &aes_key) != 0) {
35014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGE("failed to set AES decryption key.");
35114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return UNKNOWN_ERROR;
35214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
35314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
354ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    size_t n = buffer->size();
355ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    if (!n) {
356ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        return OK;
357ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    }
358fbe6a51d5841c865b870bab1da7d828caa78a7caRobert Shih
359fbe6a51d5841c865b870bab1da7d828caa78a7caRobert Shih    if (n < 16 || n % 16) {
360fbe6a51d5841c865b870bab1da7d828caa78a7caRobert Shih        ALOGE("not enough or trailing bytes (%zu) in encrypted buffer", n);
361fbe6a51d5841c865b870bab1da7d828caa78a7caRobert Shih        return ERROR_MALFORMED;
362fbe6a51d5841c865b870bab1da7d828caa78a7caRobert Shih    }
36314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
364ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    if (first) {
365ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        // If decrypting the first block in a file, read the iv from the manifest
366ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        // or derive the iv from the file's sequence number.
36714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
368ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        AString iv;
369ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        if (itemMeta->findString("cipher-iv", &iv)) {
370ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
371ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                    || iv.size() != 16 * 2 + 2) {
37214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("malformed cipher IV '%s'.", iv.c_str());
37314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
37414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
37514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
376ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            memset(mAESInitVec, 0, sizeof(mAESInitVec));
377ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            for (size_t i = 0; i < 16; ++i) {
378ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                char c1 = tolower(iv.c_str()[2 + 2 * i]);
379ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                char c2 = tolower(iv.c_str()[3 + 2 * i]);
380ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                if (!isxdigit(c1) || !isxdigit(c2)) {
381ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                    ALOGE("malformed cipher IV '%s'.", iv.c_str());
382ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                    return ERROR_MALFORMED;
383ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                }
384ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
385ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
386ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih
387ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih                mAESInitVec[i] = nibble1 << 4 | nibble2;
388ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            }
389ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        } else {
390ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            memset(mAESInitVec, 0, sizeof(mAESInitVec));
391ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            mAESInitVec[15] = mSeqNumber & 0xff;
392ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            mAESInitVec[14] = (mSeqNumber >> 8) & 0xff;
393ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            mAESInitVec[13] = (mSeqNumber >> 16) & 0xff;
394ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            mAESInitVec[12] = (mSeqNumber >> 24) & 0xff;
39514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
39614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
39714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
39814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AES_cbc_encrypt(
39914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            buffer->data(), buffer->data(), buffer->size(),
400ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            &aes_key, mAESInitVec, AES_DECRYPT);
40114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
402ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    return OK;
403ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih}
40414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
405ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shihstatus_t PlaylistFetcher::checkDecryptPadding(const sp<ABuffer> &buffer) {
406ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    AString method;
407ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    CHECK(buffer->meta()->findString("cipher-method", &method));
408ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    if (method == "NONE") {
409ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        return OK;
410ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    }
41114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
412ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    uint8_t padding = 0;
413ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    if (buffer->size() > 0) {
414ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        padding = buffer->data()[buffer->size() - 1];
41514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
41614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
417ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    if (padding > 16) {
418ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        return ERROR_MALFORMED;
419ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    }
42014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
421ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    for (size_t i = buffer->size() - padding; i < padding; i++) {
422ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        if (buffer->data()[i] != padding) {
423ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih            return ERROR_MALFORMED;
424ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih        }
425ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    }
42614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
427ebe130923fb1a5b8dda4b3ee215593edcd804f0dRobert Shih    buffer->setRange(buffer->offset(), buffer->size() - padding);
42814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
42914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
43014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
431e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnarvoid PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) {
432e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    int64_t maxDelayUs = delayUsToRefreshPlaylist();
433e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (maxDelayUs < minDelayUs) {
434e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar        maxDelayUs = minDelayUs;
435e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    }
436e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (delayUs > maxDelayUs) {
43725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("Need to refresh playlist in %lld", (long long)maxDelayUs);
438e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar        delayUs = maxDelayUs;
439e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    }
4401d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar    sp<AMessage> msg = new AMessage(kWhatMonitorQueue, this);
44114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->setInt32("generation", mMonitorQueueGeneration);
44214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->post(delayUs);
44314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
44414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
44514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::cancelMonitorQueue() {
44614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ++mMonitorQueueGeneration;
44714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
44814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4495abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid PlaylistFetcher::setStoppingThreshold(float thresholdRatio, bool disconnect) {
4505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    {
4515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        AutoMutex _l(mThresholdLock);
4525abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mThresholdRatio = thresholdRatio;
4535abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
4545abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (disconnect) {
4555abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mHTTPDownloader->disconnect();
4565abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
4575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
4585abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
4595abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid PlaylistFetcher::resetStoppingThreshold(bool disconnect) {
4605abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    {
4615abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        AutoMutex _l(mThresholdLock);
4625abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mThresholdRatio = -1.0f;
4635abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    }
4645abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (disconnect) {
4655abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mHTTPDownloader->disconnect();
4665abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    } else {
4675abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        // allow reconnect
4685abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        mHTTPDownloader->reconnect();
469a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
4705abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
4715abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
4725abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangfloat PlaylistFetcher::getStoppingThreshold() {
4735abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    AutoMutex _l(mThresholdLock);
4745abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    return mThresholdRatio;
475c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang}
476c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
47714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::startAsync(
47814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<AnotherPacketSource> &audioSource,
47914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<AnotherPacketSource> &videoSource,
48014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<AnotherPacketSource> &subtitleSource,
4810852843d304006e3ab333081fddda13b07193de8Robert Shih        const sp<AnotherPacketSource> &metadataSource,
4821543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        int64_t startTimeUs,
483309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        int64_t segmentStartTimeUs,
484309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        int32_t startDiscontinuitySeq,
485a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        LiveSession::SeekMode seekMode) {
4861d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar    sp<AMessage> msg = new AMessage(kWhatStart, this);
48714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
48814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint32_t streamTypeMask = 0ul;
48914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
49014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (audioSource != NULL) {
49114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        msg->setPointer("audioSource", audioSource.get());
49214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        streamTypeMask |= LiveSession::STREAMTYPE_AUDIO;
49314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
49414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
49514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (videoSource != NULL) {
49614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        msg->setPointer("videoSource", videoSource.get());
49714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        streamTypeMask |= LiveSession::STREAMTYPE_VIDEO;
49814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
49914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
50014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (subtitleSource != NULL) {
50114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        msg->setPointer("subtitleSource", subtitleSource.get());
50214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        streamTypeMask |= LiveSession::STREAMTYPE_SUBTITLES;
50314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
50414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5050852843d304006e3ab333081fddda13b07193de8Robert Shih    if (metadataSource != NULL) {
5060852843d304006e3ab333081fddda13b07193de8Robert Shih        msg->setPointer("metadataSource", metadataSource.get());
5070852843d304006e3ab333081fddda13b07193de8Robert Shih        // metadataSource does not affect streamTypeMask.
5080852843d304006e3ab333081fddda13b07193de8Robert Shih    }
5090852843d304006e3ab333081fddda13b07193de8Robert Shih
51014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->setInt32("streamTypeMask", streamTypeMask);
51114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->setInt64("startTimeUs", startTimeUs);
512309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    msg->setInt64("segmentStartTimeUs", segmentStartTimeUs);
513309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    msg->setInt32("startDiscontinuitySeq", startDiscontinuitySeq);
514a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    msg->setInt32("seekMode", seekMode);
51514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->post();
51614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
51714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5185ef659e010e90175eb5282d9642a02f6105189bfChong Zhang/*
5195ef659e010e90175eb5282d9642a02f6105189bfChong Zhang * pauseAsync
5205ef659e010e90175eb5282d9642a02f6105189bfChong Zhang *
5215ef659e010e90175eb5282d9642a02f6105189bfChong Zhang * threshold: 0.0f - pause after current fetch block (default 47Kbytes)
5225ef659e010e90175eb5282d9642a02f6105189bfChong Zhang *           -1.0f - pause after finishing current segment
5235ef659e010e90175eb5282d9642a02f6105189bfChong Zhang *        0.0~1.0f - pause if remaining of current segment exceeds threshold
5245ef659e010e90175eb5282d9642a02f6105189bfChong Zhang */
5255abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid PlaylistFetcher::pauseAsync(
5265abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        float thresholdRatio, bool disconnect) {
5275abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    setStoppingThreshold(thresholdRatio, disconnect);
5285abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
5291d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar    (new AMessage(kWhatPause, this))->post();
53014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
53114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
532309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihvoid PlaylistFetcher::stopAsync(bool clear) {
5335abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    setStoppingThreshold(0.0f, true /* disconncect */);
534c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
5351d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar    sp<AMessage> msg = new AMessage(kWhatStop, this);
536309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    msg->setInt32("clear", clear);
5375ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih    msg->post();
53814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
53914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5401543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shihvoid PlaylistFetcher::resumeUntilAsync(const sp<AMessage> &params) {
54125f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang    FLOGV("resumeUntilAsync: params=%s", params->debugString().c_str());
54225f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
5431d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar    AMessage* msg = new AMessage(kWhatResumeUntil, this);
5441543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    msg->setMessage("params", params);
5451543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    msg->post();
5461543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih}
5471543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
5485abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhangvoid PlaylistFetcher::fetchPlaylistAsync() {
5495abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    (new AMessage(kWhatFetchPlaylist, this))->post();
5505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang}
5515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
55214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::onMessageReceived(const sp<AMessage> &msg) {
55314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    switch (msg->what()) {
55414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case kWhatStart:
55514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
55614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            status_t err = onStart(msg);
55714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
55814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            sp<AMessage> notify = mNotify->dup();
55914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->setInt32("what", kWhatStarted);
56014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->setInt32("err", err);
56114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->post();
56214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
56314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
56414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
56514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case kWhatPause:
56614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
56714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            onPause();
56814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
56914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            sp<AMessage> notify = mNotify->dup();
57014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->setInt32("what", kWhatPaused);
571a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            notify->setInt32("seekMode",
572a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    mDownloadState->hasSavedState()
573a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    ? LiveSession::kSeekModeNextSample
574a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    : LiveSession::kSeekModeNextSegment);
57514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->post();
57614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
57714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
57814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
57914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case kWhatStop:
58014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
5815ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih            onStop(msg);
58214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
58314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            sp<AMessage> notify = mNotify->dup();
58414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->setInt32("what", kWhatStopped);
58514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            notify->post();
58614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
58714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
58814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5895abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        case kWhatFetchPlaylist:
5905abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        {
5915abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            bool unchanged;
5925abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            sp<M3UParser> playlist = mHTTPDownloader->fetchPlaylist(
5935abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                    mURI.c_str(), NULL /* curPlaylistHash */, &unchanged);
5945abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
5955abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            sp<AMessage> notify = mNotify->dup();
5965abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            notify->setInt32("what", kWhatPlaylistFetched);
5975abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            notify->setObject("playlist", playlist);
5985abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            notify->post();
5995abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            break;
6005abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
6015abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
60214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case kWhatMonitorQueue:
6031543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        case kWhatDownloadNext:
60414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
60514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            int32_t generation;
60614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            CHECK(msg->findInt32("generation", &generation));
60714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
60814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (generation != mMonitorQueueGeneration) {
60914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                // Stale event
61014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                break;
61114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
61214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6131543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih            if (msg->what() == kWhatMonitorQueue) {
6141543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih                onMonitorQueue();
6151543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih            } else {
6161543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih                onDownloadNext();
6171543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih            }
6181543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih            break;
6191543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        }
6201543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
6211543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        case kWhatResumeUntil:
6221543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        {
6231543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih            onResumeUntil(msg);
62414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
62514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
62614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
62714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        default:
62814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            TRESPASS();
62914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
63014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
63114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
63214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t PlaylistFetcher::onStart(const sp<AMessage> &msg) {
63314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mPacketSources.clear();
634c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mStopParams.clear();
635c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mStartTimeUsNotify = mNotify->dup();
636c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mStartTimeUsNotify->setInt32("what", kWhatStartedAt);
637a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mStartTimeUsNotify->setString("uri", mURI);
63814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
63914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint32_t streamTypeMask;
64014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK(msg->findInt32("streamTypeMask", (int32_t *)&streamTypeMask));
64114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
64214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t startTimeUs;
643309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int64_t segmentStartTimeUs;
644309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t startDiscontinuitySeq;
645a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int32_t seekMode;
64614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK(msg->findInt64("startTimeUs", &startTimeUs));
647309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    CHECK(msg->findInt64("segmentStartTimeUs", &segmentStartTimeUs));
648309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    CHECK(msg->findInt32("startDiscontinuitySeq", &startDiscontinuitySeq));
649a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    CHECK(msg->findInt32("seekMode", &seekMode));
65014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
65114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (streamTypeMask & LiveSession::STREAMTYPE_AUDIO) {
65214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        void *ptr;
65314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(msg->findPointer("audioSource", &ptr));
65414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
65514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mPacketSources.add(
65614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                LiveSession::STREAMTYPE_AUDIO,
65714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                static_cast<AnotherPacketSource *>(ptr));
65814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
65914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
66014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (streamTypeMask & LiveSession::STREAMTYPE_VIDEO) {
66114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        void *ptr;
66214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(msg->findPointer("videoSource", &ptr));
66314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
66414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mPacketSources.add(
66514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                LiveSession::STREAMTYPE_VIDEO,
66614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                static_cast<AnotherPacketSource *>(ptr));
66714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
66814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
66914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (streamTypeMask & LiveSession::STREAMTYPE_SUBTITLES) {
67014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        void *ptr;
67114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(msg->findPointer("subtitleSource", &ptr));
67214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
67314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mPacketSources.add(
67414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                LiveSession::STREAMTYPE_SUBTITLES,
67514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                static_cast<AnotherPacketSource *>(ptr));
67614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
67714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6780852843d304006e3ab333081fddda13b07193de8Robert Shih    void *ptr;
6790852843d304006e3ab333081fddda13b07193de8Robert Shih    // metadataSource is not part of streamTypeMask
6800852843d304006e3ab333081fddda13b07193de8Robert Shih    if ((streamTypeMask & (LiveSession::STREAMTYPE_AUDIO | LiveSession::STREAMTYPE_VIDEO))
6810852843d304006e3ab333081fddda13b07193de8Robert Shih            && msg->findPointer("metadataSource", &ptr)) {
6820852843d304006e3ab333081fddda13b07193de8Robert Shih        mPacketSources.add(
6830852843d304006e3ab333081fddda13b07193de8Robert Shih                LiveSession::STREAMTYPE_METADATA,
6840852843d304006e3ab333081fddda13b07193de8Robert Shih                static_cast<AnotherPacketSource *>(ptr));
6850852843d304006e3ab333081fddda13b07193de8Robert Shih    }
6860852843d304006e3ab333081fddda13b07193de8Robert Shih
68714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mStreamTypeMask = streamTypeMask;
688309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
689309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    mSegmentStartTimeUs = segmentStartTimeUs;
6907c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
6917c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    if (startDiscontinuitySeq >= 0) {
6927c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mDiscontinuitySeq = startDiscontinuitySeq;
6937c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    }
69414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
695c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
696a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mSeekMode = (LiveSession::SeekMode) seekMode;
697c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
6987c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    if (startTimeUs >= 0 || mSeekMode == LiveSession::kSeekModeNextSample) {
6997c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mStartup = true;
7007c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mIDRFound = false;
7017c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mVideoBuffer->clear();
7027c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    }
7037c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
7040f9a3cf9962b6859cfee9d4bf4676b5aafca79cbRobert Shih    if (startTimeUs >= 0) {
7050f9a3cf9962b6859cfee9d4bf4676b5aafca79cbRobert Shih        mStartTimeUs = startTimeUs;
706c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        mFirstPTSValid = false;
70714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mSeqNumber = -1;
708c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        mTimeChangeSignaled = false;
709a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        mDownloadState->resetState();
7101543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    }
7111543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
71214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    postMonitorQueue();
71314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
71414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
71514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
71614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
71714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::onPause() {
71814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    cancelMonitorQueue();
719c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mLastDiscontinuitySeq = mDiscontinuitySeq;
720c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
7215abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    resetStoppingThreshold(false /* disconnect */);
7221543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih}
7231543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
7245ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shihvoid PlaylistFetcher::onStop(const sp<AMessage> &msg) {
7251543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    cancelMonitorQueue();
72614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
727309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t clear;
728309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    CHECK(msg->findInt32("clear", &clear));
729309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (clear) {
7305ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih        for (size_t i = 0; i < mPacketSources.size(); i++) {
7315ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
7325ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih            packetSource->clear();
7335ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih        }
7345ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih    }
7355ce50c1931e1e3d8f113394bbe2c9f99354f4c5fRobert Shih
736a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mDownloadState->resetState();
73714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mPacketSources.clear();
73814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mStreamTypeMask = 0;
739c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
7405abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    resetStoppingThreshold(true /* disconnect */);
74114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
74214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
7431543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih// Resume until we have reached the boundary timestamps listed in `msg`; when
7441543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih// the remaining time is too short (within a resume threshold) stop immediately
7451543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih// instead.
7461543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shihstatus_t PlaylistFetcher::onResumeUntil(const sp<AMessage> &msg) {
7471543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    sp<AMessage> params;
7481543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    CHECK(msg->findMessage("params", &params));
7491543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
7501543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    mStopParams = params;
751964adb17885185808398507d2de88665fe193ee2Chong Zhang    onDownloadNext();
7521543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
7531543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    return OK;
75414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
75514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
7567c8708046117e03c0d38006bdd9685139df3ac6bChong Zhangvoid PlaylistFetcher::notifyStopReached() {
7577c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    sp<AMessage> notify = mNotify->dup();
7587c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    notify->setInt32("what", kWhatStopReached);
7597c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    notify->post();
7607c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang}
7617c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
76214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::notifyError(status_t err) {
76314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AMessage> notify = mNotify->dup();
76414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    notify->setInt32("what", kWhatError);
76514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    notify->setInt32("err", err);
76614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    notify->post();
76714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
76814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
76914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::queueDiscontinuity(
77014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ATSParser::DiscontinuityType type, const sp<AMessage> &extra) {
77114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (size_t i = 0; i < mPacketSources.size(); ++i) {
772632740c58119a132ce19f6d498e39c5c3773971aChong Zhang        // do not discard buffer upon #EXT-X-DISCONTINUITY tag
773632740c58119a132ce19f6d498e39c5c3773971aChong Zhang        // (seek will discard buffer by abandoning old fetchers)
774632740c58119a132ce19f6d498e39c5c3773971aChong Zhang        mPacketSources.valueAt(i)->queueDiscontinuity(
775632740c58119a132ce19f6d498e39c5c3773971aChong Zhang                type, extra, false /* discard */);
77614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
77714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
77814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
77914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::onMonitorQueue() {
7807c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    // in the middle of an unfinished download, delay
7817c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    // playlist refresh as it'll change seq numbers
7827c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    if (!mDownloadState->hasSavedState()) {
7837c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        refreshPlaylist();
7847c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    }
785e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar
786e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    int64_t targetDurationUs = kMinBufferedDurationUs;
787e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (mPlaylist != NULL) {
788978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        targetDurationUs = mPlaylist->getTargetDuration();
789e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    }
790e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar
791e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    int64_t bufferedDurationUs = 0ll;
792538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang    status_t finalResult = OK;
79314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
79414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        sp<AnotherPacketSource> packetSource =
79514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
79614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
797e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar        bufferedDurationUs =
798dcb89b3b505522efde173c105a851c412f947178Chong Zhang                packetSource->getBufferedDurationUs(&finalResult);
79914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else {
800538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // Use min stream duration, but ignore streams that never have any packet
801538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // enqueued to prevent us from waiting on a non-existent stream;
802538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // when we cannot make out from the manifest what streams are included in
803538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // a playlist we might assume extra streams.
804538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        bufferedDurationUs = -1ll;
80514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        for (size_t i = 0; i < mPacketSources.size(); ++i) {
806538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang            if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0
807538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang                    || mPacketSources[i]->getLatestEnqueuedMeta() == NULL) {
80814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                continue;
80914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
81014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
811e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar            int64_t bufferedStreamDurationUs =
81214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult);
81325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
81425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            FSLOGV(mPacketSources.keyAt(i), "buffered %lld", (long long)bufferedStreamDurationUs);
81525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
816538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang            if (bufferedDurationUs == -1ll
817538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang                 || bufferedStreamDurationUs < bufferedDurationUs) {
818e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                bufferedDurationUs = bufferedStreamDurationUs;
81914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
82014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
821538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        if (bufferedDurationUs == -1ll) {
822538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang            bufferedDurationUs = 0ll;
823538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        }
82414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
82514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
826538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang    if (finalResult == OK && bufferedDurationUs < kMinBufferedDurationUs) {
82725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("monitoring, buffered=%lld < %lld",
82825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                (long long)bufferedDurationUs, (long long)kMinBufferedDurationUs);
82925f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
8301543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        // delay the next download slightly; hopefully this gives other concurrent fetchers
8311543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        // a better chance to run.
8321543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        // onDownloadNext();
8331d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar        sp<AMessage> msg = new AMessage(kWhatDownloadNext, this);
8341543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        msg->setInt32("generation", mMonitorQueueGeneration);
8351543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        msg->post(1000l);
83614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else {
837538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // We'd like to maintain buffering above durationToBufferUs, so try
838538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // again when buffer just about to go below durationToBufferUs
839538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        // (or after targetDurationUs / 2, whichever is smaller).
840538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        int64_t delayUs = bufferedDurationUs - kMinBufferedDurationUs + 1000000ll;
841538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        if (delayUs > targetDurationUs / 2) {
842538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang            delayUs = targetDurationUs / 2;
843538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        }
84425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
84525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("pausing for %lld, buffered=%lld > %lld",
84625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                (long long)delayUs,
84725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                (long long)bufferedDurationUs,
84825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                (long long)kMinBufferedDurationUs);
84925f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
850538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        postMonitorQueue(delayUs);
85114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
85214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
85314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
854e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnarstatus_t PlaylistFetcher::refreshPlaylist() {
855e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    if (delayUsToRefreshPlaylist() <= 0) {
85614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        bool unchanged;
8575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        sp<M3UParser> playlist = mHTTPDownloader->fetchPlaylist(
85814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mURI.c_str(), mPlaylistHash, &unchanged);
85914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
86014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (playlist == NULL) {
86114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (unchanged) {
86214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                // We succeeded in fetching the playlist, but it was
86314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                // unchanged from the last time we tried.
86414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
86514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) {
86614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    mRefreshState = (RefreshState)(mRefreshState + 1);
86714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                }
86814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
869daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                ALOGE("failed to load playlist at url '%s'", uriDebugString(mURI).c_str());
870e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                return ERROR_IO;
87114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
87214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else {
87314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
87414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mPlaylist = playlist;
87514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
87614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
87714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                updateDuration();
87814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
8797c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // Notify LiveSession to use target-duration based buffering level
8807c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // for up/down switch. Default LiveSession::kUpSwitchMark may not
8817c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // be reachable for live streams, as our max buffering amount is
8827c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // limited to 3 segments.
8837c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            if (!mPlaylist->isComplete()) {
8847c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                updateTargetDuration();
8857c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            }
886978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            mPlaylistTimeUs = ALooper::GetNowUs();
88714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
88814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
88914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
89014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
891e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar    return OK;
892e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar}
893e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar
89443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih// static
89543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shihbool PlaylistFetcher::bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer) {
89643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    return buffer->size() > 0 && buffer->data()[0] == 0x47;
89743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih}
89843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
8997c8708046117e03c0d38006bdd9685139df3ac6bChong Zhangbool PlaylistFetcher::shouldPauseDownload() {
900a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
901a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        // doesn't apply to subtitles
902a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return false;
903a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
904a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
905a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    // Calculate threshold to abort current download
9065abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    float thresholdRatio = getStoppingThreshold();
907a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
9085abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    if (thresholdRatio < 0.0f) {
909a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        // never abort
910a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return false;
9115abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    } else if (thresholdRatio == 0.0f) {
912a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        // immediately abort
913a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return true;
914a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
915a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
916a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    // now we have a positive thresholdUs, abort if remaining
917a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    // portion to download is over that threshold.
918a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (mSegmentFirstPTS < 0) {
919a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        // this means we haven't even find the first access unit,
920a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        // abort now as we must be very far away from the end.
921a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return true;
922a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
923a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int64_t lastEnqueueUs = mSegmentFirstPTS;
924a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    for (size_t i = 0; i < mPacketSources.size(); ++i) {
925a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) {
926a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            continue;
927a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        }
928a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<AMessage> meta = mPacketSources[i]->getLatestEnqueuedMeta();
929a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t type;
930a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        if (meta == NULL || meta->findInt32("discontinuity", &type)) {
931a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            continue;
932a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        }
933a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int64_t tmpUs;
934a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        CHECK(meta->findInt64("timeUs", &tmpUs));
935a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        if (tmpUs > lastEnqueueUs) {
936a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            lastEnqueueUs = tmpUs;
937a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        }
938a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
939a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    lastEnqueueUs -= mSegmentFirstPTS;
94025f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
9415abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    int64_t targetDurationUs = mPlaylist->getTargetDuration();
9425abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang    int64_t thresholdUs = thresholdRatio * targetDurationUs;
9435abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
94425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang    FLOGV("%spausing now, thresholdUs %lld, remaining %lld",
94525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            targetDurationUs - lastEnqueueUs > thresholdUs ? "" : "not ",
94625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            (long long)thresholdUs,
94725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            (long long)(targetDurationUs - lastEnqueueUs));
94825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang
949a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (targetDurationUs - lastEnqueueUs > thresholdUs) {
950a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        return true;
951a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
952a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    return false;
953a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
954a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
955a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangbool PlaylistFetcher::initDownloadState(
956a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        AString &uri,
957a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        sp<AMessage> &itemMeta,
958a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &firstSeqNumberInPlaylist,
959a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int32_t &lastSeqNumberInPlaylist) {
960daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih    status_t err = refreshPlaylist();
961a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    firstSeqNumberInPlaylist = 0;
962a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    lastSeqNumberInPlaylist = 0;
963632740c58119a132ce19f6d498e39c5c3773971aChong Zhang    bool discontinuity = false;
96414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
965daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih    if (mPlaylist != NULL) {
966978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mPlaylist->getSeqNumberRange(
967978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                &firstSeqNumberInPlaylist, &lastSeqNumberInPlaylist);
96814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
969daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih        if (mDiscontinuitySeq < 0) {
970daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            mDiscontinuitySeq = mPlaylist->getDiscontinuitySeq();
971daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih        }
972309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
973309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
974a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    mSegmentFirstPTS = -1ll;
975a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
976daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih    if (mPlaylist != NULL && mSeqNumber < 0) {
97714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_GE(mStartTimeUs, 0ll);
97814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
979309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        if (mSegmentStartTimeUs < 0) {
980309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) {
981309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                // If this is a live session, start 3 segments from the end on connect
982309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                mSeqNumber = lastSeqNumberInPlaylist - 3;
98339f5874c4040bec6fdbf0c0912daffcb10010df8Robert Shih                if (mSeqNumber < firstSeqNumberInPlaylist) {
98439f5874c4040bec6fdbf0c0912daffcb10010df8Robert Shih                    mSeqNumber = firstSeqNumberInPlaylist;
98539f5874c4040bec6fdbf0c0912daffcb10010df8Robert Shih                }
986309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            } else {
987afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih                // When seeking mSegmentStartTimeUs is unavailable (< 0), we
988afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih                // use mStartTimeUs (client supplied timestamp) to determine both start segment
989afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih                // and relative position inside a segment
990309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                mSeqNumber = getSeqNumberForTime(mStartTimeUs);
991309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                mStartTimeUs -= getSegmentStartTimeUs(mSeqNumber);
992309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
993309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            mStartTimeUsRelative = true;
99425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            FLOGV("Initial sequence number for time %lld is %d from (%d .. %d)",
99525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    (long long)mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
996e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    lastSeqNumberInPlaylist);
99714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else {
998afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih            // When adapting or track switching, mSegmentStartTimeUs (relative
999afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih            // to media time 0) is used to determine the start segment; mStartTimeUs (absolute
1000afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih            // timestamps coming from the media container) is used to determine the position
1001afcc4fcbb3a094ec2221d6e523772e76894d1f00Robert Shih            // inside a segments.
1002d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES
1003d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                    && mSeekMode != LiveSession::kSeekModeNextSample) {
1004309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                // avoid double fetch/decode
1005978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                // Use (mSegmentStartTimeUs + 1/2 * targetDurationUs) to search
1006978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                // for the starting segment in new variant.
1007978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                // If the two variants' segments are aligned, this gives the
1008978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                // next segment. If they're not aligned, this gives the segment
1009978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                // that overlaps no more than 1/2 * targetDurationUs.
1010978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mSeqNumber = getSeqNumberForTime(mSegmentStartTimeUs
1011978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                        + mPlaylist->getTargetDuration() / 2);
1012978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            } else {
1013978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mSeqNumber = getSeqNumberForTime(mSegmentStartTimeUs);
1014309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
1015309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            ssize_t minSeq = getSeqNumberForDiscontinuity(mDiscontinuitySeq);
1016309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (mSeqNumber < minSeq) {
1017309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                mSeqNumber = minSeq;
1018309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
1019309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
102014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (mSeqNumber < firstSeqNumberInPlaylist) {
102114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mSeqNumber = firstSeqNumberInPlaylist;
102214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
1023309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1024309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (mSeqNumber > lastSeqNumberInPlaylist) {
1025309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                mSeqNumber = lastSeqNumberInPlaylist;
1026309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
102725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            FLOGV("Initial sequence number is %d from (%d .. %d)",
1028e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    mSeqNumber, firstSeqNumberInPlaylist,
1029e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    lastSeqNumberInPlaylist);
103014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
103114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
103214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1033daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih    // if mPlaylist is NULL then err must be non-OK; but the other way around might not be true
103414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (mSeqNumber < firstSeqNumberInPlaylist
1035daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            || mSeqNumber > lastSeqNumberInPlaylist
1036daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            || err != OK) {
1037daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih        if ((err != OK || !mPlaylist->isComplete()) && mNumRetries < kMaxNumRetries) {
103814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ++mNumRetries;
103914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1040daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            if (mSeqNumber > lastSeqNumberInPlaylist || err != OK) {
1041daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                // make sure we reach this retry logic on refresh failures
1042daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                // by adding an err != OK clause to all enclosing if's.
1043daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih
1044e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                // refresh in increasing fraction (1/2, 1/3, ...) of the
1045e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                // playlist's target duration or 3 seconds, whichever is less
1046daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                int64_t delayUs = kMaxMonitorDelayUs;
1047978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                if (mPlaylist != NULL) {
1048978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                    delayUs = mPlaylist->size() * mPlaylist->getTargetDuration()
1049978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                            / (1 + mNumRetries);
1050daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                }
1051e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                if (delayUs > kMaxMonitorDelayUs) {
1052e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    delayUs = kMaxMonitorDelayUs;
1053e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                }
105425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                FLOGV("sequence number high: %d from (%d .. %d), "
105525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                      "monitor in %lld (retry=%d)",
1056e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                        mSeqNumber, firstSeqNumberInPlaylist,
105725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                        lastSeqNumberInPlaylist, (long long)delayUs, mNumRetries);
1058e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                postMonitorQueue(delayUs);
1059a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                return false;
106014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
106114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1062daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            if (err != OK) {
1063daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih                notifyError(err);
1064a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                return false;
1065daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            }
1066daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih
1067daad5b2f4a6bb46a7911661e398278d6a80d7093Robert Shih            // we've missed the boat, let's start 3 segments prior to the latest sequence
106814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            // number available and signal a discontinuity.
106914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1070e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar            ALOGI("We've missed the boat, restarting playback."
1071e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                  "  mStartup=%d, was  looking for %d in %d-%d",
1072e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    mStartup, mSeqNumber, firstSeqNumberInPlaylist,
1073e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                    lastSeqNumberInPlaylist);
107495697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih            if (mStopParams != NULL) {
107595697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih                // we should have kept on fetching until we hit the boundaries in mStopParams,
107695697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih                // but since the segments we are supposed to fetch have already rolled off
107795697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih                // the playlist, i.e. we have already missed the boat, we inevitably have to
107895697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih                // skip.
10797c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                notifyStopReached();
1080a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                return false;
108195697aecd644ffcfbe7fe828e9e42bfab71b75a5Robert Shih            }
1082e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar            mSeqNumber = lastSeqNumberInPlaylist - 3;
1083e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar            if (mSeqNumber < firstSeqNumberInPlaylist) {
1084e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar                mSeqNumber = firstSeqNumberInPlaylist;
1085e175e5ec1636fc638465187f3d5c6166d92388edLajos Molnar            }
1086632740c58119a132ce19f6d498e39c5c3773971aChong Zhang            discontinuity = true;
108714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
108814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            // fall through
108914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else {
10907c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            if (mPlaylist != NULL) {
10917c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                ALOGE("Cannot find sequence number %d in playlist "
10927c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                     "(contains %d - %d)",
10937c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                     mSeqNumber, firstSeqNumberInPlaylist,
10947c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                      firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1);
10957c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
1096aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                if (mTSParser != NULL) {
1097aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    mTSParser->signalEOS(ERROR_END_OF_STREAM);
1098aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    // Use an empty buffer; we don't have any new data, just want to extract
1099aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    // potential new access units after flush.  Reset mSeqNumber to
1100aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    // lastSeqNumberInPlaylist such that we set the correct access unit
1101aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    // properties in extractAndQueueAccessUnitsFromTs.
1102aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    sp<ABuffer> buffer = new ABuffer(0);
1103aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    mSeqNumber = lastSeqNumberInPlaylist;
1104aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                    extractAndQueueAccessUnitsFromTs(buffer);
1105aabbdc7401ae24a4199f12a283985deb648673c0Robert Shih                }
11067c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                notifyError(ERROR_END_OF_STREAM);
11077c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            } else {
11087c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                // It's possible that we were never able to download the playlist.
11097c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                // In this case we should notify error, instead of EOS, as EOS during
11107c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                // prepare means we succeeded in downloading everything.
11117c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                ALOGE("Failed to download playlist!");
11127c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                notifyError(ERROR_IO);
11137c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            }
111414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1115a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            return false;
111614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
111714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
111814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
111914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mNumRetries = 0;
112014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
112114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK(mPlaylist->itemAt(
112214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mSeqNumber - firstSeqNumberInPlaylist,
112314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                &uri,
112414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                &itemMeta));
112514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1126c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    CHECK(itemMeta->findInt32("discontinuity-sequence", &mDiscontinuitySeq));
1127c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
112814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t val;
112914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
1130c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        discontinuity = true;
1131c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    } else if (mLastDiscontinuitySeq >= 0
1132c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            && mDiscontinuitySeq != mLastDiscontinuitySeq) {
1133c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // Seek jumped to a new discontinuity sequence. We need to signal
1134c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // a format change to decoder. Decoder needs to shutdown and be
1135c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // created again if seamless format change is unsupported.
113625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("saw discontinuity: mStartup %d, mLastDiscontinuitySeq %d, "
1137c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                "mDiscontinuitySeq %d, mStartTimeUs %lld",
113825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                mStartup, mLastDiscontinuitySeq, mDiscontinuitySeq, (long long)mStartTimeUs);
1139632740c58119a132ce19f6d498e39c5c3773971aChong Zhang        discontinuity = true;
114014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
1141c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    mLastDiscontinuitySeq = -1;
114214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
114343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    // decrypt a junk buffer to prefetch key; since a session uses only one http connection,
114443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    // this avoids interleaved connections to the key and segment file.
114543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    {
114643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        sp<ABuffer> junk = new ABuffer(16);
114743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        junk->setRange(0, 16);
114843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk,
114943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                true /* first */);
11505abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (err == ERROR_NOT_CONNECTED) {
11515abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return false;
11525abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        } else if (err != OK) {
115343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            notifyError(err);
1154a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            return false;
115543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
115614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
115714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1158c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    if ((mStartup && !mTimeChangeSignaled) || discontinuity) {
1159c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // We need to signal a time discontinuity to ATSParser on the
1160c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // first segment after start, or on a discontinuity segment.
1161c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // Setting mNextPTSTimeUs informs extractAndQueueAccessUnitsXX()
1162c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // to send the time discontinuity.
1163c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
1164c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // If this was a live event this made no sense since
1165c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // we don't have access to all the segment before the current
1166c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // one.
1167c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber);
1168c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        }
1169c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
1170c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // Setting mTimeChangeSignaled to true, so that if start time
1171c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // searching goes into 2nd segment (without a discontinuity),
1172c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // we don't reset time again. It causes corruption when pending
1173c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // data in ATSParser is cleared.
1174c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        mTimeChangeSignaled = true;
1175c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    }
1176c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
1177c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    if (discontinuity) {
1178c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        ALOGI("queueing discontinuity (explicit=%d)", discontinuity);
1179c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
1180c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // Signal a format discontinuity to ATSParser to clear partial data
1181c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        // from previous streams. Not doing this causes bitstream corruption.
11827c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        if (mTSParser != NULL) {
1183a722375a32e9a0febc3770513647dc32bf88ccc0Robert Shih            mTSParser.clear();
11847c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        }
1185c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
1186c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        queueDiscontinuity(
1187978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                ATSParser::DISCONTINUITY_FORMAT_ONLY,
1188c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                NULL /* extra */);
1189c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
1190c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        if (mStartup && mStartTimeUsRelative && mFirstPTSValid) {
1191c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // This means we guessed mStartTimeUs to be in the previous
1192c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // segment (likely very close to the end), but either video or
1193c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // audio has not found start by the end of that segment.
1194c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            //
1195c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // If this new segment is not a discontinuity, keep searching.
1196c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            //
1197c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // If this new segment even got a discontinuity marker, just
1198c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            // set mStartTimeUs=0, and take all samples from now on.
1199c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            mStartTimeUs = 0;
1200c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            mFirstPTSValid = false;
1201978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            mIDRFound = false;
1202978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            mVideoBuffer->clear();
1203c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        }
1204c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    }
1205c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
120625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang    FLOGV("fetching segment %d from (%d .. %d)",
1207a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist);
1208a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    return true;
1209a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang}
1210a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
1211a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhangvoid PlaylistFetcher::onDownloadNext() {
1212a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    AString uri;
1213a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<AMessage> itemMeta;
1214a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<ABuffer> buffer;
1215a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    sp<ABuffer> tsBuffer;
1216a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int32_t firstSeqNumberInPlaylist = 0;
1217a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int32_t lastSeqNumberInPlaylist = 0;
1218a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    bool connectHTTP = true;
1219a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
1220a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (mDownloadState->hasSavedState()) {
1221a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        mDownloadState->restoreState(
1222a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                uri,
1223a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                itemMeta,
1224a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                buffer,
1225a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                tsBuffer,
1226a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                firstSeqNumberInPlaylist,
1227a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                lastSeqNumberInPlaylist);
1228a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        connectHTTP = false;
122925f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("resuming: '%s'", uri.c_str());
1230a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    } else {
1231a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        if (!initDownloadState(
1232a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                uri,
1233a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                itemMeta,
1234a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                firstSeqNumberInPlaylist,
1235a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                lastSeqNumberInPlaylist)) {
1236a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            return;
1237a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        }
123825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("fetching: '%s'", uri.c_str());
1239a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
1240a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
1241a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    int64_t range_offset, range_length;
1242a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    if (!itemMeta->findInt64("range-offset", &range_offset)
1243a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang            || !itemMeta->findInt64("range-length", &range_length)) {
1244a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        range_offset = 0;
1245a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        range_length = -1;
1246a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    }
1247a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
124843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    // block-wise download
12497c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    bool shouldPause = false;
125043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    ssize_t bytesRead;
125143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    do {
1252a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        int64_t startUs = ALooper::GetNowUs();
12535abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        bytesRead = mHTTPDownloader->fetchBlock(
1254a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize,
12555abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang                NULL /* actualURL */, connectHTTP);
12565abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        int64_t delayUs = ALooper::GetNowUs() - startUs;
12575abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang
12585abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (bytesRead == ERROR_NOT_CONNECTED) {
12595abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return;
12605abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
12615abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        if (bytesRead < 0) {
12625abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            status_t err = bytesRead;
12635abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
12645abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            notifyError(err);
12655abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang            return;
12665abbd3dcbb0bb32a3d4b90dddbcf90458967eb6fChong Zhang        }
126714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1268d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        // add sample for bandwidth estimation, excluding samples from subtitles (as
1269d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        // its too small), or during startup/resumeUntil (when we could have more than
1270d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        // one connection open which affects bandwidth)
1271d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if (!mStartup && mStopParams == NULL && bytesRead > 0
1272538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang                && (mStreamTypeMask
1273538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang                        & (LiveSession::STREAMTYPE_AUDIO
1274538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang                        | LiveSession::STREAMTYPE_VIDEO))) {
1275538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang            mSession->addBandwidthMeasurement(bytesRead, delayUs);
127625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            if (delayUs > 2000000ll) {
127725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                FLOGV("bytesRead %zd took %.2f seconds - abnormal bandwidth dip",
127825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                        bytesRead, (double)delayUs / 1.0e6);
127925f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            }
1280538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang        }
1281538b6d22a3578c0201d48f8548289aa254d81484Chong Zhang
1282a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        connectHTTP = false;
1283a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
128443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        CHECK(buffer != NULL);
128514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
128643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        size_t size = buffer->size();
128743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // Set decryption range.
128843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        buffer->setRange(size - bytesRead, bytesRead);
128943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer,
129043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                buffer->offset() == 0 /* first */);
129143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // Unset decryption range.
129243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        buffer->setRange(0, size);
129314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
129443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if (err != OK) {
129543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            ALOGE("decryptBuffer failed w/ error %d", err);
129614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
129743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            notifyError(err);
129843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return;
129914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
130014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1301a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang        bool startUp = mStartup; // save current start up state
1302a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang
130343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        err = OK;
130443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if (bufferStartsWithTsSyncByte(buffer)) {
130543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            // Incremental extraction is only supported for MPEG2 transport streams.
130643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            if (tsBuffer == NULL) {
130743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
130843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                tsBuffer->setRange(0, 0);
130943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            } else if (tsBuffer->capacity() != buffer->capacity()) {
131043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                size_t tsOff = tsBuffer->offset(), tsSize = tsBuffer->size();
131143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
131243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                tsBuffer->setRange(tsOff, tsSize);
131343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            }
131443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            tsBuffer->setRange(tsBuffer->offset(), tsBuffer->size() + bytesRead);
131543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            err = extractAndQueueAccessUnitsFromTs(tsBuffer);
131643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
131743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
131843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if (err == -EAGAIN) {
1319f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih            // starting sequence number too low/high
13205cda1b30b8c3900f8405f9bf2fab2df6e38ea95fRobert Shih            mTSParser.clear();
1321dae1e733f7cd4abaa14791657fa0a1b0e44a27b6Robert Shih            for (size_t i = 0; i < mPacketSources.size(); i++) {
1322dae1e733f7cd4abaa14791657fa0a1b0e44a27b6Robert Shih                sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
1323dae1e733f7cd4abaa14791657fa0a1b0e44a27b6Robert Shih                packetSource->clear();
1324dae1e733f7cd4abaa14791657fa0a1b0e44a27b6Robert Shih            }
132543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            postMonitorQueue();
132643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return;
1327309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        } else if (err == ERROR_OUT_OF_RANGE) {
132843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            // reached stopping point
13297c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            notifyStopReached();
133043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return;
1331309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        } else if (err != OK) {
133243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            notifyError(err);
133343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return;
13347c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        }
13357c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        // If we're switching, post start notification
13367c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        // this should only be posted when the last chunk is full processed by TSParser
13377c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        if (mSeekMode != LiveSession::kSeekModeExactPosition && startUp != mStartup) {
13387c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            CHECK(mStartTimeUsNotify != NULL);
13397c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            mStartTimeUsNotify->post();
13407c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            mStartTimeUsNotify.clear();
13417c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            shouldPause = true;
13427c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        }
13437c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        if (shouldPause || shouldPauseDownload()) {
13447c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // save state and return if this is not the last chunk,
13457c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            // leaving the fetcher in paused state.
13467c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            if (bytesRead != 0) {
13477c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                mDownloadState->saveState(
13487c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        uri,
13497c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        itemMeta,
13507c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        buffer,
13517c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        tsBuffer,
13527c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        firstSeqNumberInPlaylist,
13537c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                        lastSeqNumberInPlaylist);
13547c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang                return;
13557c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            }
13567c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            shouldPause = true;
135743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
1358a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang    } while (bytesRead != 0);
135943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
136043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (bufferStartsWithTsSyncByte(buffer)) {
1361bf20727f0aaf609bc3b495b07b45822b137d21baRobert Shih        // If we don't see a stream in the program table after fetching a full ts segment
1362bf20727f0aaf609bc3b495b07b45822b137d21baRobert Shih        // mark it as nonexistent.
13630852843d304006e3ab333081fddda13b07193de8Robert Shih        ATSParser::SourceType srcTypes[] =
136443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                { ATSParser::VIDEO, ATSParser::AUDIO };
13650852843d304006e3ab333081fddda13b07193de8Robert Shih        LiveSession::StreamType streamTypes[] =
136643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                { LiveSession::STREAMTYPE_VIDEO, LiveSession::STREAMTYPE_AUDIO };
13670852843d304006e3ab333081fddda13b07193de8Robert Shih        const size_t kNumTypes = NELEM(srcTypes);
136843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
136943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        for (size_t i = 0; i < kNumTypes; i++) {
137043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            ATSParser::SourceType srcType = srcTypes[i];
137143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            LiveSession::StreamType streamType = streamTypes[i];
137243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
137343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            sp<AnotherPacketSource> source =
137443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                static_cast<AnotherPacketSource *>(
137543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    mTSParser->getSource(srcType).get());
137643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
1377bf20727f0aaf609bc3b495b07b45822b137d21baRobert Shih            if (!mTSParser->hasSource(srcType)) {
137843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                ALOGW("MPEG2 Transport stream does not contain %s data.",
137943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                      srcType == ATSParser::VIDEO ? "video" : "audio");
138043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
138143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                mStreamTypeMask &= ~streamType;
138243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                mPacketSources.removeItem(streamType);
138343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            }
138443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
138514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
13861543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    }
13871543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
138843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (checkDecryptPadding(buffer) != OK) {
138943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        ALOGE("Incorrect padding bytes after decryption.");
139043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        notifyError(ERROR_MALFORMED);
13911543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        return;
13921543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih    }
13931543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
139443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (tsBuffer != NULL) {
139543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        AString method;
139643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        CHECK(buffer->meta()->findString("cipher-method", &method));
139743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if ((tsBuffer->size() > 0 && method == "NONE")
139843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                || tsBuffer->size() > 16) {
139943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            ALOGE("MPEG2 transport stream is not an even multiple of 188 "
140043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    "bytes in length.");
140143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            notifyError(ERROR_MALFORMED);
140243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return;
140343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
140443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
140543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
140643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    // bulk extract non-ts files
14077c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    bool startUp = mStartup;
140843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (tsBuffer == NULL) {
14097c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        status_t err = extractAndQueueAccessUnits(buffer, itemMeta);
141073d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        if (err == -EAGAIN) {
141173d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            // starting sequence number too low/high
141273d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            postMonitorQueue();
141373d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            return;
141473d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        } else if (err == ERROR_OUT_OF_RANGE) {
141573d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            // reached stopping point
14167c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            notifyStopReached();
14177c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            return;
14187c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        } else if (err != OK) {
14197c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            notifyError(err);
142073d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            return;
142173d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        }
142243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
142343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
14247c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    ++mSeqNumber;
14257c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
14267c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    // if adapting, pause after found the next starting point
14277c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    if (mSeekMode != LiveSession::kSeekModeExactPosition && startUp != mStartup) {
1428d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        CHECK(mStartTimeUsNotify != NULL);
14297c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mStartTimeUsNotify->post();
14307c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        mStartTimeUsNotify.clear();
14317c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        shouldPause = true;
143214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
143314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
14347c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    if (!shouldPause) {
14357c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        postMonitorQueue();
14367c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    }
143714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
143814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1439978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang/*
1440978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang * returns true if we need to adjust mSeqNumber
1441978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang */
1442978449984366946a2e5c9f7cf350746f4306caf8Chong Zhangbool PlaylistFetcher::adjustSeqNumberWithAnchorTime(int64_t anchorTimeUs) {
1443978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int32_t firstSeqNumberInPlaylist = mPlaylist->getFirstSeqNumber();
1444978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1445978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int64_t minDiffUs, maxDiffUs;
1446978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (mSeekMode == LiveSession::kSeekModeNextSample) {
14478a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // if the previous fetcher paused in the middle of a segment, we
14488a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // want to start at a segment that overlaps the last sample
1449978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        minDiffUs = -mPlaylist->getTargetDuration();
1450978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        maxDiffUs = 0ll;
1451978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    } else {
14528a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // if the previous fetcher paused at the end of a segment, ideally
14538a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // we want to start at the segment that's roughly aligned with its
14548a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // next segment, but if the two variants are not well aligned we
14558a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        // adjust the diff to within (-T/2, T/2)
1456978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        minDiffUs = -mPlaylist->getTargetDuration() / 2;
14578a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang        maxDiffUs = mPlaylist->getTargetDuration() / 2;
1458f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih    }
1459f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1460978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int32_t oldSeqNumber = mSeqNumber;
1461978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    ssize_t index = mSeqNumber - firstSeqNumberInPlaylist;
1462f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1463978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    // adjust anchorTimeUs to within (minDiffUs, maxDiffUs) from mStartTimeUs
1464978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int64_t diffUs = anchorTimeUs - mStartTimeUs;
1465978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (diffUs > maxDiffUs) {
1466978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        while (index > 0 && diffUs > maxDiffUs) {
1467978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            --index;
1468978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1469978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            sp<AMessage> itemMeta;
1470978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            CHECK(mPlaylist->itemAt(index, NULL /* uri */, &itemMeta));
1471978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1472978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            int64_t itemDurationUs;
1473978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1474978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1475978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            diffUs -= itemDurationUs;
1476978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1477978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    } else if (diffUs < minDiffUs) {
1478978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        while (index + 1 < (ssize_t) mPlaylist->size()
1479978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                && diffUs < minDiffUs) {
1480978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            ++index;
1481978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1482978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            sp<AMessage> itemMeta;
1483978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            CHECK(mPlaylist->itemAt(index, NULL /* uri */, &itemMeta));
1484978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1485978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            int64_t itemDurationUs;
1486978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
1487f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1488978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            diffUs += itemDurationUs;
1489978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1490f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih    }
1491f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1492978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    mSeqNumber = firstSeqNumberInPlaylist + index;
1493978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1494978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (mSeqNumber != oldSeqNumber) {
1495978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        FLOGV("guessed wrong seg number: diff %lld out of [%lld, %lld]",
1496978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                (long long) anchorTimeUs - mStartTimeUs,
1497978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                (long long) minDiffUs,
1498978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                (long long) maxDiffUs);
1499978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        return true;
1500f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih    }
1501978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    return false;
1502f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih}
1503f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1504309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihint32_t PlaylistFetcher::getSeqNumberForDiscontinuity(size_t discontinuitySeq) const {
1505978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    int32_t firstSeqNumberInPlaylist = mPlaylist->getFirstSeqNumber();
1506309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1507309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    size_t index = 0;
1508309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    while (index < mPlaylist->size()) {
1509309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        sp<AMessage> itemMeta;
1510309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        CHECK(mPlaylist->itemAt( index, NULL /* uri */, &itemMeta));
1511d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        size_t curDiscontinuitySeq;
1512d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        CHECK(itemMeta->findInt32("discontinuity-sequence", (int32_t *)&curDiscontinuitySeq));
1513d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        int32_t seqNumber = firstSeqNumberInPlaylist + index;
1514309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        if (curDiscontinuitySeq == discontinuitySeq) {
1515d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            return seqNumber;
1516d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        } else if (curDiscontinuitySeq > discontinuitySeq) {
1517d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            return seqNumber <= 0 ? 0 : seqNumber - 1;
1518309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        }
1519309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1520309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        ++index;
1521309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1522309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1523309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    return firstSeqNumberInPlaylist + mPlaylist->size();
1524309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih}
1525309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
152614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberint32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const {
152714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    size_t index = 0;
152814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t segmentStartUs = 0;
152914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (index < mPlaylist->size()) {
153014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        sp<AMessage> itemMeta;
153114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(mPlaylist->itemAt(
153214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    index, NULL /* uri */, &itemMeta));
153314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
153414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        int64_t itemDurationUs;
153514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
153614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
153714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (timeUs < segmentStartUs + itemDurationUs) {
153814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
153914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
154014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
154114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        segmentStartUs += itemDurationUs;
154214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ++index;
154314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
154414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
154514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (index >= mPlaylist->size()) {
154614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        index = mPlaylist->size() - 1;
154714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
154814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1549978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    return mPlaylist->getFirstSeqNumber() + index;
155014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
155114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1552309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihconst sp<ABuffer> &PlaylistFetcher::setAccessUnitProperties(
1553309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        const sp<ABuffer> &accessUnit, const sp<AnotherPacketSource> &source, bool discard) {
1554309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    sp<MetaData> format = source->getFormat();
1555309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (format != NULL) {
1556309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        // for simplicity, store a reference to the format in each unit
1557309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        accessUnit->meta()->setObject("format", format);
1558309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1559309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1560309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (discard) {
1561309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        accessUnit->meta()->setInt32("discard", discard);
1562309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1563309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1564309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    accessUnit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq);
1565309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    accessUnit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber));
1566978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    accessUnit->meta()->setInt64("segmentFirstTimeUs", mSegmentFirstPTS);
15677c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    accessUnit->meta()->setInt64("segmentDurationUs", getSegmentDurationUs(mSeqNumber));
1568978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) {
1569978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        accessUnit->meta()->setInt64("playlistTimeUs", mPlaylistTimeUs);
1570978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    }
1571309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    return accessUnit;
1572309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih}
1573309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
15740852843d304006e3ab333081fddda13b07193de8Robert Shihbool PlaylistFetcher::isStartTimeReached(int64_t timeUs) {
15750852843d304006e3ab333081fddda13b07193de8Robert Shih    if (!mFirstPTSValid) {
15760852843d304006e3ab333081fddda13b07193de8Robert Shih        mFirstTimeUs = timeUs;
15770852843d304006e3ab333081fddda13b07193de8Robert Shih        mFirstPTSValid = true;
15780852843d304006e3ab333081fddda13b07193de8Robert Shih    }
15790852843d304006e3ab333081fddda13b07193de8Robert Shih    bool startTimeReached = true;
15800852843d304006e3ab333081fddda13b07193de8Robert Shih    if (mStartTimeUsRelative) {
15810852843d304006e3ab333081fddda13b07193de8Robert Shih        FLOGV("startTimeUsRelative, timeUs (%lld) - %lld = %lld",
15820852843d304006e3ab333081fddda13b07193de8Robert Shih                (long long)timeUs,
15830852843d304006e3ab333081fddda13b07193de8Robert Shih                (long long)mFirstTimeUs,
15840852843d304006e3ab333081fddda13b07193de8Robert Shih                (long long)(timeUs - mFirstTimeUs));
15850852843d304006e3ab333081fddda13b07193de8Robert Shih        timeUs -= mFirstTimeUs;
15860852843d304006e3ab333081fddda13b07193de8Robert Shih        if (timeUs < 0) {
15870852843d304006e3ab333081fddda13b07193de8Robert Shih            FLOGV("clamp negative timeUs to 0");
15880852843d304006e3ab333081fddda13b07193de8Robert Shih            timeUs = 0;
15890852843d304006e3ab333081fddda13b07193de8Robert Shih        }
15900852843d304006e3ab333081fddda13b07193de8Robert Shih        startTimeReached = (timeUs >= mStartTimeUs);
15910852843d304006e3ab333081fddda13b07193de8Robert Shih    }
15920852843d304006e3ab333081fddda13b07193de8Robert Shih    return startTimeReached;
15930852843d304006e3ab333081fddda13b07193de8Robert Shih}
15940852843d304006e3ab333081fddda13b07193de8Robert Shih
159543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shihstatus_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer) {
159643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (mTSParser == NULL) {
159743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers.
159843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
159943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
160014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
160143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (mNextPTSTimeUs >= 0ll) {
160243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        sp<AMessage> extra = new AMessage;
160343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // Since we are using absolute timestamps, signal an offset of 0 to prevent
160443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // ATSParser from skewing the timestamps of access units.
160543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0);
160614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1607d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        // When adapting, signal a recent media time to the parser,
1608d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        // so that PTS wrap around is handled for the new variant.
1609d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if (mStartTimeUs >= 0 && !mStartTimeUsRelative) {
1610d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            extra->setInt64(IStreamListener::kKeyRecentMediaTimeUs, mStartTimeUs);
1611d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        }
1612d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang
161343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        mTSParser->signalDiscontinuity(
1614fef808d42a9c94b0b5ef3c3d5fb0a090edbc42daWei Jia                ATSParser::DISCONTINUITY_TIME, extra);
161514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
161643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        mNextPTSTimeUs = -1ll;
161743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
161814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
161943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    size_t offset = 0;
162043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    while (offset + 188 <= buffer->size()) {
162143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188);
162214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
162343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if (err != OK) {
162443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            return err;
162514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
162614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
162743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        offset += 188;
162843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
162943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    // setRange to indicate consumed bytes.
163043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    buffer->setRange(buffer->offset() + offset, buffer->size() - offset);
16311543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
1632978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (mSegmentFirstPTS < 0ll) {
1633978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        // get the smallest first PTS from all streams present in this parser
163425f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan        for (size_t i = mPacketSources.size(); i > 0;) {
163525f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan            i--;
1636978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            const LiveSession::StreamType stream = mPacketSources.keyAt(i);
1637978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            if (stream == LiveSession::STREAMTYPE_SUBTITLES) {
1638978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                ALOGE("MPEG2 Transport streams do not contain subtitles.");
1639978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                return ERROR_MALFORMED;
1640978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            }
16418a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang            if (stream == LiveSession::STREAMTYPE_METADATA) {
16428a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang                continue;
16438a048338d9291b2db1b3a325fff58cb1aa69f04dChong Zhang            }
1644978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            ATSParser::SourceType type =LiveSession::getSourceTypeForStream(stream);
1645978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            sp<AnotherPacketSource> source =
1646978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                static_cast<AnotherPacketSource *>(
1647978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                        mTSParser->getSource(type).get());
1648978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
1649978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            if (source == NULL) {
1650978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                continue;
1651978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            }
1652978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            sp<AMessage> meta = source->getMetaAfterLastDequeued(0);
1653978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            if (meta != NULL) {
1654978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                int64_t timeUs;
1655978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                CHECK(meta->findInt64("timeUs", &timeUs));
1656978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                if (mSegmentFirstPTS < 0ll || timeUs < mSegmentFirstPTS) {
1657978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                    mSegmentFirstPTS = timeUs;
1658978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                }
1659978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            }
1660978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1661978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (mSegmentFirstPTS < 0ll) {
1662978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // didn't find any TS packet, can return early
1663978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            return OK;
1664978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1665978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (!mStartTimeUsRelative) {
1666978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // mStartup
1667978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            //   mStartup is true until we have queued a packet for all the streams
1668978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            //   we are fetching. We queue packets whose timestamps are greater than
1669978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            //   mStartTimeUs.
1670978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // mSegmentStartTimeUs >= 0
1671978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            //   mSegmentStartTimeUs is non-negative when adapting or switching tracks
1672978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // adjustSeqNumberWithAnchorTime(timeUs) == true
1673978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            //   we guessed a seq number that's either too large or too small.
1674978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // If this happens, we'll adjust mSeqNumber and restart fetching from new
1675978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // location. Note that we only want to adjust once, so set mSegmentStartTimeUs
1676978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // to -1 so that we don't enter this chunk next time.
1677978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            if (mStartup && mSegmentStartTimeUs >= 0
1678978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                    && adjustSeqNumberWithAnchorTime(mSegmentFirstPTS)) {
1679978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mStartTimeUsNotify = mNotify->dup();
1680978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mStartTimeUsNotify->setInt32("what", kWhatStartedAt);
1681978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mStartTimeUsNotify->setString("uri", mURI);
1682978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mIDRFound = false;
1683978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mSegmentStartTimeUs = -1;
1684978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                return -EAGAIN;
1685978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            }
1686978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1687978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    }
1688978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
168943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    status_t err = OK;
169025f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan    for (size_t i = mPacketSources.size(); i > 0;) {
169125f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan        i--;
169243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
169314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
169443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        const LiveSession::StreamType stream = mPacketSources.keyAt(i);
16957c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        if (stream == LiveSession::STREAMTYPE_SUBTITLES) {
16967c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            ALOGE("MPEG2 Transport streams do not contain subtitles.");
16977c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang            return ERROR_MALFORMED;
169843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
16990852843d304006e3ab333081fddda13b07193de8Robert Shih
17007c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang        const char *key = LiveSession::getKeyForStream(stream);
17010852843d304006e3ab333081fddda13b07193de8Robert Shih        ATSParser::SourceType type =LiveSession::getSourceTypeForStream(stream);
170214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
170343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        sp<AnotherPacketSource> source =
170443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            static_cast<AnotherPacketSource *>(
170543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    mTSParser->getSource(type).get());
170614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
170743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        if (source == NULL) {
170843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            continue;
170943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        }
171014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1711c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        const char *mime;
1712c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        sp<MetaData> format  = source->getFormat();
1713c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang        bool isAvc = format != NULL && format->findCString(kKeyMIMEType, &mime)
1714c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
1715c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang
171643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        sp<ABuffer> accessUnit;
171743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        status_t finalResult;
171843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        while (source->hasBufferAvailable(&finalResult)
171943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                && source->dequeueAccessUnit(&accessUnit) == OK) {
172043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
1721c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            int64_t timeUs;
172243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
1723309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1724309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (mStartup) {
17250852843d304006e3ab333081fddda13b07193de8Robert Shih                bool startTimeReached = isStartTimeReached(timeUs);
1726f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1727a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                if (!startTimeReached || (isAvc && !mIDRFound)) {
1728a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    // buffer up to the closest preceding IDR frame in the next segement,
1729a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    // or the closest succeeding IDR frame after the exact position
1730978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                    FSLOGV(stream, "timeUs(%lld)-mStartTimeUs(%lld)=%lld, mIDRFound=%d",
1731978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                            (long long)timeUs,
1732978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                            (long long)mStartTimeUs,
1733978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                            (long long)timeUs - mStartTimeUs,
1734978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                            mIDRFound);
1735f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih                    if (isAvc) {
1736d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                        if (IsIDR(accessUnit)) {
1737c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                            mVideoBuffer->clear();
173825f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                            FSLOGV(stream, "found IDR, clear mVideoBuffer");
1739c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                            mIDRFound = true;
1740c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                        }
1741d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                        if (mIDRFound && mStartTimeUsRelative && !startTimeReached) {
1742c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                            mVideoBuffer->queueAccessUnit(accessUnit);
174325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                            FSLOGV(stream, "saving AVC video AccessUnit");
1744c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                        }
17451543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih                    }
1746a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    if (!startTimeReached || (isAvc && !mIDRFound)) {
1747a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                        continue;
1748a48d372833ccec13c96ece9efcc226e8beac7f59Chong Zhang                    }
17491543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih                }
1750f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih            }
1751309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1752c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang            if (mStartTimeUsNotify != NULL) {
1753d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                uint32_t streamMask = 0;
1754d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask);
17550852843d304006e3ab333081fddda13b07193de8Robert Shih                if ((mStreamTypeMask & mPacketSources.keyAt(i))
17560852843d304006e3ab333081fddda13b07193de8Robert Shih                        && !(streamMask & mPacketSources.keyAt(i))) {
1757f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih                    streamMask |= mPacketSources.keyAt(i);
1758f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih                    mStartTimeUsNotify->setInt32("streamMask", streamMask);
175925f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    FSLOGV(stream, "found start point, timeUs=%lld, streamMask becomes %x",
176025f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                            (long long)timeUs, streamMask);
1761f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih
1762f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih                    if (streamMask == mStreamTypeMask) {
176325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                        FLOGV("found start point for all streams");
1764f78f62bd6b0a99747db53828d281a50b9270a646Robert Shih                        mStartup = false;
1765309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    }
1766309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                }
176743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            }
17681543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
176943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            if (mStopParams != NULL) {
1770309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                int32_t discontinuitySeq;
177143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                int64_t stopTimeUs;
1772309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq)
1773309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                        || discontinuitySeq > mDiscontinuitySeq
1774309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                        || !mStopParams->findInt64(key, &stopTimeUs)
1775309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                        || (discontinuitySeq == mDiscontinuitySeq
1776309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                                && timeUs >= stopTimeUs)) {
177725f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    FSLOGV(stream, "reached stop point, timeUs=%lld", (long long)timeUs);
177843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    mStreamTypeMask &= ~stream;
177943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    mPacketSources.removeItemsAt(i);
178043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih                    break;
17811543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih                }
178243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            }
17831543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
1784309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (stream == LiveSession::STREAMTYPE_VIDEO) {
1785309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                const bool discard = true;
1786309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                status_t status;
1787309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                while (mVideoBuffer->hasBufferAvailable(&status)) {
1788309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    sp<ABuffer> videoBuffer;
1789309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    mVideoBuffer->dequeueAccessUnit(&videoBuffer);
1790309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    setAccessUnitProperties(videoBuffer, source, discard);
1791309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    packetSource->queueAccessUnit(videoBuffer);
179225f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    int64_t bufferTimeUs;
179325f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    CHECK(videoBuffer->meta()->findInt64("timeUs", &bufferTimeUs));
179425f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                    FSLOGV(stream, "queueAccessUnit (saved), timeUs=%lld",
179525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang                            (long long)bufferTimeUs);
1796309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                }
17970852843d304006e3ab333081fddda13b07193de8Robert Shih            } else if (stream == LiveSession::STREAMTYPE_METADATA && !mHasMetadata) {
17980852843d304006e3ab333081fddda13b07193de8Robert Shih                mHasMetadata = true;
17990852843d304006e3ab333081fddda13b07193de8Robert Shih                sp<AMessage> notify = mNotify->dup();
18000852843d304006e3ab333081fddda13b07193de8Robert Shih                notify->setInt32("what", kWhatMetadataDetected);
18010852843d304006e3ab333081fddda13b07193de8Robert Shih                notify->post();
180214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
18031543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
1804309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            setAccessUnitProperties(accessUnit, source);
180543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            packetSource->queueAccessUnit(accessUnit);
180625f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang            FSLOGV(stream, "queueAccessUnit, timeUs=%lld", (long long)timeUs);
18071543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        }
18081543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
18091543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        if (err != OK) {
181043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            break;
18111543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih        }
181243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
18131543d3c735a5ba4ddfcf8ab644575df13c7e30a9Robert Shih
181443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (err != OK) {
181525f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan        for (size_t i = mPacketSources.size(); i > 0;) {
181625f191c5cb2ec532e534be646c32806f9f85e196Vishwath Mohan            i--;
181743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
181843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih            packetSource->clear();
181914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
182043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        return err;
182143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
182214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
182343ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    if (!mStreamTypeMask) {
182443ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        // Signal gap is filled between original and new stream.
182525f82752942b1c78aec8ee303d61afff85cff9d1Chong Zhang        FLOGV("reached stop point for all streams");
182643ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        return ERROR_OUT_OF_RANGE;
182743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    }
182843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
182943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    return OK;
183043ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih}
183143ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
18327d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar/* static */
18337d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnarbool PlaylistFetcher::bufferStartsWithWebVTTMagicSequence(
18347d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar        const sp<ABuffer> &buffer) {
18357d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    size_t pos = 0;
18367d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar
18377d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    // skip possible BOM
18387d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    if (buffer->size() >= pos + 3 &&
18397d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar            !memcmp("\xef\xbb\xbf", buffer->data() + pos, 3)) {
18407d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar        pos += 3;
18417d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    }
18427d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar
18437d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    // accept WEBVTT followed by SPACE, TAB or (CR) LF
18447d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    if (buffer->size() < pos + 6 ||
18457d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar            memcmp("WEBVTT", buffer->data() + pos, 6)) {
18467d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar        return false;
18477d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    }
18487d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    pos += 6;
18497d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar
18507d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    if (buffer->size() == pos) {
18517d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar        return true;
18527d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    }
18537d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar
18547d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    uint8_t sep = buffer->data()[pos];
18557d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    return sep == ' ' || sep == '\t' || sep == '\n' || sep == '\r';
18567d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar}
18577d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar
185843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shihstatus_t PlaylistFetcher::extractAndQueueAccessUnits(
185943ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih        const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
18607d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    if (bufferStartsWithWebVTTMagicSequence(buffer)) {
186114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) {
186214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("This stream only contains subtitles.");
186314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
186414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
186514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
186614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const sp<AnotherPacketSource> packetSource =
186714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
186814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1869dcb89b3b505522efde173c105a851c412f947178Chong Zhang        int64_t durationUs;
1870dcb89b3b505522efde173c105a851c412f947178Chong Zhang        CHECK(itemMeta->findInt64("durationUs", &durationUs));
1871dcb89b3b505522efde173c105a851c412f947178Chong Zhang        buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber));
1872dcb89b3b505522efde173c105a851c412f947178Chong Zhang        buffer->meta()->setInt64("durationUs", durationUs);
1873309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        buffer->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber));
1874309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        buffer->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq);
1875b44ce2f84691559672cfaf6bb8fd3a9ac43904f2Robert Shih        buffer->meta()->setInt32("subtitleGeneration", mSubtitleGeneration);
187614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        packetSource->queueAccessUnit(buffer);
187714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return OK;
187814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
187914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
188014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (mNextPTSTimeUs >= 0ll) {
188114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mNextPTSTimeUs = -1ll;
188214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
188314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
188414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    // This better be an ISO 13818-7 (AAC) or ISO 13818-1 (MPEG) audio
188514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    // stream prefixed by an ID3 tag.
188614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
188714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool firstID3Tag = true;
188814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint64_t PTS = 0;
188914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
189014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (;;) {
189114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // Make sure to skip all ID3 tags preceding the audio data.
189214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // At least one must be present to provide the PTS timestamp.
189314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
189414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ID3 id3(buffer->data(), buffer->size(), true /* ignoreV1 */);
189514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (!id3.isValid()) {
189614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (firstID3Tag) {
189714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Unable to parse ID3 tag.");
189814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
189914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
190014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                break;
190114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
190214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
190314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
190414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (firstID3Tag) {
190514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            bool found = false;
190614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
190714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ID3::Iterator it(id3, "PRIV");
190814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            while (!it.done()) {
190914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                size_t length;
191014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                const uint8_t *data = it.getData(&length);
1911be7b5e253f85132683826f305e5dcdaf83f0b300Joshua J. Drake                if (!data) {
1912be7b5e253f85132683826f305e5dcdaf83f0b300Joshua J. Drake                    return ERROR_MALFORMED;
1913be7b5e253f85132683826f305e5dcdaf83f0b300Joshua J. Drake                }
191414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
191514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                static const char *kMatchName =
191614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    "com.apple.streaming.transportStreamTimestamp";
191714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                static const size_t kMatchNameLen = strlen(kMatchName);
191814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
191914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                if (length == kMatchNameLen + 1 + 8
192014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                        && !strncmp((const char *)data, kMatchName, kMatchNameLen)) {
192114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    found = true;
192214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    PTS = U64_AT(&data[kMatchNameLen + 1]);
192314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                }
192414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
192514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                it.next();
192614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
192714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
192814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!found) {
192914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Unable to extract transportStreamTimestamp from ID3 tag.");
193014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
193114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
193214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
193314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
193414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // skip the ID3 tag
193514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        buffer->setRange(
193614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                buffer->offset() + id3.rawSize(), buffer->size() - id3.rawSize());
193714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
193814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        firstID3Tag = false;
193914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
194014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
194114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (mStreamTypeMask != LiveSession::STREAMTYPE_AUDIO) {
194214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGW("This stream only contains audio data!");
194314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
194414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mStreamTypeMask &= LiveSession::STREAMTYPE_AUDIO;
194514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
194614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (mStreamTypeMask == 0) {
194714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return OK;
194814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
194914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
195014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
195114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AnotherPacketSource> packetSource =
195214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mPacketSources.valueFor(LiveSession::STREAMTYPE_AUDIO);
195314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
195414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (packetSource->getFormat() == NULL && buffer->size() >= 7) {
195514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ABitReader bits(buffer->data(), buffer->size());
195614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
195714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // adts_fixed_header
195814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
195914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_EQ(bits.getBits(12), 0xfffu);
196014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        bits.skipBits(3);  // ID, layer
1961b3f9759c8c9437c45b9a34519ce2ea38a8314d4eAndreas Gampe        bool protection_absent __unused = bits.getBits(1) != 0;
196214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
196314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        unsigned profile = bits.getBits(2);
196414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_NE(profile, 3u);
196514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        unsigned sampling_freq_index = bits.getBits(4);
196614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        bits.getBits(1);  // private_bit
196714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        unsigned channel_configuration = bits.getBits(3);
196814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_NE(channel_configuration, 0u);
196914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        bits.skipBits(2);  // original_copy, home
197014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
197114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        sp<MetaData> meta = MakeAACCodecSpecificData(
197214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                profile, sampling_freq_index, channel_configuration);
197314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
197414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        meta->setInt32(kKeyIsADTS, true);
197514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
197614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        packetSource->setFormat(meta);
197714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
197814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
197914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t numSamples = 0ll;
198014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t sampleRate;
198114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK(packetSource->getFormat()->findInt32(kKeySampleRate, &sampleRate));
198214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1983309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int64_t timeUs = (PTS * 100ll) / 9ll;
1984c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang    if (mStartup && !mFirstPTSValid) {
1985309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        mFirstPTSValid = true;
1986309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        mFirstTimeUs = timeUs;
1987309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1988309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1989978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (mSegmentFirstPTS < 0ll) {
1990978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mSegmentFirstPTS = timeUs;
1991978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (!mStartTimeUsRelative) {
1992978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            // Duplicated logic from how we handle .ts playlists.
1993978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            if (mStartup && mSegmentStartTimeUs >= 0
1994978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                    && adjustSeqNumberWithAnchorTime(timeUs)) {
1995978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                mSegmentStartTimeUs = -1;
1996978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                return -EAGAIN;
1997978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            }
1998978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
1999978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    }
2000978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
200114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    size_t offset = 0;
200214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (offset < buffer->size()) {
200314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const uint8_t *adtsHeader = buffer->data() + offset;
200414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_LT(offset + 5, buffer->size());
200514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
200614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        unsigned aac_frame_length =
200714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ((adtsHeader[3] & 3) << 11)
200814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            | (adtsHeader[4] << 3)
200914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            | (adtsHeader[5] >> 5);
201014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2011bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih        if (aac_frame_length == 0) {
2012bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih            const uint8_t *id3Header = adtsHeader;
2013bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih            if (!memcmp(id3Header, "ID3", 3)) {
2014bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih                ID3 id3(id3Header, buffer->size() - offset, true);
2015bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih                if (id3.isValid()) {
2016bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih                    offset += id3.rawSize();
2017bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih                    continue;
2018bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih                };
2019bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih            }
2020bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih            return ERROR_MALFORMED;
2021bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih        }
2022bdc0609f8133517b8e051938ad66bac750be90b4Robert Shih
202314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK_LE(offset + aac_frame_length, buffer->size());
202414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
202514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        int64_t unitTimeUs = timeUs + numSamples * 1000000ll / sampleRate;
2026309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        offset += aac_frame_length;
202714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
202814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // Each AAC frame encodes 1024 samples.
202914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        numSamples += 1024;
203014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2031309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        if (mStartup) {
2032309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            int64_t startTimeUs = unitTimeUs;
2033309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (mStartTimeUsRelative) {
2034309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                startTimeUs -= mFirstTimeUs;
2035309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                if (startTimeUs  < 0) {
2036309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    startTimeUs = 0;
2037309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                }
2038309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
2039309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            if (startTimeUs < mStartTimeUs) {
2040309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                continue;
2041309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            }
204273d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih
204373d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            if (mStartTimeUsNotify != NULL) {
204473d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                mStartTimeUsNotify->setInt32("streamMask", LiveSession::STREAMTYPE_AUDIO);
2045f5b7c3b3c9a6da29f3bbd02e4031ad19bc7ad0f7Robert Shih                mStartup = false;
204673d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            }
204773d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        }
204873d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih
204973d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        if (mStopParams != NULL) {
205073d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            int32_t discontinuitySeq;
205173d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            int64_t stopTimeUs;
205273d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq)
205373d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                    || discontinuitySeq > mDiscontinuitySeq
205473d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                    || !mStopParams->findInt64("timeUsAudio", &stopTimeUs)
205573d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                    || (discontinuitySeq == mDiscontinuitySeq && unitTimeUs >= stopTimeUs)) {
205673d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                mStreamTypeMask = 0;
205773d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                mPacketSources.clear();
205873d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih                return ERROR_OUT_OF_RANGE;
205973d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih            }
2060309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        }
206114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2062309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        sp<ABuffer> unit = new ABuffer(aac_frame_length);
2063309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        memcpy(unit->data(), adtsHeader, aac_frame_length);
2064309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
2065309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        unit->meta()->setInt64("timeUs", unitTimeUs);
206673d2847af14cdd5fdf8bd1ac80fb7ddf9ae7d9a7Robert Shih        setAccessUnitProperties(unit, packetSource);
2067309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        packetSource->queueAccessUnit(unit);
206814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
206914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
207014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
207114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
207214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
207314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid PlaylistFetcher::updateDuration() {
207414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t durationUs = 0ll;
207514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (size_t index = 0; index < mPlaylist->size(); ++index) {
207614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        sp<AMessage> itemMeta;
207714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(mPlaylist->itemAt(
207814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    index, NULL /* uri */, &itemMeta));
207914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
208014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        int64_t itemDurationUs;
208114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
208214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
208314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        durationUs += itemDurationUs;
208414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
208514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
208614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AMessage> msg = mNotify->dup();
208714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->setInt32("what", kWhatDurationUpdate);
208814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->setInt64("durationUs", durationUs);
208914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    msg->post();
209014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
209114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
20927c8708046117e03c0d38006bdd9685139df3ac6bChong Zhangvoid PlaylistFetcher::updateTargetDuration() {
20937c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    sp<AMessage> msg = mNotify->dup();
20947c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    msg->setInt32("what", kWhatTargetDurationUpdate);
2095978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    msg->setInt64("targetDurationUs", mPlaylist->getTargetDuration());
20967c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang    msg->post();
20977c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang}
20987c8708046117e03c0d38006bdd9685139df3ac6bChong Zhang
209914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}  // namespace android
2100