1 /* 2 * Copyright (C) 2010 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 LIVE_SESSION_H_ 18 19 #define LIVE_SESSION_H_ 20 21 #include <media/stagefright/foundation/AHandler.h> 22 #include <media/mediaplayer.h> 23 24 #include <utils/String8.h> 25 26 namespace android { 27 28 struct ABuffer; 29 struct AnotherPacketSource; 30 struct DataSource; 31 struct HTTPBase; 32 struct IMediaHTTPService; 33 struct LiveDataSource; 34 struct M3UParser; 35 struct PlaylistFetcher; 36 struct Parcel; 37 38 struct LiveSession : public AHandler { 39 enum Flags { 40 // Don't log any URLs. 41 kFlagIncognito = 1, 42 }; 43 LiveSession( 44 const sp<AMessage> ¬ify, 45 uint32_t flags, 46 const sp<IMediaHTTPService> &httpService); 47 48 enum StreamIndex { 49 kAudioIndex = 0, 50 kVideoIndex = 1, 51 kSubtitleIndex = 2, 52 kMaxStreams = 3, 53 }; 54 55 enum StreamType { 56 STREAMTYPE_AUDIO = 1 << kAudioIndex, 57 STREAMTYPE_VIDEO = 1 << kVideoIndex, 58 STREAMTYPE_SUBTITLES = 1 << kSubtitleIndex, 59 }; 60 status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit); 61 62 status_t getStreamFormat(StreamType stream, sp<AMessage> *format); 63 64 void connectAsync( 65 const char *url, 66 const KeyedVector<String8, String8> *headers = NULL); 67 68 status_t disconnect(); 69 70 // Blocks until seek is complete. 71 status_t seekTo(int64_t timeUs); 72 73 status_t getDuration(int64_t *durationUs) const; 74 size_t getTrackCount() const; 75 sp<AMessage> getTrackInfo(size_t trackIndex) const; 76 status_t selectTrack(size_t index, bool select); 77 ssize_t getSelectedTrack(media_track_type /* type */) const; 78 79 bool isSeekable() const; 80 bool hasDynamicDuration() const; 81 82 enum { 83 kWhatStreamsChanged, 84 kWhatError, 85 kWhatPrepared, 86 kWhatPreparationFailed, 87 }; 88 89 // create a format-change discontinuity 90 // 91 // swap: 92 // whether is format-change discontinuity should trigger a buffer swap 93 sp<ABuffer> createFormatChangeBuffer(bool swap = true); 94 protected: 95 virtual ~LiveSession(); 96 97 virtual void onMessageReceived(const sp<AMessage> &msg); 98 99 private: 100 friend struct PlaylistFetcher; 101 102 enum { 103 kWhatConnect = 'conn', 104 kWhatDisconnect = 'disc', 105 kWhatSeek = 'seek', 106 kWhatFetcherNotify = 'notf', 107 kWhatCheckBandwidth = 'bndw', 108 kWhatChangeConfiguration = 'chC0', 109 kWhatChangeConfiguration2 = 'chC2', 110 kWhatChangeConfiguration3 = 'chC3', 111 kWhatFinishDisconnect2 = 'fin2', 112 kWhatSwapped = 'swap', 113 kWhatCheckSwitchDown = 'ckSD', 114 kWhatSwitchDown = 'sDwn', 115 }; 116 117 static const size_t kBandwidthHistoryBytes; 118 119 struct BandwidthItem { 120 size_t mPlaylistIndex; 121 unsigned long mBandwidth; 122 }; 123 124 struct FetcherInfo { 125 sp<PlaylistFetcher> mFetcher; 126 int64_t mDurationUs; 127 bool mIsPrepared; 128 bool mToBeRemoved; 129 }; 130 131 struct StreamItem { 132 const char *mType; 133 AString mUri, mNewUri; 134 size_t mCurDiscontinuitySeq; 135 int64_t mLastDequeuedTimeUs; 136 int64_t mLastSampleDurationUs; 137 StreamItem() 138 : mType(""), 139 mCurDiscontinuitySeq(0), 140 mLastDequeuedTimeUs(0), 141 mLastSampleDurationUs(0) {} 142 StreamItem(const char *type) 143 : mType(type), 144 mCurDiscontinuitySeq(0), 145 mLastDequeuedTimeUs(0), 146 mLastSampleDurationUs(0) {} 147 AString uriKey() { 148 AString key(mType); 149 key.append("URI"); 150 return key; 151 } 152 }; 153 StreamItem mStreams[kMaxStreams]; 154 155 sp<AMessage> mNotify; 156 uint32_t mFlags; 157 sp<IMediaHTTPService> mHTTPService; 158 159 bool mInPreparationPhase; 160 bool mBuffering[kMaxStreams]; 161 162 sp<HTTPBase> mHTTPDataSource; 163 KeyedVector<String8, String8> mExtraHeaders; 164 165 AString mMasterURL; 166 167 Vector<BandwidthItem> mBandwidthItems; 168 ssize_t mCurBandwidthIndex; 169 170 sp<M3UParser> mPlaylist; 171 172 KeyedVector<AString, FetcherInfo> mFetcherInfos; 173 uint32_t mStreamMask; 174 175 // Masks used during reconfiguration: 176 // mNewStreamMask: streams in the variant playlist we're switching to; 177 // we don't want to immediately overwrite the original value. 178 uint32_t mNewStreamMask; 179 180 // mSwapMask: streams that have started to playback content in the new variant playlist; 181 // we use this to track reconfiguration progress. 182 uint32_t mSwapMask; 183 184 KeyedVector<StreamType, sp<AnotherPacketSource> > mDiscontinuities; 185 KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources; 186 // A second set of packet sources that buffer content for the variant we're switching to. 187 KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources2; 188 189 // A mutex used to serialize two sets of events: 190 // * the swapping of packet sources in dequeueAccessUnit on the player thread, AND 191 // * a forced bandwidth switch termination in cancelSwitch on the live looper. 192 Mutex mSwapMutex; 193 194 int32_t mCheckBandwidthGeneration; 195 int32_t mSwitchGeneration; 196 int32_t mSubtitleGeneration; 197 198 size_t mContinuationCounter; 199 sp<AMessage> mContinuation; 200 sp<AMessage> mSeekReply; 201 202 int64_t mLastDequeuedTimeUs; 203 int64_t mRealTimeBaseUs; 204 205 bool mReconfigurationInProgress; 206 bool mSwitchInProgress; 207 uint32_t mDisconnectReplyID; 208 uint32_t mSeekReplyID; 209 210 bool mFirstTimeUsValid; 211 int64_t mFirstTimeUs; 212 int64_t mLastSeekTimeUs; 213 sp<AMessage> mSwitchDownMonitor; 214 KeyedVector<size_t, int64_t> mDiscontinuityAbsStartTimesUs; 215 KeyedVector<size_t, int64_t> mDiscontinuityOffsetTimesUs; 216 217 sp<PlaylistFetcher> addFetcher(const char *uri); 218 219 void onConnect(const sp<AMessage> &msg); 220 status_t onSeek(const sp<AMessage> &msg); 221 void onFinishDisconnect2(); 222 223 // If given a non-zero block_size (default 0), it is used to cap the number of 224 // bytes read in from the DataSource. If given a non-NULL buffer, new content 225 // is read into the end. 226 // 227 // The DataSource we read from is responsible for signaling error or EOF to help us 228 // break out of the read loop. The DataSource can be returned to the caller, so 229 // that the caller can reuse it for subsequent fetches (within the initially 230 // requested range). 231 // 232 // For reused HTTP sources, the caller must download a file sequentially without 233 // any overlaps or gaps to prevent reconnection. 234 ssize_t fetchFile( 235 const char *url, sp<ABuffer> *out, 236 /* request/open a file starting at range_offset for range_length bytes */ 237 int64_t range_offset = 0, int64_t range_length = -1, 238 /* download block size */ 239 uint32_t block_size = 0, 240 /* reuse DataSource if doing partial fetch */ 241 sp<DataSource> *source = NULL, 242 String8 *actualUrl = NULL); 243 244 sp<M3UParser> fetchPlaylist( 245 const char *url, uint8_t *curPlaylistHash, bool *unchanged); 246 247 size_t getBandwidthIndex(); 248 int64_t latestMediaSegmentStartTimeUs(); 249 250 static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *); 251 static StreamType indexToType(int idx); 252 static ssize_t typeToIndex(int32_t type); 253 254 void changeConfiguration( 255 int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false); 256 void onChangeConfiguration(const sp<AMessage> &msg); 257 void onChangeConfiguration2(const sp<AMessage> &msg); 258 void onChangeConfiguration3(const sp<AMessage> &msg); 259 void onSwapped(const sp<AMessage> &msg); 260 void onCheckSwitchDown(); 261 void onSwitchDown(); 262 void tryToFinishBandwidthSwitch(); 263 264 void scheduleCheckBandwidthEvent(); 265 void cancelCheckBandwidthEvent(); 266 267 // cancelBandwidthSwitch is atomic wrt swapPacketSource; call it to prevent packet sources 268 // from being swapped out on stale discontinuities while manipulating 269 // mPacketSources/mPacketSources2. 270 void cancelBandwidthSwitch(); 271 272 bool canSwitchBandwidthTo(size_t bandwidthIndex); 273 void onCheckBandwidth(const sp<AMessage> &msg); 274 275 void finishDisconnect(); 276 277 void postPrepared(status_t err); 278 279 void swapPacketSource(StreamType stream); 280 bool canSwitchUp(); 281 282 DISALLOW_EVIL_CONSTRUCTORS(LiveSession); 283 }; 284 285 } // namespace android 286 287 #endif // LIVE_SESSION_H_ 288