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 #include "LiveSession.h"
     26 
     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 
     33 namespace android {
     34 
     35 NuPlayer::HTTPLiveSource::HTTPLiveSource(
     36         const sp<AMessage> &notify,
     37         const char *url,
     38         const KeyedVector<String8, String8> *headers,
     39         bool uidValid, uid_t uid)
     40     : Source(notify),
     41       mURL(url),
     42       mUIDValid(uidValid),
     43       mUID(uid),
     44       mFlags(0),
     45       mFinalResult(OK),
     46       mOffset(0),
     47       mFetchSubtitleDataGeneration(0) {
     48     if (headers) {
     49         mExtraHeaders = *headers;
     50 
     51         ssize_t index =
     52             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
     53 
     54         if (index >= 0) {
     55             mFlags |= kFlagIncognito;
     56 
     57             mExtraHeaders.removeItemsAt(index);
     58         }
     59     }
     60 }
     61 
     62 NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
     63     if (mLiveSession != NULL) {
     64         mLiveSession->disconnect();
     65         mLiveSession.clear();
     66 
     67         mLiveLooper->stop();
     68         mLiveLooper.clear();
     69     }
     70 }
     71 
     72 void NuPlayer::HTTPLiveSource::prepareAsync() {
     73     mLiveLooper = new ALooper;
     74     mLiveLooper->setName("http live");
     75     mLiveLooper->start();
     76 
     77     sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
     78 
     79     mLiveSession = new LiveSession(
     80             notify,
     81             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
     82             mUIDValid,
     83             mUID);
     84 
     85     mLiveLooper->registerHandler(mLiveSession);
     86 
     87     mLiveSession->connectAsync(
     88             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
     89 }
     90 
     91 void NuPlayer::HTTPLiveSource::start() {
     92 }
     93 
     94 sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
     95     sp<AMessage> format;
     96     status_t err = mLiveSession->getStreamFormat(
     97             audio ? LiveSession::STREAMTYPE_AUDIO
     98                   : LiveSession::STREAMTYPE_VIDEO,
     99             &format);
    100 
    101     if (err != OK) {
    102         return NULL;
    103     }
    104 
    105     return format;
    106 }
    107 
    108 status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
    109     return OK;
    110 }
    111 
    112 status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
    113         bool audio, sp<ABuffer> *accessUnit) {
    114     return mLiveSession->dequeueAccessUnit(
    115             audio ? LiveSession::STREAMTYPE_AUDIO
    116                   : LiveSession::STREAMTYPE_VIDEO,
    117             accessUnit);
    118 }
    119 
    120 status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
    121     return mLiveSession->getDuration(durationUs);
    122 }
    123 
    124 status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
    125     return mLiveSession->getTrackInfo(reply);
    126 }
    127 
    128 status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
    129     status_t err = mLiveSession->selectTrack(trackIndex, select);
    130 
    131     if (err == OK) {
    132         mFetchSubtitleDataGeneration++;
    133         if (select) {
    134             sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
    135             msg->setInt32("generation", mFetchSubtitleDataGeneration);
    136             msg->post();
    137         }
    138     }
    139 
    140     // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
    141     // selected track, or unselecting a non-selected track. In this case it's an
    142     // no-op so we return OK.
    143     return (err == OK || err == BAD_VALUE) ? OK : err;
    144 }
    145 
    146 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
    147     return mLiveSession->seekTo(seekTimeUs);
    148 }
    149 
    150 void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
    151     switch (msg->what()) {
    152         case kWhatSessionNotify:
    153         {
    154             onSessionNotify(msg);
    155             break;
    156         }
    157 
    158         case kWhatFetchSubtitleData:
    159         {
    160             int32_t generation;
    161             CHECK(msg->findInt32("generation", &generation));
    162 
    163             if (generation != mFetchSubtitleDataGeneration) {
    164                 // stale
    165                 break;
    166             }
    167 
    168             sp<ABuffer> buffer;
    169             if (mLiveSession->dequeueAccessUnit(
    170                     LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) {
    171                 sp<AMessage> notify = dupNotify();
    172                 notify->setInt32("what", kWhatSubtitleData);
    173                 notify->setBuffer("buffer", buffer);
    174                 notify->post();
    175 
    176                 int64_t timeUs, baseUs, durationUs, delayUs;
    177                 CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
    178                 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
    179                 CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
    180                 delayUs = baseUs + timeUs - ALooper::GetNowUs();
    181 
    182                 msg->post(delayUs > 0ll ? delayUs : 0ll);
    183             } else {
    184                 // try again in 1 second
    185                 msg->post(1000000ll);
    186             }
    187 
    188             break;
    189         }
    190 
    191         default:
    192             Source::onMessageReceived(msg);
    193             break;
    194     }
    195 }
    196 
    197 void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
    198     int32_t what;
    199     CHECK(msg->findInt32("what", &what));
    200 
    201     switch (what) {
    202         case LiveSession::kWhatPrepared:
    203         {
    204             // notify the current size here if we have it, otherwise report an initial size of (0,0)
    205             sp<AMessage> format = getFormat(false /* audio */);
    206             int32_t width;
    207             int32_t height;
    208             if (format != NULL &&
    209                     format->findInt32("width", &width) && format->findInt32("height", &height)) {
    210                 notifyVideoSizeChanged(width, height);
    211             } else {
    212                 notifyVideoSizeChanged(0, 0);
    213             }
    214 
    215             uint32_t flags = FLAG_CAN_PAUSE;
    216             if (mLiveSession->isSeekable()) {
    217                 flags |= FLAG_CAN_SEEK;
    218                 flags |= FLAG_CAN_SEEK_BACKWARD;
    219                 flags |= FLAG_CAN_SEEK_FORWARD;
    220             }
    221 
    222             if (mLiveSession->hasDynamicDuration()) {
    223                 flags |= FLAG_DYNAMIC_DURATION;
    224             }
    225 
    226             notifyFlagsChanged(flags);
    227 
    228             notifyPrepared();
    229             break;
    230         }
    231 
    232         case LiveSession::kWhatPreparationFailed:
    233         {
    234             status_t err;
    235             CHECK(msg->findInt32("err", &err));
    236 
    237             notifyPrepared(err);
    238             break;
    239         }
    240 
    241         case LiveSession::kWhatStreamsChanged:
    242         {
    243             uint32_t changedMask;
    244             CHECK(msg->findInt32(
    245                         "changedMask", (int32_t *)&changedMask));
    246 
    247             bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
    248             bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
    249 
    250             sp<AMessage> reply;
    251             CHECK(msg->findMessage("reply", &reply));
    252 
    253             sp<AMessage> notify = dupNotify();
    254             notify->setInt32("what", kWhatQueueDecoderShutdown);
    255             notify->setInt32("audio", audio);
    256             notify->setInt32("video", video);
    257             notify->setMessage("reply", reply);
    258             notify->post();
    259             break;
    260         }
    261 
    262         case LiveSession::kWhatError:
    263         {
    264             break;
    265         }
    266 
    267         default:
    268             TRESPASS();
    269     }
    270 }
    271 
    272 }  // namespace android
    273 
    274