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