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