Home | History | Annotate | Download | only in httplive
      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> &notify,
     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