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