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