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 #include "SDPLoader.h"
     26 
     27 #include <media/IMediaHTTPService.h>
     28 #include <media/stagefright/MediaDefs.h>
     29 #include <media/stagefright/MetaData.h>
     30 
     31 namespace android {
     32 
     33 const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs
     34 
     35 NuPlayer::RTSPSource::RTSPSource(
     36         const sp<AMessage> &notify,
     37         const sp<IMediaHTTPService> &httpService,
     38         const char *url,
     39         const KeyedVector<String8, String8> *headers,
     40         bool uidValid,
     41         uid_t uid,
     42         bool isSDP)
     43     : Source(notify),
     44       mHTTPService(httpService),
     45       mURL(url),
     46       mUIDValid(uidValid),
     47       mUID(uid),
     48       mFlags(0),
     49       mIsSDP(isSDP),
     50       mState(DISCONNECTED),
     51       mFinalResult(OK),
     52       mDisconnectReplyID(0),
     53       mBuffering(true),
     54       mSeekGeneration(0),
     55       mEOSTimeoutAudio(0),
     56       mEOSTimeoutVideo(0) {
     57     if (headers) {
     58         mExtraHeaders = *headers;
     59 
     60         ssize_t index =
     61             mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
     62 
     63         if (index >= 0) {
     64             mFlags |= kFlagIncognito;
     65 
     66             mExtraHeaders.removeItemsAt(index);
     67         }
     68     }
     69 }
     70 
     71 NuPlayer::RTSPSource::~RTSPSource() {
     72     if (mLooper != NULL) {
     73         mLooper->unregisterHandler(id());
     74         mLooper->stop();
     75     }
     76 }
     77 
     78 void NuPlayer::RTSPSource::prepareAsync() {
     79     if (mLooper == NULL) {
     80         mLooper = new ALooper;
     81         mLooper->setName("rtsp");
     82         mLooper->start();
     83 
     84         mLooper->registerHandler(this);
     85     }
     86 
     87     CHECK(mHandler == NULL);
     88     CHECK(mSDPLoader == NULL);
     89 
     90     sp<AMessage> notify = new AMessage(kWhatNotify, id());
     91 
     92     CHECK_EQ(mState, (int)DISCONNECTED);
     93     mState = CONNECTING;
     94 
     95     if (mIsSDP) {
     96         mSDPLoader = new SDPLoader(notify,
     97                 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
     98                 mHTTPService);
     99 
    100         mSDPLoader->load(
    101                 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
    102     } else {
    103         mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
    104         mLooper->registerHandler(mHandler);
    105 
    106         mHandler->connect();
    107     }
    108 
    109     sp<AMessage> notifyStart = dupNotify();
    110     notifyStart->setInt32("what", kWhatBufferingStart);
    111     notifyStart->post();
    112 }
    113 
    114 void NuPlayer::RTSPSource::start() {
    115 }
    116 
    117 void NuPlayer::RTSPSource::stop() {
    118     if (mLooper == NULL) {
    119         return;
    120     }
    121     sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
    122 
    123     sp<AMessage> dummy;
    124     msg->postAndAwaitResponse(&dummy);
    125 }
    126 
    127 void NuPlayer::RTSPSource::pause() {
    128     int64_t mediaDurationUs = 0;
    129     getDuration(&mediaDurationUs);
    130     for (size_t index = 0; index < mTracks.size(); index++) {
    131         TrackInfo *info = &mTracks.editItemAt(index);
    132         sp<AnotherPacketSource> source = info->mSource;
    133 
    134         // Check if EOS or ERROR is received
    135         if (source != NULL && source->isFinished(mediaDurationUs)) {
    136             return;
    137         }
    138     }
    139     mHandler->pause();
    140 }
    141 
    142 void NuPlayer::RTSPSource::resume() {
    143     mHandler->resume();
    144 }
    145 
    146 status_t NuPlayer::RTSPSource::feedMoreTSData() {
    147     return mFinalResult;
    148 }
    149 
    150 sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
    151     sp<AnotherPacketSource> source = getSource(audio);
    152 
    153     if (source == NULL) {
    154         return NULL;
    155     }
    156 
    157     return source->getFormat();
    158 }
    159 
    160 bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() {
    161     // We're going to buffer at least 2 secs worth data on all tracks before
    162     // starting playback (both at startup and after a seek).
    163 
    164     static const int64_t kMinDurationUs = 2000000ll;
    165 
    166     int64_t mediaDurationUs = 0;
    167     getDuration(&mediaDurationUs);
    168     if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
    169             || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
    170         return true;
    171     }
    172 
    173     status_t err;
    174     int64_t durationUs;
    175     if (mAudioTrack != NULL
    176             && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
    177                     < kMinDurationUs
    178             && err == OK) {
    179         ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
    180               durationUs / 1E6);
    181         return false;
    182     }
    183 
    184     if (mVideoTrack != NULL
    185             && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
    186                     < kMinDurationUs
    187             && err == OK) {
    188         ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
    189               durationUs / 1E6);
    190         return false;
    191     }
    192 
    193     return true;
    194 }
    195 
    196 status_t NuPlayer::RTSPSource::dequeueAccessUnit(
    197         bool audio, sp<ABuffer> *accessUnit) {
    198     if (mBuffering) {
    199         if (!haveSufficientDataOnAllTracks()) {
    200             return -EWOULDBLOCK;
    201         }
    202 
    203         mBuffering = false;
    204 
    205         sp<AMessage> notify = dupNotify();
    206         notify->setInt32("what", kWhatBufferingEnd);
    207         notify->post();
    208     }
    209 
    210     sp<AnotherPacketSource> source = getSource(audio);
    211 
    212     if (source == NULL) {
    213         return -EWOULDBLOCK;
    214     }
    215 
    216     status_t finalResult;
    217     if (!source->hasBufferAvailable(&finalResult)) {
    218         if (finalResult == OK) {
    219             int64_t mediaDurationUs = 0;
    220             getDuration(&mediaDurationUs);
    221             sp<AnotherPacketSource> otherSource = getSource(!audio);
    222             status_t otherFinalResult;
    223 
    224             // If other source already signaled EOS, this source should also signal EOS
    225             if (otherSource != NULL &&
    226                     !otherSource->hasBufferAvailable(&otherFinalResult) &&
    227                     otherFinalResult == ERROR_END_OF_STREAM) {
    228                 source->signalEOS(ERROR_END_OF_STREAM);
    229                 return ERROR_END_OF_STREAM;
    230             }
    231 
    232             // If this source has detected near end, give it some time to retrieve more
    233             // data before signaling EOS
    234             if (source->isFinished(mediaDurationUs)) {
    235                 int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
    236                 if (eosTimeout == 0) {
    237                     setEOSTimeout(audio, ALooper::GetNowUs());
    238                 } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
    239                     setEOSTimeout(audio, 0);
    240                     source->signalEOS(ERROR_END_OF_STREAM);
    241                     return ERROR_END_OF_STREAM;
    242                 }
    243                 return -EWOULDBLOCK;
    244             }
    245 
    246             if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
    247                 // We should not enter buffering mode
    248                 // if any of the sources already have detected EOS.
    249                 mBuffering = true;
    250 
    251                 sp<AMessage> notify = dupNotify();
    252                 notify->setInt32("what", kWhatBufferingStart);
    253                 notify->post();
    254             }
    255 
    256             return -EWOULDBLOCK;
    257         }
    258         return finalResult;
    259     }
    260 
    261     setEOSTimeout(audio, 0);
    262 
    263     return source->dequeueAccessUnit(accessUnit);
    264 }
    265 
    266 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
    267     if (mTSParser != NULL) {
    268         sp<MediaSource> source = mTSParser->getSource(
    269                 audio ? ATSParser::AUDIO : ATSParser::VIDEO);
    270 
    271         return static_cast<AnotherPacketSource *>(source.get());
    272     }
    273 
    274     return audio ? mAudioTrack : mVideoTrack;
    275 }
    276 
    277 void NuPlayer::RTSPSource::setEOSTimeout(bool audio, int64_t timeout) {
    278     if (audio) {
    279         mEOSTimeoutAudio = timeout;
    280     } else {
    281         mEOSTimeoutVideo = timeout;
    282     }
    283 }
    284 
    285 status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
    286     *durationUs = 0ll;
    287 
    288     int64_t audioDurationUs;
    289     if (mAudioTrack != NULL
    290             && mAudioTrack->getFormat()->findInt64(
    291                 kKeyDuration, &audioDurationUs)
    292             && audioDurationUs > *durationUs) {
    293         *durationUs = audioDurationUs;
    294     }
    295 
    296     int64_t videoDurationUs;
    297     if (mVideoTrack != NULL
    298             && mVideoTrack->getFormat()->findInt64(
    299                 kKeyDuration, &videoDurationUs)
    300             && videoDurationUs > *durationUs) {
    301         *durationUs = videoDurationUs;
    302     }
    303 
    304     return OK;
    305 }
    306 
    307 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
    308     sp<AMessage> msg = new AMessage(kWhatPerformSeek, id());
    309     msg->setInt32("generation", ++mSeekGeneration);
    310     msg->setInt64("timeUs", seekTimeUs);
    311     msg->post(200000ll);
    312 
    313     return OK;
    314 }
    315 
    316 void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) {
    317     if (mState != CONNECTED) {
    318         return;
    319     }
    320 
    321     mState = SEEKING;
    322     mHandler->seek(seekTimeUs);
    323 }
    324 
    325 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
    326     if (msg->what() == kWhatDisconnect) {
    327         uint32_t replyID;
    328         CHECK(msg->senderAwaitsResponse(&replyID));
    329 
    330         mDisconnectReplyID = replyID;
    331         finishDisconnectIfPossible();
    332         return;
    333     } else if (msg->what() == kWhatPerformSeek) {
    334         int32_t generation;
    335         CHECK(msg->findInt32("generation", &generation));
    336 
    337         if (generation != mSeekGeneration) {
    338             // obsolete.
    339             return;
    340         }
    341 
    342         int64_t seekTimeUs;
    343         CHECK(msg->findInt64("timeUs", &seekTimeUs));
    344 
    345         performSeek(seekTimeUs);
    346         return;
    347     }
    348 
    349     CHECK_EQ(msg->what(), (int)kWhatNotify);
    350 
    351     int32_t what;
    352     CHECK(msg->findInt32("what", &what));
    353 
    354     switch (what) {
    355         case MyHandler::kWhatConnected:
    356         {
    357             onConnected();
    358 
    359             notifyVideoSizeChanged();
    360 
    361             uint32_t flags = 0;
    362 
    363             if (mHandler->isSeekable()) {
    364                 flags = FLAG_CAN_PAUSE
    365                         | FLAG_CAN_SEEK
    366                         | FLAG_CAN_SEEK_BACKWARD
    367                         | FLAG_CAN_SEEK_FORWARD;
    368             }
    369 
    370             notifyFlagsChanged(flags);
    371             notifyPrepared();
    372             break;
    373         }
    374 
    375         case MyHandler::kWhatDisconnected:
    376         {
    377             onDisconnected(msg);
    378             break;
    379         }
    380 
    381         case MyHandler::kWhatSeekDone:
    382         {
    383             mState = CONNECTED;
    384             break;
    385         }
    386 
    387         case MyHandler::kWhatAccessUnit:
    388         {
    389             size_t trackIndex;
    390             CHECK(msg->findSize("trackIndex", &trackIndex));
    391 
    392             if (mTSParser == NULL) {
    393                 CHECK_LT(trackIndex, mTracks.size());
    394             } else {
    395                 CHECK_EQ(trackIndex, 0u);
    396             }
    397 
    398             sp<ABuffer> accessUnit;
    399             CHECK(msg->findBuffer("accessUnit", &accessUnit));
    400 
    401             int32_t damaged;
    402             if (accessUnit->meta()->findInt32("damaged", &damaged)
    403                     && damaged) {
    404                 ALOGI("dropping damaged access unit.");
    405                 break;
    406             }
    407 
    408             if (mTSParser != NULL) {
    409                 size_t offset = 0;
    410                 status_t err = OK;
    411                 while (offset + 188 <= accessUnit->size()) {
    412                     err = mTSParser->feedTSPacket(
    413                             accessUnit->data() + offset, 188);
    414                     if (err != OK) {
    415                         break;
    416                     }
    417 
    418                     offset += 188;
    419                 }
    420 
    421                 if (offset < accessUnit->size()) {
    422                     err = ERROR_MALFORMED;
    423                 }
    424 
    425                 if (err != OK) {
    426                     sp<AnotherPacketSource> source = getSource(false /* audio */);
    427                     if (source != NULL) {
    428                         source->signalEOS(err);
    429                     }
    430 
    431                     source = getSource(true /* audio */);
    432                     if (source != NULL) {
    433                         source->signalEOS(err);
    434                     }
    435                 }
    436                 break;
    437             }
    438 
    439             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    440 
    441             sp<AnotherPacketSource> source = info->mSource;
    442             if (source != NULL) {
    443                 uint32_t rtpTime;
    444                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
    445 
    446                 if (!info->mNPTMappingValid) {
    447                     // This is a live stream, we didn't receive any normal
    448                     // playtime mapping. We won't map to npt time.
    449                     source->queueAccessUnit(accessUnit);
    450                     break;
    451                 }
    452 
    453                 int64_t nptUs =
    454                     ((double)rtpTime - (double)info->mRTPTime)
    455                         / info->mTimeScale
    456                         * 1000000ll
    457                         + info->mNormalPlaytimeUs;
    458 
    459                 accessUnit->meta()->setInt64("timeUs", nptUs);
    460 
    461                 source->queueAccessUnit(accessUnit);
    462             }
    463             break;
    464         }
    465 
    466         case MyHandler::kWhatEOS:
    467         {
    468             int32_t finalResult;
    469             CHECK(msg->findInt32("finalResult", &finalResult));
    470             CHECK_NE(finalResult, (status_t)OK);
    471 
    472             if (mTSParser != NULL) {
    473                 sp<AnotherPacketSource> source = getSource(false /* audio */);
    474                 if (source != NULL) {
    475                     source->signalEOS(finalResult);
    476                 }
    477 
    478                 source = getSource(true /* audio */);
    479                 if (source != NULL) {
    480                     source->signalEOS(finalResult);
    481                 }
    482 
    483                 return;
    484             }
    485 
    486             size_t trackIndex;
    487             CHECK(msg->findSize("trackIndex", &trackIndex));
    488             CHECK_LT(trackIndex, mTracks.size());
    489 
    490             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    491             sp<AnotherPacketSource> source = info->mSource;
    492             if (source != NULL) {
    493                 source->signalEOS(finalResult);
    494             }
    495 
    496             break;
    497         }
    498 
    499         case MyHandler::kWhatSeekDiscontinuity:
    500         {
    501             size_t trackIndex;
    502             CHECK(msg->findSize("trackIndex", &trackIndex));
    503             CHECK_LT(trackIndex, mTracks.size());
    504 
    505             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    506             sp<AnotherPacketSource> source = info->mSource;
    507             if (source != NULL) {
    508                 source->queueDiscontinuity(
    509                         ATSParser::DISCONTINUITY_SEEK,
    510                         NULL,
    511                         true /* discard */);
    512             }
    513 
    514             break;
    515         }
    516 
    517         case MyHandler::kWhatNormalPlayTimeMapping:
    518         {
    519             size_t trackIndex;
    520             CHECK(msg->findSize("trackIndex", &trackIndex));
    521             CHECK_LT(trackIndex, mTracks.size());
    522 
    523             uint32_t rtpTime;
    524             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
    525 
    526             int64_t nptUs;
    527             CHECK(msg->findInt64("nptUs", &nptUs));
    528 
    529             TrackInfo *info = &mTracks.editItemAt(trackIndex);
    530             info->mRTPTime = rtpTime;
    531             info->mNormalPlaytimeUs = nptUs;
    532             info->mNPTMappingValid = true;
    533             break;
    534         }
    535 
    536         case SDPLoader::kWhatSDPLoaded:
    537         {
    538             onSDPLoaded(msg);
    539             break;
    540         }
    541 
    542         default:
    543             TRESPASS();
    544     }
    545 }
    546 
    547 void NuPlayer::RTSPSource::onConnected() {
    548     CHECK(mAudioTrack == NULL);
    549     CHECK(mVideoTrack == NULL);
    550 
    551     size_t numTracks = mHandler->countTracks();
    552     for (size_t i = 0; i < numTracks; ++i) {
    553         int32_t timeScale;
    554         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
    555 
    556         const char *mime;
    557         CHECK(format->findCString(kKeyMIMEType, &mime));
    558 
    559         if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
    560             // Very special case for MPEG2 Transport Streams.
    561             CHECK_EQ(numTracks, 1u);
    562 
    563             mTSParser = new ATSParser;
    564             return;
    565         }
    566 
    567         bool isAudio = !strncasecmp(mime, "audio/", 6);
    568         bool isVideo = !strncasecmp(mime, "video/", 6);
    569 
    570         TrackInfo info;
    571         info.mTimeScale = timeScale;
    572         info.mRTPTime = 0;
    573         info.mNormalPlaytimeUs = 0ll;
    574         info.mNPTMappingValid = false;
    575 
    576         if ((isAudio && mAudioTrack == NULL)
    577                 || (isVideo && mVideoTrack == NULL)) {
    578             sp<AnotherPacketSource> source = new AnotherPacketSource(format);
    579 
    580             if (isAudio) {
    581                 mAudioTrack = source;
    582             } else {
    583                 mVideoTrack = source;
    584             }
    585 
    586             info.mSource = source;
    587         }
    588 
    589         mTracks.push(info);
    590     }
    591 
    592     mState = CONNECTED;
    593 }
    594 
    595 void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
    596     status_t err;
    597     CHECK(msg->findInt32("result", &err));
    598 
    599     mSDPLoader.clear();
    600 
    601     if (mDisconnectReplyID != 0) {
    602         err = UNKNOWN_ERROR;
    603     }
    604 
    605     if (err == OK) {
    606         sp<ASessionDescription> desc;
    607         sp<RefBase> obj;
    608         CHECK(msg->findObject("description", &obj));
    609         desc = static_cast<ASessionDescription *>(obj.get());
    610 
    611         AString rtspUri;
    612         if (!desc->findAttribute(0, "a=control", &rtspUri)) {
    613             ALOGE("Unable to find url in SDP");
    614             err = UNKNOWN_ERROR;
    615         } else {
    616             sp<AMessage> notify = new AMessage(kWhatNotify, id());
    617 
    618             mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
    619             mLooper->registerHandler(mHandler);
    620 
    621             mHandler->loadSDP(desc);
    622         }
    623     }
    624 
    625     if (err != OK) {
    626         if (mState == CONNECTING) {
    627             // We're still in the preparation phase, signal that it
    628             // failed.
    629             notifyPrepared(err);
    630         }
    631 
    632         mState = DISCONNECTED;
    633         mFinalResult = err;
    634 
    635         if (mDisconnectReplyID != 0) {
    636             finishDisconnectIfPossible();
    637         }
    638     }
    639 }
    640 
    641 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
    642     if (mState == DISCONNECTED) {
    643         return;
    644     }
    645 
    646     status_t err;
    647     CHECK(msg->findInt32("result", &err));
    648     CHECK_NE(err, (status_t)OK);
    649 
    650     mLooper->unregisterHandler(mHandler->id());
    651     mHandler.clear();
    652 
    653     if (mState == CONNECTING) {
    654         // We're still in the preparation phase, signal that it
    655         // failed.
    656         notifyPrepared(err);
    657     }
    658 
    659     mState = DISCONNECTED;
    660     mFinalResult = err;
    661 
    662     if (mDisconnectReplyID != 0) {
    663         finishDisconnectIfPossible();
    664     }
    665 }
    666 
    667 void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
    668     if (mState != DISCONNECTED) {
    669         if (mHandler != NULL) {
    670             mHandler->disconnect();
    671         } else if (mSDPLoader != NULL) {
    672             mSDPLoader->cancel();
    673         }
    674         return;
    675     }
    676 
    677     (new AMessage)->postReply(mDisconnectReplyID);
    678     mDisconnectReplyID = 0;
    679 }
    680 
    681 }  // namespace android
    682