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