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 "RTSPSource"
     19 #include <utils/Log.h>
     20 
     21 #include "RTSPSource.h"
     22 
     23 #include "AnotherPacketSource.h"
     24 #include "MyHandler.h"
     25 
     26 #include <media/stagefright/MetaData.h>
     27 
     28 namespace android {
     29 
     30 NuPlayer::RTSPSource::RTSPSource(
     31         const char *url,
     32         const KeyedVector<String8, String8> *headers,
     33         bool uidValid,
     34         uid_t uid)
     35     : mURL(url),
     36       mUIDValid(uidValid),
     37       mUID(uid),
     38       mFlags(0),
     39       mState(DISCONNECTED),
     40       mFinalResult(OK),
     41       mDisconnectReplyID(0),
     42       mSeekGeneration(0) {
     43     if (headers) {
     44         mExtraHeaders = *headers;
     45 
     46         ssize_t index =
     47             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
     48 
     49         if (index >= 0) {
     50             mFlags |= kFlagIncognito;
     51 
     52             mExtraHeaders.removeItemsAt(index);
     53         }
     54     }
     55 }
     56 
     57 NuPlayer::RTSPSource::~RTSPSource() {
     58     if (mLooper != NULL) {
     59         mLooper->stop();
     60     }
     61 }
     62 
     63 void NuPlayer::RTSPSource::start() {
     64     if (mLooper == NULL) {
     65         mLooper = new ALooper;
     66         mLooper->setName("rtsp");
     67         mLooper->start();
     68 
     69         mReflector = new AHandlerReflector<RTSPSource>(this);
     70         mLooper->registerHandler(mReflector);
     71     }
     72 
     73     CHECK(mHandler == NULL);
     74 
     75     sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
     76 
     77     mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
     78     mLooper->registerHandler(mHandler);
     79 
     80     CHECK_EQ(mState, (int)DISCONNECTED);
     81     mState = CONNECTING;
     82 
     83     mHandler->connect();
     84 }
     85 
     86 void NuPlayer::RTSPSource::stop() {
     87     sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
     88 
     89     sp<AMessage> dummy;
     90     msg->postAndAwaitResponse(&dummy);
     91 }
     92 
     93 status_t NuPlayer::RTSPSource::feedMoreTSData() {
     94     return mFinalResult;
     95 }
     96 
     97 sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) {
     98     sp<AnotherPacketSource> source = getSource(audio);
     99 
    100     if (source == NULL) {
    101         return NULL;
    102     }
    103 
    104     return source->getFormat();
    105 }
    106 
    107 status_t NuPlayer::RTSPSource::dequeueAccessUnit(
    108         bool audio, sp<ABuffer> *accessUnit) {
    109     sp<AnotherPacketSource> source = getSource(audio);
    110 
    111     if (source == NULL) {
    112         return -EWOULDBLOCK;
    113     }
    114 
    115     status_t finalResult;
    116     if (!source->hasBufferAvailable(&finalResult)) {
    117         return finalResult == OK ? -EWOULDBLOCK : finalResult;
    118     }
    119 
    120     return source->dequeueAccessUnit(accessUnit);
    121 }
    122 
    123 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
    124     return audio ? mAudioTrack : mVideoTrack;
    125 }
    126 
    127 status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
    128     *durationUs = 0ll;
    129 
    130     int64_t audioDurationUs;
    131     if (mAudioTrack != NULL
    132             && mAudioTrack->getFormat()->findInt64(
    133                 kKeyDuration, &audioDurationUs)
    134             && audioDurationUs > *durationUs) {
    135         *durationUs = audioDurationUs;
    136     }
    137 
    138     int64_t videoDurationUs;
    139     if (mVideoTrack != NULL
    140             && mVideoTrack->getFormat()->findInt64(
    141                 kKeyDuration, &videoDurationUs)
    142             && videoDurationUs > *durationUs) {
    143         *durationUs = videoDurationUs;
    144     }
    145 
    146     return OK;
    147 }
    148 
    149 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
    150     sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
    151     msg->setInt32("generation", ++mSeekGeneration);
    152     msg->setInt64("timeUs", seekTimeUs);
    153     msg->post(200000ll);
    154 
    155     return OK;
    156 }
    157 
    158 void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
    159     if (mState != CONNECTED) {
    160         return;
    161     }
    162 
    163     mState = SEEKING;
    164     mHandler->seek(seekTimeUs);
    165 }
    166 
    167 bool NuPlayer::RTSPSource::isSeekable() {
    168     return true;
    169 }
    170 
    171 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    172     if (msg->what() == kWhatDisconnect) {
    173         uint32_t replyID;
    174         CHECK(msg->senderAwaitsResponse(&replyID));
    175 
    176         mDisconnectReplyID = replyID;
    177         finishDisconnectIfPossible();
    178         return;
    179     } else if (msg->what() == kWhatPerformSeek) {
    180         int32_t generation;
    181         CHECK(msg->findInt32("generation", &generation));
    182 
    183         if (generation != mSeekGeneration) {
    184             // obsolete.
    185             return;
    186         }
    187 
    188         int64_t seekTimeUs;
    189         CHECK(msg->findInt64("timeUs", &seekTimeUs));
    190 
    191         performSeek(seekTimeUs);
    192         return;
    193     }
    194 
    195     CHECK_EQ(msg->what(), (int)kWhatNotify);
    196 
    197     int32_t what;
    198     CHECK(msg->findInt32("what", &what));
    199 
    200     switch (what) {
    201         case MyHandler::kWhatConnected:
    202             onConnected();
    203             break;
    204 
    205         case MyHandler::kWhatDisconnected:
    206             onDisconnected(msg);
    207             break;
    208 
    209         case MyHandler::kWhatSeekDone:
    210         {
    211             mState = CONNECTED;
    212             break;
    213         }
    214 
    215         case MyHandler::kWhatAccessUnit:
    216         {
    217             size_t trackIndex;
    218             CHECK(msg->findSize("trackIndex", &trackIndex));
    219             CHECK_LT(trackIndex, mTracks.size());
    220 
    221             sp<RefBase> obj;
    222             CHECK(msg->findObject("accessUnit", &obj));
    223 
    224             sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
    225 
    226             int32_t damaged;
    227             if (accessUnit->meta()->findInt32("damaged", &damaged)
    228                     && damaged) {
    229                 LOGI("dropping damaged access unit.");
    230                 break;
    231             }
    232 
    233             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    234 
    235             sp<AnotherPacketSource> source = info->mSource;
    236             if (source != NULL) {
    237                 uint32_t rtpTime;
    238                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
    239 
    240                 if (!info->mNPTMappingValid) {
    241                     // This is a live stream, we didn't receive any normal
    242                     // playtime mapping. Assume the first packets correspond
    243                     // to time 0.
    244 
    245                     LOGV("This is a live stream, assuming time = 0");
    246 
    247                     info->mRTPTime = rtpTime;
    248                     info->mNormalPlaytimeUs = 0ll;
    249                     info->mNPTMappingValid = true;
    250                 }
    251 
    252                 int64_t nptUs =
    253                     ((double)rtpTime - (double)info->mRTPTime)
    254                         / info->mTimeScale
    255                         * 1000000ll
    256                         + info->mNormalPlaytimeUs;
    257 
    258                 accessUnit->meta()->setInt64("timeUs", nptUs);
    259 
    260                 source->queueAccessUnit(accessUnit);
    261             }
    262             break;
    263         }
    264 
    265         case MyHandler::kWhatEOS:
    266         {
    267             size_t trackIndex;
    268             CHECK(msg->findSize("trackIndex", &trackIndex));
    269             CHECK_LT(trackIndex, mTracks.size());
    270 
    271             int32_t finalResult;
    272             CHECK(msg->findInt32("finalResult", &finalResult));
    273             CHECK_NE(finalResult, (status_t)OK);
    274 
    275             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    276             sp<AnotherPacketSource> source = info->mSource;
    277             if (source != NULL) {
    278                 source->signalEOS(finalResult);
    279             }
    280 
    281             break;
    282         }
    283 
    284         case MyHandler::kWhatSeekDiscontinuity:
    285         {
    286             size_t trackIndex;
    287             CHECK(msg->findSize("trackIndex", &trackIndex));
    288             CHECK_LT(trackIndex, mTracks.size());
    289 
    290             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    291             sp<AnotherPacketSource> source = info->mSource;
    292             if (source != NULL) {
    293                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
    294             }
    295 
    296             break;
    297         }
    298 
    299         case MyHandler::kWhatNormalPlayTimeMapping:
    300         {
    301             size_t trackIndex;
    302             CHECK(msg->findSize("trackIndex", &trackIndex));
    303             CHECK_LT(trackIndex, mTracks.size());
    304 
    305             uint32_t rtpTime;
    306             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
    307 
    308             int64_t nptUs;
    309             CHECK(msg->findInt64("nptUs", &nptUs));
    310 
    311             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    312             info->mRTPTime = rtpTime;
    313             info->mNormalPlaytimeUs = nptUs;
    314             info->mNPTMappingValid = true;
    315             break;
    316         }
    317 
    318         default:
    319             TRESPASS();
    320     }
    321 }
    322 
    323 void NuPlayer::RTSPSource::onConnected() {
    324     CHECK(mAudioTrack == NULL);
    325     CHECK(mVideoTrack == NULL);
    326 
    327     size_t numTracks = mHandler->countTracks();
    328     for (size_t i = 0; i < numTracks; ++i) {
    329         int32_t timeScale;
    330         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
    331 
    332         const char *mime;
    333         CHECK(format->findCString(kKeyMIMEType, &mime));
    334 
    335         bool isAudio = !strncasecmp(mime, "audio/", 6);
    336         bool isVideo = !strncasecmp(mime, "video/", 6);
    337 
    338         TrackInfo info;
    339         info.mTimeScale = timeScale;
    340         info.mRTPTime = 0;
    341         info.mNormalPlaytimeUs = 0ll;
    342         info.mNPTMappingValid = false;
    343 
    344         if ((isAudio && mAudioTrack == NULL)
    345                 || (isVideo && mVideoTrack == NULL)) {
    346             sp<AnotherPacketSource> source = new AnotherPacketSource(format);
    347 
    348             if (isAudio) {
    349                 mAudioTrack = source;
    350             } else {
    351                 mVideoTrack = source;
    352             }
    353 
    354             info.mSource = source;
    355         }
    356 
    357         mTracks.push(info);
    358     }
    359 
    360     mState = CONNECTED;
    361 }
    362 
    363 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
    364     status_t err;
    365     CHECK(msg->findInt32("result", &err));
    366     CHECK_NE(err, (status_t)OK);
    367 
    368     mLooper->unregisterHandler(mHandler->id());
    369     mHandler.clear();
    370 
    371     mState = DISCONNECTED;
    372     mFinalResult = err;
    373 
    374     if (mDisconnectReplyID != 0) {
    375         finishDisconnectIfPossible();
    376     }
    377 }
    378 
    379 void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
    380     if (mState != DISCONNECTED) {
    381         mHandler->disconnect();
    382         return;
    383     }
    384 
    385     (new AMessage)->postReply(mDisconnectReplyID);
    386     mDisconnectReplyID = 0;
    387 }
    388 
    389 }  // namespace android
    390