PlaylistFetcher.h revision 309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3
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#ifndef PLAYLIST_FETCHER_H_
1814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#define PLAYLIST_FETCHER_H_
2014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <media/stagefright/foundation/AHandler.h>
2214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "mpeg2ts/ATSParser.h"
2414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "LiveSession.h"
2514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubernamespace android {
2714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
2814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct ABuffer;
2914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct AnotherPacketSource;
3014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct DataSource;
3114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct HTTPBase;
3214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct LiveDataSource;
3314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct M3UParser;
3414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct String8;
3514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
3614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct PlaylistFetcher : public AHandler {
3714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum {
3814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatStarted,
3914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatPaused,
4014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatStopped,
4114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatError,
4214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatDurationUpdate,
4314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatTemporarilyDoneFetching,
4414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatPrepared,
4514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatPreparationFailed,
46777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih        kWhatStartedAt,
4714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
4814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    PlaylistFetcher(
5014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const sp<AMessage> &notify,
5114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const sp<LiveSession> &session,
5214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const char *uri);
5314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<DataSource> getDataSource();
5514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void startAsync(
5714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const sp<AnotherPacketSource> &audioSource,
5814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const sp<AnotherPacketSource> &videoSource,
5914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const sp<AnotherPacketSource> &subtitleSource,
60309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            int64_t startTimeUs = -1ll,         // starting timestamps
61309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            int64_t segmentStartTimeUs = -1ll, // starting position within playlist
62309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            // startTimeUs!=segmentStartTimeUs only when playlist is live
63309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            int32_t startDiscontinuitySeq = 0,
64309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            bool adaptive = false);
6514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void pauseAsync();
6714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
68309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    void stopAsync(bool clear = true);
6914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
70777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    void resumeUntilAsync(const sp<AMessage> &params);
71777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih
7214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberprotected:
7314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    virtual ~PlaylistFetcher();
7414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    virtual void onMessageReceived(const sp<AMessage> &msg);
7514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
7614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberprivate:
7714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum {
7814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kMaxNumRetries         = 5,
7914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
8014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
8114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum {
8214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatStart          = 'strt',
8314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatPause          = 'paus',
8414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatStop           = 'stop',
8514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        kWhatMonitorQueue   = 'moni',
86777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih        kWhatResumeUntil    = 'rsme',
87777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih        kWhatDownloadNext   = 'dlnx',
8814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
8914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
9014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    static const int64_t kMinBufferedDurationUs;
916708a45ba1b5eacf583d5e80b2075b68940fe0abLajos Molnar    static const int64_t kMaxMonitorDelayUs;
9243ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    static const int32_t kDownloadBlockSize;
93777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    static const int32_t kNumSkipFrames;
9414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
9543ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer);
967d8e3ccfbf326b5e190b416590e956c2fc3021f7Lajos Molnar    static bool bufferStartsWithWebVTTMagicSequence(const sp<ABuffer>& buffer);
9743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
98777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    // notifications to mSession
9914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AMessage> mNotify;
100777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    sp<AMessage> mStartTimeUsNotify;
101777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih
10214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<LiveSession> mSession;
10314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString mURI;
10414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
10514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint32_t mStreamTypeMask;
10614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t mStartTimeUs;
107309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int64_t mSegmentStartTimeUs;
108309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    ssize_t mDiscontinuitySeq;
109309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    bool mStartTimeUsRelative;
110777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    sp<AMessage> mStopParams; // message containing the latest timestamps we should fetch.
11114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    KeyedVector<LiveSession::StreamType, sp<AnotherPacketSource> >
11314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mPacketSources;
11414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    KeyedVector<AString, sp<ABuffer> > mAESKeyForURI;
11614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t mLastPlaylistFetchTimeUs;
11814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<M3UParser> mPlaylist;
11914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t mSeqNumber;
12014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t mNumRetries;
12114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool mStartup;
122309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    bool mAdaptive;
1236708a45ba1b5eacf583d5e80b2075b68940fe0abLajos Molnar    bool mPrepared;
12414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t mNextPTSTimeUs;
12514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t mMonitorQueueGeneration;
12714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum RefreshState {
12914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        INITIAL_MINIMUM_RELOAD_DELAY,
13014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FIRST_UNCHANGED_RELOAD_ATTEMPT,
13114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        SECOND_UNCHANGED_RELOAD_ATTEMPT,
13214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        THIRD_UNCHANGED_RELOAD_ATTEMPT
13314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
13414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    RefreshState mRefreshState;
13514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
13614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint8_t mPlaylistHash[16];
13714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
13814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<ATSParser> mTSParser;
13914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
14014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool mFirstPTSValid;
14114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint64_t mFirstPTS;
142309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int64_t mFirstTimeUs;
14314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t mAbsoluteTimeAnchorUs;
144309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    sp<AnotherPacketSource> mVideoBuffer;
14514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1462cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // Stores the initialization vector to decrypt the next block of cipher text, which can
1472cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // either be derived from the sequence number, read from the manifest, or copied from
1482cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // the last block of cipher text (cipher-block chaining).
1492cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    unsigned char mAESInitVec[16];
1502cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih
1512cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // Set first to true if decrypting the first segment of a playlist segment. When
1522cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // first is true, reset the initialization vector based on the available
1532cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // information in the manifest; otherwise, use the initialization vector as
1542cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // updated by the last call to AES_cbc_encrypt.
1552cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    //
1562cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // For the input to decrypt correctly, decryptBuffer must be called on
1572cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // consecutive byte ranges on block boundaries, e.g. 0..15, 16..47, 48..63,
1582cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    // and so on.
15914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    status_t decryptBuffer(
1602cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih            size_t playlistIndex, const sp<ABuffer> &buffer,
1612cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih            bool first = true);
1622cd94583868b775a548233a4f7cd1d988fc6344fRobert Shih    status_t checkDecryptPadding(const sp<ABuffer> &buffer);
16314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1646708a45ba1b5eacf583d5e80b2075b68940fe0abLajos Molnar    void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
16514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void cancelMonitorQueue();
16614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
1676708a45ba1b5eacf583d5e80b2075b68940fe0abLajos Molnar    int64_t delayUsToRefreshPlaylist() const;
1686708a45ba1b5eacf583d5e80b2075b68940fe0abLajos Molnar    status_t refreshPlaylist();
16914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
17014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    // Returns the media time in us of the segment specified by seqNumber.
17114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    // This is computed by summing the durations of all segments before it.
17214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int64_t getSegmentStartTimeUs(int32_t seqNumber) const;
17314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
17414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    status_t onStart(const sp<AMessage> &msg);
17514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void onPause();
176ceeabe15f4e7bc73efdfcafed917202de9d515cbRobert Shih    void onStop(const sp<AMessage> &msg);
17714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void onMonitorQueue();
17814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void onDownloadNext();
17914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
180777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    // Resume a fetcher to continue until the stopping point stored in msg.
181777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    status_t onResumeUntil(const sp<AMessage> &msg);
182777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih
183309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    const sp<ABuffer> &setAccessUnitProperties(
184309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            const sp<ABuffer> &accessUnit,
185309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            const sp<AnotherPacketSource> &source,
186309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            bool discard = false);
18743ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih    status_t extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer);
18843ca783effd99bba0e6e2dd6fe177a8888578ef8Robert Shih
189dcb89b3b505522efde173c105a851c412f947178Chong Zhang    status_t extractAndQueueAccessUnits(
190dcb89b3b505522efde173c105a851c412f947178Chong Zhang            const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta);
19114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
19214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void notifyError(status_t err);
19314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
19414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void queueDiscontinuity(
19514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ATSParser::DiscontinuityType type, const sp<AMessage> &extra);
19614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
197309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t getSeqNumberWithAnchorTime(int64_t anchorTimeUs) const;
198309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t getSeqNumberForDiscontinuity(size_t discontinuitySeq) const;
19914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    int32_t getSeqNumberForTime(int64_t timeUs) const;
20014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
20114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void updateDuration();
20214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
203777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    // Before resuming a fetcher in onResume, check the remaining duration is longer than that
204777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    // returned by resumeThreshold.
205777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih    int64_t resumeThreshold(const sp<AMessage> &msg);
206777ee5ed736c8f6c3f7d196ea022f7432bfd23e1Robert Shih
20714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
20814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber};
20914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
21014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}  // namespace android
21114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
21214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#endif  // PLAYLIST_FETCHER_H_
21314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
214