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