1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef PLAYLIST_FETCHER_H_
18 
19 #define PLAYLIST_FETCHER_H_
20 
21 #include <media/stagefright/foundation/AHandler.h>
22 #include <openssl/aes.h>
23 
24 #include "mpeg2ts/ATSParser.h"
25 #include "LiveSession.h"
26 
27 namespace android {
28 
29 struct ABuffer;
30 struct AnotherPacketSource;
31 class DataSource;
32 struct HTTPBase;
33 struct LiveDataSource;
34 struct M3UParser;
35 class String8;
36 
37 struct PlaylistFetcher : public AHandler {
38     static const int64_t kMinBufferedDurationUs;
39     static const int32_t kDownloadBlockSize;
40     static const int64_t kFetcherResumeThreshold;
41 
42     enum {
43         kWhatStarted,
44         kWhatPaused,
45         kWhatStopped,
46         kWhatError,
47         kWhatDurationUpdate,
48         kWhatTargetDurationUpdate,
49         kWhatPrepared,
50         kWhatPreparationFailed,
51         kWhatStartedAt,
52         kWhatStopReached,
53         kWhatPlaylistFetched,
54         kWhatMetadataDetected,
55     };
56 
57     PlaylistFetcher(
58             const sp<AMessage> &notify,
59             const sp<LiveSession> &session,
60             const char *uri,
61             int32_t id,
62             int32_t subtitleGeneration);
63 
64     int32_t getFetcherID() const;
65 
66     void startAsync(
67             const sp<AnotherPacketSource> &audioSource,
68             const sp<AnotherPacketSource> &videoSource,
69             const sp<AnotherPacketSource> &subtitleSource,
70             const sp<AnotherPacketSource> &metadataSource,
71             int64_t startTimeUs = -1ll,         // starting timestamps
72             int64_t segmentStartTimeUs = -1ll, // starting position within playlist
73             // startTimeUs!=segmentStartTimeUs only when playlist is live
74             int32_t startDiscontinuitySeq = -1,
75             LiveSession::SeekMode seekMode = LiveSession::kSeekModeExactPosition);
76 
77     void pauseAsync(float thresholdRatio, bool disconnect);
78 
79     void stopAsync(bool clear = true);
80 
81     void resumeUntilAsync(const sp<AMessage> &params);
82 
83     void fetchPlaylistAsync();
84 
getStreamTypeMaskPlaylistFetcher85     uint32_t getStreamTypeMask() const {
86         return mStreamTypeMask;
87     }
88 
89 protected:
90     virtual ~PlaylistFetcher();
91     virtual void onMessageReceived(const sp<AMessage> &msg);
92 
93 private:
94     enum {
95         kMaxNumRetries         = 5,
96     };
97 
98     enum {
99         kWhatStart          = 'strt',
100         kWhatPause          = 'paus',
101         kWhatStop           = 'stop',
102         kWhatMonitorQueue   = 'moni',
103         kWhatResumeUntil    = 'rsme',
104         kWhatDownloadNext   = 'dlnx',
105         kWhatFetchPlaylist  = 'flst'
106     };
107 
108     struct DownloadState;
109 
110     static const int64_t kMaxMonitorDelayUs;
111     static const int32_t kNumSkipFrames;
112 
113     static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer);
114     static bool bufferStartsWithWebVTTMagicSequence(const sp<ABuffer>& buffer);
115 
116     // notifications to mSession
117     sp<AMessage> mNotify;
118     sp<AMessage> mStartTimeUsNotify;
119 
120     sp<HTTPDownloader> mHTTPDownloader;
121     sp<LiveSession> mSession;
122     AString mURI;
123 
124     int32_t mFetcherID;
125 
126     uint32_t mStreamTypeMask;
127     int64_t mStartTimeUs;
128 
129     // Start time relative to the beginning of the first segment in the initial
130     // playlist. It's value is initialized to a non-negative value only when we are
131     // adapting or switching tracks.
132     int64_t mSegmentStartTimeUs;
133 
134     int32_t mDiscontinuitySeq;
135     bool mStartTimeUsRelative;
136     sp<AMessage> mStopParams; // message containing the latest timestamps we should fetch.
137 
138     KeyedVector<LiveSession::StreamType, sp<AnotherPacketSource> >
139         mPacketSources;
140 
141     KeyedVector<AString, sp<ABuffer> > mAESKeyForURI;
142 
143     int64_t mLastPlaylistFetchTimeUs;
144     int64_t mPlaylistTimeUs;
145     sp<M3UParser> mPlaylist;
146     int32_t mSeqNumber;
147     int32_t mNumRetries;
148     bool mStartup;
149     bool mIDRFound;
150     int32_t mSeekMode;
151     bool mTimeChangeSignaled;
152     int64_t mNextPTSTimeUs;
153 
154     int32_t mMonitorQueueGeneration;
155     const int32_t mSubtitleGeneration;
156 
157     int32_t mLastDiscontinuitySeq;
158 
159     enum RefreshState {
160         INITIAL_MINIMUM_RELOAD_DELAY,
161         FIRST_UNCHANGED_RELOAD_ATTEMPT,
162         SECOND_UNCHANGED_RELOAD_ATTEMPT,
163         THIRD_UNCHANGED_RELOAD_ATTEMPT
164     };
165     RefreshState mRefreshState;
166 
167     uint8_t mPlaylistHash[16];
168 
169     sp<ATSParser> mTSParser;
170 
171     bool mFirstPTSValid;
172     int64_t mFirstTimeUs;
173     int64_t mSegmentFirstPTS;
174     sp<AnotherPacketSource> mVideoBuffer;
175 
176     // Stores the initialization vector to decrypt the next block of cipher text, which can
177     // either be derived from the sequence number, read from the manifest, or copied from
178     // the last block of cipher text (cipher-block chaining).
179     unsigned char mAESInitVec[AES_BLOCK_SIZE];
180     unsigned char mKeyData[AES_BLOCK_SIZE];
181     bool mSampleAesKeyItemChanged;
182     sp<AMessage> mSampleAesKeyItem;
183 
184     Mutex mThresholdLock;
185     float mThresholdRatio;
186 
187     sp<DownloadState> mDownloadState;
188 
189     bool mHasMetadata;
190 
191     // Set first to true if decrypting the first segment of a playlist segment. When
192     // first is true, reset the initialization vector based on the available
193     // information in the manifest; otherwise, use the initialization vector as
194     // updated by the last call to AES_cbc_encrypt.
195     //
196     // For the input to decrypt correctly, decryptBuffer must be called on
197     // consecutive byte ranges on block boundaries, e.g. 0..15, 16..47, 48..63,
198     // and so on.
199     status_t decryptBuffer(
200             size_t playlistIndex, const sp<ABuffer> &buffer,
201             bool first = true);
202     status_t checkDecryptPadding(const sp<ABuffer> &buffer);
203 
204     void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
205     void cancelMonitorQueue();
206     void setStoppingThreshold(float thresholdRatio, bool disconnect);
207     void resetStoppingThreshold(bool disconnect);
208     float getStoppingThreshold();
209     bool shouldPauseDownload();
210 
211     int64_t delayUsToRefreshPlaylist() const;
212     status_t refreshPlaylist();
213 
214     // Returns the media time in us of the segment specified by seqNumber.
215     // This is computed by summing the durations of all segments before it.
216     int64_t getSegmentStartTimeUs(int32_t seqNumber) const;
217     // Returns the duration time in us of the segment specified.
218     int64_t getSegmentDurationUs(int32_t seqNumber) const;
219 
220     status_t onStart(const sp<AMessage> &msg);
221     void onPause();
222     void onStop(const sp<AMessage> &msg);
223     void onMonitorQueue();
224     void onDownloadNext();
225     void initSeqNumberForLiveStream(
226             int32_t &firstSeqNumberInPlaylist,
227             int32_t &lastSeqNumberInPlaylist);
228     bool initDownloadState(
229             AString &uri,
230             sp<AMessage> &itemMeta,
231             int32_t &firstSeqNumberInPlaylist,
232             int32_t &lastSeqNumberInPlaylist);
233 
234     // Resume a fetcher to continue until the stopping point stored in msg.
235     status_t onResumeUntil(const sp<AMessage> &msg);
236 
237     const sp<ABuffer> &setAccessUnitProperties(
238             const sp<ABuffer> &accessUnit,
239             const sp<AnotherPacketSource> &source,
240             bool discard = false);
241     bool isStartTimeReached(int64_t timeUs);
242     status_t extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer);
243 
244     status_t extractAndQueueAccessUnits(
245             const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta);
246 
247     void notifyStopReached();
248     void notifyError(status_t err);
249 
250     void queueDiscontinuity(
251             ATSParser::DiscontinuityType type, const sp<AMessage> &extra);
252 
253     bool adjustSeqNumberWithAnchorTime(int64_t anchorTimeUs);
254     int32_t getSeqNumberForDiscontinuity(size_t discontinuitySeq) const;
255     int32_t getSeqNumberForTime(int64_t timeUs) const;
256 
257     void updateDuration();
258     void updateTargetDuration();
259 
260     DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
261 };
262 
263 }  // namespace android
264 
265 #endif  // PLAYLIST_FETCHER_H_
266 
267