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     int32_t mNumRetriesForMonitorQueue;
149     bool mStartup;
150     bool mIDRFound;
151     int32_t mSeekMode;
152     bool mTimeChangeSignaled;
153     int64_t mNextPTSTimeUs;
154 
155     int32_t mMonitorQueueGeneration;
156     const int32_t mSubtitleGeneration;
157 
158     int32_t mLastDiscontinuitySeq;
159 
160     enum RefreshState {
161         INITIAL_MINIMUM_RELOAD_DELAY,
162         FIRST_UNCHANGED_RELOAD_ATTEMPT,
163         SECOND_UNCHANGED_RELOAD_ATTEMPT,
164         THIRD_UNCHANGED_RELOAD_ATTEMPT
165     };
166     RefreshState mRefreshState;
167 
168     uint8_t mPlaylistHash[16];
169 
170     sp<ATSParser> mTSParser;
171 
172     bool mFirstPTSValid;
173     int64_t mFirstTimeUs;
174     int64_t mSegmentFirstPTS;
175     sp<AnotherPacketSource> mVideoBuffer;
176 
177     // Stores the initialization vector to decrypt the next block of cipher text, which can
178     // either be derived from the sequence number, read from the manifest, or copied from
179     // the last block of cipher text (cipher-block chaining).
180     unsigned char mAESInitVec[AES_BLOCK_SIZE];
181     unsigned char mKeyData[AES_BLOCK_SIZE];
182     bool mSampleAesKeyItemChanged;
183     sp<AMessage> mSampleAesKeyItem;
184 
185     Mutex mThresholdLock;
186     float mThresholdRatio;
187 
188     sp<DownloadState> mDownloadState;
189 
190     bool mHasMetadata;
191 
192     // Set first to true if decrypting the first segment of a playlist segment. When
193     // first is true, reset the initialization vector based on the available
194     // information in the manifest; otherwise, use the initialization vector as
195     // updated by the last call to AES_cbc_encrypt.
196     //
197     // For the input to decrypt correctly, decryptBuffer must be called on
198     // consecutive byte ranges on block boundaries, e.g. 0..15, 16..47, 48..63,
199     // and so on.
200     status_t decryptBuffer(
201             size_t playlistIndex, const sp<ABuffer> &buffer,
202             bool first = true);
203     status_t checkDecryptPadding(const sp<ABuffer> &buffer);
204 
205     void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
206     void cancelMonitorQueue();
207     void setStoppingThreshold(float thresholdRatio, bool disconnect);
208     void resetStoppingThreshold(bool disconnect);
209     float getStoppingThreshold();
210     bool shouldPauseDownload();
211 
212     int64_t delayUsToRefreshPlaylist() const;
213     status_t refreshPlaylist();
214 
215     // Returns the media time in us of the segment specified by seqNumber.
216     // This is computed by summing the durations of all segments before it.
217     int64_t getSegmentStartTimeUs(int32_t seqNumber) const;
218     // Returns the duration time in us of the segment specified.
219     int64_t getSegmentDurationUs(int32_t seqNumber) const;
220 
221     status_t onStart(const sp<AMessage> &msg);
222     void onPause();
223     void onStop(const sp<AMessage> &msg);
224     void onMonitorQueue();
225     void onDownloadNext();
226     void initSeqNumberForLiveStream(
227             int32_t &firstSeqNumberInPlaylist,
228             int32_t &lastSeqNumberInPlaylist);
229     bool initDownloadState(
230             AString &uri,
231             sp<AMessage> &itemMeta,
232             int32_t &firstSeqNumberInPlaylist,
233             int32_t &lastSeqNumberInPlaylist);
234 
235     // Resume a fetcher to continue until the stopping point stored in msg.
236     status_t onResumeUntil(const sp<AMessage> &msg);
237 
238     const sp<ABuffer> &setAccessUnitProperties(
239             const sp<ABuffer> &accessUnit,
240             const sp<AnotherPacketSource> &source,
241             bool discard = false);
242     bool isStartTimeReached(int64_t timeUs);
243     status_t extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer);
244 
245     status_t extractAndQueueAccessUnits(
246             const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta);
247 
248     void notifyStopReached();
249     void notifyError(status_t err);
250 
251     void queueDiscontinuity(
252             ATSParser::DiscontinuityType type, const sp<AMessage> &extra);
253 
254     bool adjustSeqNumberWithAnchorTime(int64_t anchorTimeUs);
255     int32_t getSeqNumberForDiscontinuity(size_t discontinuitySeq) const;
256     int32_t getSeqNumberForTime(int64_t timeUs) const;
257 
258     void updateDuration();
259     void updateTargetDuration();
260 
261     DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
262 };
263 
264 }  // namespace android
265 
266 #endif  // PLAYLIST_FETCHER_H_
267 
268