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