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> ¬ify, 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> ¶ms) { 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", ¶ms)); 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