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 "ATSParser.h"
     24 #include "AnotherPacketSource.h"
     25 #include "LiveDataSource.h"
     26 #include "LiveSession.h"
     27 
     28 #include <media/stagefright/foundation/ABuffer.h>
     29 #include <media/stagefright/foundation/ADebug.h>
     30 #include <media/stagefright/foundation/AMessage.h>
     31 #include <media/stagefright/MediaErrors.h>
     32 #include <media/stagefright/MetaData.h>
     33 
     34 namespace android {
     35 
     36 NuPlayer::HTTPLiveSource::HTTPLiveSource(
     37         const sp<AMessage> &notify,
     38         const char *url,
     39         const KeyedVector<String8, String8> *headers,
     40         bool uidValid, uid_t uid)
     41     : Source(notify),
     42       mURL(url),
     43       mUIDValid(uidValid),
     44       mUID(uid),
     45       mFlags(0),
     46       mFinalResult(OK),
     47       mOffset(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         mLiveLooper->stop();
     66     }
     67 }
     68 
     69 void NuPlayer::HTTPLiveSource::prepareAsync() {
     70     mLiveLooper = new ALooper;
     71     mLiveLooper->setName("http live");
     72     mLiveLooper->start();
     73 
     74     sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
     75 
     76     mLiveSession = new LiveSession(
     77             notify,
     78             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
     79             mUIDValid, mUID);
     80 
     81     mLiveLooper->registerHandler(mLiveSession);
     82 
     83     mLiveSession->connect(
     84             mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
     85 
     86     mTSParser = new ATSParser;
     87 }
     88 
     89 void NuPlayer::HTTPLiveSource::start() {
     90 }
     91 
     92 sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
     93     ATSParser::SourceType type =
     94         audio ? ATSParser::AUDIO : ATSParser::VIDEO;
     95 
     96     sp<AnotherPacketSource> source =
     97         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
     98 
     99     if (source == NULL) {
    100         return NULL;
    101     }
    102 
    103     return source->getFormat();
    104 }
    105 
    106 status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
    107     if (mFinalResult != OK) {
    108         return mFinalResult;
    109     }
    110 
    111     sp<LiveDataSource> source =
    112         static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());
    113 
    114     for (int32_t i = 0; i < 50; ++i) {
    115         char buffer[188];
    116         ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));
    117 
    118         if (n == -EWOULDBLOCK) {
    119             break;
    120         } else if (n < 0) {
    121             if (n != ERROR_END_OF_STREAM) {
    122                 ALOGI("input data EOS reached, error %ld", n);
    123             } else {
    124                 ALOGI("input data EOS reached.");
    125             }
    126             mTSParser->signalEOS(n);
    127             mFinalResult = n;
    128             break;
    129         } else {
    130             if (buffer[0] == 0x00) {
    131                 // XXX legacy
    132 
    133                 uint8_t type = buffer[1];
    134 
    135                 sp<AMessage> extra = new AMessage;
    136 
    137                 if (type & 2) {
    138                     int64_t mediaTimeUs;
    139                     memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
    140 
    141                     extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
    142                 }
    143 
    144                 mTSParser->signalDiscontinuity(
    145                         ((type & 1) == 0)
    146                             ? ATSParser::DISCONTINUITY_SEEK
    147                             : ATSParser::DISCONTINUITY_FORMATCHANGE,
    148                         extra);
    149             } else {
    150                 status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
    151 
    152                 if (err != OK) {
    153                     ALOGE("TS Parser returned error %d", err);
    154                     mTSParser->signalEOS(err);
    155                     mFinalResult = err;
    156                     break;
    157                 }
    158             }
    159 
    160             mOffset += n;
    161         }
    162     }
    163 
    164     return OK;
    165 }
    166 
    167 status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
    168         bool audio, sp<ABuffer> *accessUnit) {
    169     ATSParser::SourceType type =
    170         audio ? ATSParser::AUDIO : ATSParser::VIDEO;
    171 
    172     sp<AnotherPacketSource> source =
    173         static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
    174 
    175     if (source == NULL) {
    176         return -EWOULDBLOCK;
    177     }
    178 
    179     status_t finalResult;
    180     if (!source->hasBufferAvailable(&finalResult)) {
    181         return finalResult == OK ? -EWOULDBLOCK : finalResult;
    182     }
    183 
    184     return source->dequeueAccessUnit(accessUnit);
    185 }
    186 
    187 status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
    188     return mLiveSession->getDuration(durationUs);
    189 }
    190 
    191 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
    192     // We need to make sure we're not seeking until we have seen the very first
    193     // PTS timestamp in the whole stream (from the beginning of the stream).
    194     while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) {
    195         usleep(100000);
    196     }
    197 
    198     mLiveSession->seekTo(seekTimeUs);
    199 
    200     return OK;
    201 }
    202 
    203 void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
    204     switch (msg->what()) {
    205         case kWhatSessionNotify:
    206         {
    207             onSessionNotify(msg);
    208             break;
    209         }
    210 
    211         default:
    212             Source::onMessageReceived(msg);
    213             break;
    214     }
    215 }
    216 
    217 void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
    218     int32_t what;
    219     CHECK(msg->findInt32("what", &what));
    220 
    221     switch (what) {
    222         case LiveSession::kWhatPrepared:
    223         {
    224             notifyVideoSizeChanged(0, 0);
    225 
    226             uint32_t flags = FLAG_CAN_PAUSE;
    227             if (mLiveSession->isSeekable()) {
    228                 flags |= FLAG_CAN_SEEK;
    229                 flags |= FLAG_CAN_SEEK_BACKWARD;
    230                 flags |= FLAG_CAN_SEEK_FORWARD;
    231             }
    232 
    233             if (mLiveSession->hasDynamicDuration()) {
    234                 flags |= FLAG_DYNAMIC_DURATION;
    235             }
    236 
    237             notifyFlagsChanged(flags);
    238 
    239             notifyPrepared();
    240             break;
    241         }
    242 
    243         case LiveSession::kWhatPreparationFailed:
    244         {
    245             status_t err;
    246             CHECK(msg->findInt32("err", &err));
    247 
    248             notifyPrepared(err);
    249             break;
    250         }
    251 
    252         default:
    253             TRESPASS();
    254     }
    255 }
    256 
    257 }  // namespace android
    258 
    259