Home | History | Annotate | Download | only in nuplayer
      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 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "HTTPLiveSource"
     19 #include <utils/Log.h>
     20 
     21 #include "HTTPLiveSource.h"
     22 
     23 #include "AnotherPacketSource.h"
     24 #include "LiveDataSource.h"
     25 
     26 #include <media/IMediaHTTPService.h>
     27 #include <media/stagefright/foundation/ABuffer.h>
     28 #include <media/stagefright/foundation/ADebug.h>
     29 #include <media/stagefright/foundation/AMessage.h>
     30 #include <media/stagefright/MediaErrors.h>
     31 #include <media/stagefright/MetaData.h>
     32 #include <media/stagefright/MediaDefs.h>
     33 #include <media/stagefright/Utils.h>
     34 
     35 // default buffer prepare/ready/underflow marks
     36 static const int kReadyMarkMs     = 5000;  // 5 seconds
     37 static const int kPrepareMarkMs   = 1500;  // 1.5 seconds
     38 static const int kUnderflowMarkMs = 1000;  // 1 second
     39 
     40 namespace android {
     41 
     42 NuPlayer::HTTPLiveSource::HTTPLiveSource(
     43         const sp<AMessage> &notify,
     44         const sp<IMediaHTTPService> &httpService,
     45         const char *url,
     46         const KeyedVector<String8, String8> *headers)
     47     : Source(notify),
     48       mHTTPService(httpService),
     49       mURL(url),
     50       mFlags(0),
     51       mFinalResult(OK),
     52       mOffset(0),
     53       mFetchSubtitleDataGeneration(0),
     54       mFetchMetaDataGeneration(0),
     55       mHasMetadata(false),
     56       mMetadataSelected(false) {
     57     getDefaultBufferingSettings(&mBufferingSettings);
     58     if (headers) {
     59         mExtraHeaders = *headers;
     60 
     61         ssize_t index =
     62             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
     63 
     64         if (index >= 0) {
     65             mFlags |= kFlagIncognito;
     66 
     67             mExtraHeaders.removeItemsAt(index);
     68         }
     69     }
     70 }
     71 
     72 NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
     73     if (mLiveSession != NULL) {
     74         mLiveSession->disconnect();
     75 
     76         mLiveLooper->unregisterHandler(mLiveSession->id());
     77         mLiveLooper->unregisterHandler(id());
     78         mLiveLooper->stop();
     79 
     80         mLiveSession.clear();
     81         mLiveLooper.clear();
     82     }
     83 }
     84 
     85 status_t NuPlayer::HTTPLiveSource::getDefaultBufferingSettings(
     86             BufferingSettings* buffering /* nonnull */) {
     87     buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
     88     buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
     89     buffering->mInitialWatermarkMs = kPrepareMarkMs;
     90     buffering->mRebufferingWatermarkLowMs = kUnderflowMarkMs;
     91     buffering->mRebufferingWatermarkHighMs = kReadyMarkMs;
     92 
     93     return OK;
     94 }
     95 
     96 status_t NuPlayer::HTTPLiveSource::setBufferingSettings(const BufferingSettings& buffering) {
     97     if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
     98             || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
     99             || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
    100                 && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
    101         return BAD_VALUE;
    102     }
    103 
    104     mBufferingSettings = buffering;
    105 
    106     if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
    107         mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
    108     }
    109     if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
    110         mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
    111         mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
    112     }
    113 
    114     if (mLiveSession != NULL) {
    115         mLiveSession->setBufferingSettings(mBufferingSettings);
    116     }
    117 
    118     return OK;
    119 }
    120 
    121 void NuPlayer::HTTPLiveSource::prepareAsync() {
    122     if (mLiveLooper == NULL) {
    123         mLiveLooper = new ALooper;
    124         mLiveLooper->setName("http live");
    125         mLiveLooper->start();
    126 
    127         mLiveLooper->registerHandler(this);
    128     }
    129 
    130     sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
    131 
    132     mLiveSession = new LiveSession(
    133             notify,
    134             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
    135             mHTTPService);
    136 
    137     mLiveLooper->registerHandler(mLiveSession);
    138 
    139     mLiveSession->setBufferingSettings(mBufferingSettings);
    140     mLiveSession->connectAsync(
    141             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
    142 }
    143 
    144 void NuPlayer::HTTPLiveSource::start() {
    145 }
    146 
    147 sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
    148     sp<MetaData> meta;
    149     if (mLiveSession != NULL) {
    150         mLiveSession->getStreamFormatMeta(
    151                 audio ? LiveSession::STREAMTYPE_AUDIO
    152                       : LiveSession::STREAMTYPE_VIDEO,
    153                 &meta);
    154     }
    155 
    156     return meta;
    157 }
    158 
    159 sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
    160     sp<MetaData> meta;
    161     status_t err = -EWOULDBLOCK;
    162     if (mLiveSession != NULL) {
    163         err = mLiveSession->getStreamFormatMeta(
    164                 audio ? LiveSession::STREAMTYPE_AUDIO
    165                       : LiveSession::STREAMTYPE_VIDEO,
    166                 &meta);
    167     }
    168 
    169     sp<AMessage> format;
    170     if (err == -EWOULDBLOCK) {
    171         format = new AMessage();
    172         format->setInt32("err", err);
    173         return format;
    174     }
    175 
    176     if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
    177         return NULL;
    178     }
    179     return format;
    180 }
    181 
    182 status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
    183     return OK;
    184 }
    185 
    186 status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
    187         bool audio, sp<ABuffer> *accessUnit) {
    188     return mLiveSession->dequeueAccessUnit(
    189             audio ? LiveSession::STREAMTYPE_AUDIO
    190                   : LiveSession::STREAMTYPE_VIDEO,
    191             accessUnit);
    192 }
    193 
    194 status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
    195     return mLiveSession->getDuration(durationUs);
    196 }
    197 
    198 size_t NuPlayer::HTTPLiveSource::getTrackCount() const {
    199     return mLiveSession->getTrackCount();
    200 }
    201 
    202 sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const {
    203     return mLiveSession->getTrackInfo(trackIndex);
    204 }
    205 
    206 ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const {
    207     if (mLiveSession == NULL) {
    208         return -1;
    209     } else if (type == MEDIA_TRACK_TYPE_METADATA) {
    210         // MEDIA_TRACK_TYPE_METADATA is always last track
    211         // mMetadataSelected can only be true when mHasMetadata is true
    212         return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1;
    213     } else {
    214         return mLiveSession->getSelectedTrack(type);
    215     }
    216 }
    217 
    218 status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
    219     if (mLiveSession == NULL) {
    220         return INVALID_OPERATION;
    221     }
    222 
    223     status_t err = INVALID_OPERATION;
    224     bool postFetchMsg = false, isSub = false;
    225     if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
    226         err = mLiveSession->selectTrack(trackIndex, select);
    227         postFetchMsg = select;
    228         isSub = true;
    229     } else {
    230         // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1)
    231         if (mMetadataSelected && !select) {
    232             err = OK;
    233         } else if (!mMetadataSelected && select) {
    234             postFetchMsg = true;
    235             err = OK;
    236         } else {
    237             err = BAD_VALUE; // behave as LiveSession::selectTrack
    238         }
    239 
    240         mMetadataSelected = select;
    241     }
    242 
    243     if (err == OK) {
    244         int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration;
    245         generation++;
    246         if (postFetchMsg) {
    247             int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData;
    248             sp<AMessage> msg = new AMessage(what, this);
    249             msg->setInt32("generation", generation);
    250             msg->post();
    251         }
    252     }
    253 
    254     // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
    255     // selected track, or unselecting a non-selected track. In this case it's an
    256     // no-op so we return OK.
    257     return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
    258 }
    259 
    260 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
    261     if (mLiveSession->isSeekable()) {
    262         return mLiveSession->seekTo(seekTimeUs, mode);
    263     } else {
    264         return INVALID_OPERATION;
    265     }
    266 }
    267 
    268 void NuPlayer::HTTPLiveSource::pollForRawData(
    269         const sp<AMessage> &msg, int32_t currentGeneration,
    270         LiveSession::StreamType fetchType, int32_t pushWhat) {
    271 
    272     int32_t generation;
    273     CHECK(msg->findInt32("generation", &generation));
    274 
    275     if (generation != currentGeneration) {
    276         return;
    277     }
    278 
    279     sp<ABuffer> buffer;
    280     while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
    281 
    282         sp<AMessage> notify = dupNotify();
    283         notify->setInt32("what", pushWhat);
    284         notify->setBuffer("buffer", buffer);
    285 
    286         int64_t timeUs, baseUs, delayUs;
    287         CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
    288         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
    289         delayUs = baseUs + timeUs - ALooper::GetNowUs();
    290 
    291         if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
    292             notify->post();
    293             msg->post(delayUs > 0ll ? delayUs : 0ll);
    294             return;
    295         } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
    296             if (delayUs < -1000000ll) { // 1 second
    297                 continue;
    298             }
    299             notify->post();
    300             // push all currently available metadata buffers in each invocation of pollForRawData
    301             // continue;
    302         } else {
    303             TRESPASS();
    304         }
    305     }
    306 
    307     // try again in 1 second
    308     msg->post(1000000ll);
    309 }
    310 
    311 void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
    312     switch (msg->what()) {
    313         case kWhatSessionNotify:
    314         {
    315             onSessionNotify(msg);
    316             break;
    317         }
    318 
    319         case kWhatFetchSubtitleData:
    320         {
    321             pollForRawData(
    322                     msg, mFetchSubtitleDataGeneration,
    323                     /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
    324                     /* push */ kWhatSubtitleData);
    325 
    326             break;
    327         }
    328 
    329         case kWhatFetchMetaData:
    330         {
    331             if (!mMetadataSelected) {
    332                 break;
    333             }
    334 
    335             pollForRawData(
    336                     msg, mFetchMetaDataGeneration,
    337                     /* fetch */ LiveSession::STREAMTYPE_METADATA,
    338                     /* push */ kWhatTimedMetaData);
    339 
    340             break;
    341         }
    342 
    343         default:
    344             Source::onMessageReceived(msg);
    345             break;
    346     }
    347 }
    348 
    349 void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
    350     int32_t what;
    351     CHECK(msg->findInt32("what", &what));
    352 
    353     switch (what) {
    354         case LiveSession::kWhatPrepared:
    355         {
    356             // notify the current size here if we have it, otherwise report an initial size of (0,0)
    357             sp<AMessage> format = getFormat(false /* audio */);
    358             int32_t width;
    359             int32_t height;
    360             if (format != NULL &&
    361                     format->findInt32("width", &width) && format->findInt32("height", &height)) {
    362                 notifyVideoSizeChanged(format);
    363             } else {
    364                 notifyVideoSizeChanged();
    365             }
    366 
    367             uint32_t flags = 0;
    368             if (mLiveSession->isSeekable()) {
    369                 flags |= FLAG_CAN_PAUSE;
    370                 flags |= FLAG_CAN_SEEK;
    371                 flags |= FLAG_CAN_SEEK_BACKWARD;
    372                 flags |= FLAG_CAN_SEEK_FORWARD;
    373             }
    374 
    375             if (mLiveSession->hasDynamicDuration()) {
    376                 flags |= FLAG_DYNAMIC_DURATION;
    377             }
    378 
    379             notifyFlagsChanged(flags);
    380 
    381             notifyPrepared();
    382             break;
    383         }
    384 
    385         case LiveSession::kWhatPreparationFailed:
    386         {
    387             status_t err;
    388             CHECK(msg->findInt32("err", &err));
    389 
    390             notifyPrepared(err);
    391             break;
    392         }
    393 
    394         case LiveSession::kWhatStreamsChanged:
    395         {
    396             uint32_t changedMask;
    397             CHECK(msg->findInt32(
    398                         "changedMask", (int32_t *)&changedMask));
    399 
    400             bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
    401             bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
    402 
    403             sp<AMessage> reply;
    404             CHECK(msg->findMessage("reply", &reply));
    405 
    406             sp<AMessage> notify = dupNotify();
    407             notify->setInt32("what", kWhatQueueDecoderShutdown);
    408             notify->setInt32("audio", audio);
    409             notify->setInt32("video", video);
    410             notify->setMessage("reply", reply);
    411             notify->post();
    412             break;
    413         }
    414 
    415         case LiveSession::kWhatBufferingStart:
    416         {
    417             sp<AMessage> notify = dupNotify();
    418             notify->setInt32("what", kWhatPauseOnBufferingStart);
    419             notify->post();
    420             break;
    421         }
    422 
    423         case LiveSession::kWhatBufferingEnd:
    424         {
    425             sp<AMessage> notify = dupNotify();
    426             notify->setInt32("what", kWhatResumeOnBufferingEnd);
    427             notify->post();
    428             break;
    429         }
    430 
    431 
    432         case LiveSession::kWhatBufferingUpdate:
    433         {
    434             sp<AMessage> notify = dupNotify();
    435             int32_t percentage;
    436             CHECK(msg->findInt32("percentage", &percentage));
    437             notify->setInt32("what", kWhatBufferingUpdate);
    438             notify->setInt32("percentage", percentage);
    439             notify->post();
    440             break;
    441         }
    442 
    443         case LiveSession::kWhatMetadataDetected:
    444         {
    445             if (!mHasMetadata) {
    446                 mHasMetadata = true;
    447 
    448                 sp<AMessage> notify = dupNotify();
    449                 // notification without buffer triggers MEDIA_INFO_METADATA_UPDATE
    450                 notify->setInt32("what", kWhatTimedMetaData);
    451                 notify->post();
    452             }
    453             break;
    454         }
    455 
    456         case LiveSession::kWhatError:
    457         {
    458             break;
    459         }
    460 
    461         default:
    462             TRESPASS();
    463     }
    464 }
    465 
    466 }  // namespace android
    467 
    468