• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RTSPSource(const sp<AMessage> & notify,const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers,bool uidValid,uid_t uid,bool isSDP)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 
~RTSPSource()78 NuPlayer::RTSPSource::~RTSPSource() {
79     if (mLooper != NULL) {
80         mLooper->unregisterHandler(id());
81         mLooper->stop();
82     }
83 }
84 
prepareAsync()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 
start()124 void NuPlayer::RTSPSource::start() {
125 }
126 
stop()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 
feedMoreTSData()137 status_t NuPlayer::RTSPSource::feedMoreTSData() {
138     Mutex::Autolock _l(mBufferingLock);
139     return mFinalResult;
140 }
141 
getFormatMeta(bool audio)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 
haveSufficientDataOnAllTracks()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 
dequeueAccessUnit(bool audio,sp<ABuffer> * accessUnit)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 
getSource(bool audio)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 
setEOSTimeout(bool audio,int64_t timeout)257 void NuPlayer::RTSPSource::setEOSTimeout(bool audio, int64_t timeout) {
258     if (audio) {
259         mEOSTimeoutAudio = timeout;
260     } else {
261         mEOSTimeoutVideo = timeout;
262     }
263 }
264 
getDuration(int64_t * durationUs)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 
seekTo(int64_t seekTimeUs)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 
performSeek(int64_t seekTimeUs)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 
schedulePollBuffering()311 void NuPlayer::RTSPSource::schedulePollBuffering() {
312     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
313     msg->post(1000000ll); // 1 second intervals
314 }
315 
checkBuffering(bool * prepared,bool * underflow,bool * overflow,bool * startServer)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 
322     size_t count = numTracks;
323     for (size_t i = 0; i < count; ++i) {
324         status_t finalResult;
325         TrackInfo *info = &mTracks.editItemAt(i);
326         sp<AnotherPacketSource> src = info->mSource;
327         if (src == NULL) {
328             --numTracks;
329             continue;
330         }
331         int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
332 
333         // isFinished when duration is 0 checks for EOS result only
334         if (bufferedDurationUs > kPrepareMarkUs || src->isFinished(/* duration */ 0)) {
335             ++preparedCount;
336         }
337 
338         if (src->isFinished(/* duration */ 0)) {
339             ++overflowCount;
340         } else {
341             if (bufferedDurationUs < kUnderflowMarkUs) {
342                 ++underflowCount;
343             }
344             if (bufferedDurationUs > kOverflowMarkUs) {
345                 ++overflowCount;
346             }
347             if (bufferedDurationUs < kStartServerMarkUs) {
348                 ++startCount;
349             }
350         }
351     }
352 
353     *prepared    = (preparedCount == numTracks);
354     *underflow   = (underflowCount > 0);
355     *overflow    = (overflowCount == numTracks);
356     *startServer = (startCount > 0);
357 }
358 
onPollBuffering()359 void NuPlayer::RTSPSource::onPollBuffering() {
360     bool prepared, underflow, overflow, startServer;
361     checkBuffering(&prepared, &underflow, &overflow, &startServer);
362 
363     if (prepared && mInPreparationPhase) {
364         mInPreparationPhase = false;
365         notifyPrepared();
366     }
367 
368     if (!mInPreparationPhase && underflow) {
369         startBufferingIfNecessary();
370     }
371 
372     if (overflow && mHandler != NULL) {
373         stopBufferingIfNecessary();
374         mHandler->pause();
375     }
376 
377     if (startServer && mHandler != NULL) {
378         mHandler->resume();
379     }
380 
381     schedulePollBuffering();
382 }
383 
onMessageReceived(const sp<AMessage> & msg)384 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
385     if (msg->what() == kWhatDisconnect) {
386         sp<AReplyToken> replyID;
387         CHECK(msg->senderAwaitsResponse(&replyID));
388 
389         mDisconnectReplyID = replyID;
390         finishDisconnectIfPossible();
391         return;
392     } else if (msg->what() == kWhatPerformSeek) {
393         int32_t generation;
394         CHECK(msg->findInt32("generation", &generation));
395         CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
396 
397         if (generation != mSeekGeneration) {
398             // obsolete.
399             finishSeek(OK);
400             return;
401         }
402 
403         int64_t seekTimeUs;
404         CHECK(msg->findInt64("timeUs", &seekTimeUs));
405 
406         performSeek(seekTimeUs);
407         return;
408     } else if (msg->what() == kWhatPollBuffering) {
409         onPollBuffering();
410         return;
411     }
412 
413     CHECK_EQ(msg->what(), (int)kWhatNotify);
414 
415     int32_t what;
416     CHECK(msg->findInt32("what", &what));
417 
418     switch (what) {
419         case MyHandler::kWhatConnected:
420         {
421             onConnected();
422 
423             notifyVideoSizeChanged();
424 
425             uint32_t flags = 0;
426 
427             if (mHandler->isSeekable()) {
428                 flags = FLAG_CAN_PAUSE
429                         | FLAG_CAN_SEEK
430                         | FLAG_CAN_SEEK_BACKWARD
431                         | FLAG_CAN_SEEK_FORWARD;
432             }
433 
434             notifyFlagsChanged(flags);
435             schedulePollBuffering();
436             break;
437         }
438 
439         case MyHandler::kWhatDisconnected:
440         {
441             onDisconnected(msg);
442             break;
443         }
444 
445         case MyHandler::kWhatSeekDone:
446         {
447             mState = CONNECTED;
448             // Unblock seekTo here in case we attempted to seek in a live stream
449             finishSeek(OK);
450             break;
451         }
452 
453         case MyHandler::kWhatSeekPaused:
454         {
455             sp<AnotherPacketSource> source = getSource(true /* audio */);
456             if (source != NULL) {
457                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
458                         /* extra */ NULL,
459                         /* discard */ true);
460             }
461             source = getSource(false /* video */);
462             if (source != NULL) {
463                 source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
464                         /* extra */ NULL,
465                         /* discard */ true);
466             };
467 
468             status_t err = OK;
469             msg->findInt32("err", &err);
470 
471             if (err == OK) {
472                 int64_t timeUs;
473                 CHECK(msg->findInt64("time", &timeUs));
474                 mHandler->continueSeekAfterPause(timeUs);
475             } else {
476                 finishSeek(err);
477             }
478             break;
479         }
480 
481         case MyHandler::kWhatAccessUnit:
482         {
483             size_t trackIndex;
484             CHECK(msg->findSize("trackIndex", &trackIndex));
485 
486             if (mTSParser == NULL) {
487                 CHECK_LT(trackIndex, mTracks.size());
488             } else {
489                 CHECK_EQ(trackIndex, 0u);
490             }
491 
492             sp<ABuffer> accessUnit;
493             CHECK(msg->findBuffer("accessUnit", &accessUnit));
494 
495             int32_t damaged;
496             if (accessUnit->meta()->findInt32("damaged", &damaged)
497                     && damaged) {
498                 ALOGI("dropping damaged access unit.");
499                 break;
500             }
501 
502             if (mTSParser != NULL) {
503                 size_t offset = 0;
504                 status_t err = OK;
505                 while (offset + 188 <= accessUnit->size()) {
506                     err = mTSParser->feedTSPacket(
507                             accessUnit->data() + offset, 188);
508                     if (err != OK) {
509                         break;
510                     }
511 
512                     offset += 188;
513                 }
514 
515                 if (offset < accessUnit->size()) {
516                     err = ERROR_MALFORMED;
517                 }
518 
519                 if (err != OK) {
520                     sp<AnotherPacketSource> source = getSource(false /* audio */);
521                     if (source != NULL) {
522                         source->signalEOS(err);
523                     }
524 
525                     source = getSource(true /* audio */);
526                     if (source != NULL) {
527                         source->signalEOS(err);
528                     }
529                 }
530                 break;
531             }
532 
533             TrackInfo *info = &mTracks.editItemAt(trackIndex);
534 
535             sp<AnotherPacketSource> source = info->mSource;
536             if (source != NULL) {
537                 uint32_t rtpTime;
538                 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
539 
540                 if (!info->mNPTMappingValid) {
541                     // This is a live stream, we didn't receive any normal
542                     // playtime mapping. We won't map to npt time.
543                     source->queueAccessUnit(accessUnit);
544                     break;
545                 }
546 
547                 int64_t nptUs =
548                     ((double)rtpTime - (double)info->mRTPTime)
549                         / info->mTimeScale
550                         * 1000000ll
551                         + info->mNormalPlaytimeUs;
552 
553                 accessUnit->meta()->setInt64("timeUs", nptUs);
554 
555                 source->queueAccessUnit(accessUnit);
556             }
557             break;
558         }
559 
560         case MyHandler::kWhatEOS:
561         {
562             int32_t finalResult;
563             CHECK(msg->findInt32("finalResult", &finalResult));
564             CHECK_NE(finalResult, (status_t)OK);
565 
566             if (mTSParser != NULL) {
567                 sp<AnotherPacketSource> source = getSource(false /* audio */);
568                 if (source != NULL) {
569                     source->signalEOS(finalResult);
570                 }
571 
572                 source = getSource(true /* audio */);
573                 if (source != NULL) {
574                     source->signalEOS(finalResult);
575                 }
576 
577                 return;
578             }
579 
580             size_t trackIndex;
581             CHECK(msg->findSize("trackIndex", &trackIndex));
582             CHECK_LT(trackIndex, mTracks.size());
583 
584             TrackInfo *info = &mTracks.editItemAt(trackIndex);
585             sp<AnotherPacketSource> source = info->mSource;
586             if (source != NULL) {
587                 source->signalEOS(finalResult);
588             }
589 
590             break;
591         }
592 
593         case MyHandler::kWhatSeekDiscontinuity:
594         {
595             size_t trackIndex;
596             CHECK(msg->findSize("trackIndex", &trackIndex));
597             CHECK_LT(trackIndex, mTracks.size());
598 
599             TrackInfo *info = &mTracks.editItemAt(trackIndex);
600             sp<AnotherPacketSource> source = info->mSource;
601             if (source != NULL) {
602                 source->queueDiscontinuity(
603                         ATSParser::DISCONTINUITY_TIME,
604                         NULL,
605                         true /* discard */);
606             }
607 
608             break;
609         }
610 
611         case MyHandler::kWhatNormalPlayTimeMapping:
612         {
613             size_t trackIndex;
614             CHECK(msg->findSize("trackIndex", &trackIndex));
615             CHECK_LT(trackIndex, mTracks.size());
616 
617             uint32_t rtpTime;
618             CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
619 
620             int64_t nptUs;
621             CHECK(msg->findInt64("nptUs", &nptUs));
622 
623             TrackInfo *info = &mTracks.editItemAt(trackIndex);
624             info->mRTPTime = rtpTime;
625             info->mNormalPlaytimeUs = nptUs;
626             info->mNPTMappingValid = true;
627             break;
628         }
629 
630         case SDPLoader::kWhatSDPLoaded:
631         {
632             onSDPLoaded(msg);
633             break;
634         }
635 
636         default:
637             TRESPASS();
638     }
639 }
640 
onConnected()641 void NuPlayer::RTSPSource::onConnected() {
642     CHECK(mAudioTrack == NULL);
643     CHECK(mVideoTrack == NULL);
644 
645     size_t numTracks = mHandler->countTracks();
646     for (size_t i = 0; i < numTracks; ++i) {
647         int32_t timeScale;
648         sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
649 
650         const char *mime;
651         CHECK(format->findCString(kKeyMIMEType, &mime));
652 
653         if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
654             // Very special case for MPEG2 Transport Streams.
655             CHECK_EQ(numTracks, 1u);
656 
657             mTSParser = new ATSParser;
658             return;
659         }
660 
661         bool isAudio = !strncasecmp(mime, "audio/", 6);
662         bool isVideo = !strncasecmp(mime, "video/", 6);
663 
664         TrackInfo info;
665         info.mTimeScale = timeScale;
666         info.mRTPTime = 0;
667         info.mNormalPlaytimeUs = 0ll;
668         info.mNPTMappingValid = false;
669 
670         if ((isAudio && mAudioTrack == NULL)
671                 || (isVideo && mVideoTrack == NULL)) {
672             sp<AnotherPacketSource> source = new AnotherPacketSource(format);
673 
674             if (isAudio) {
675                 mAudioTrack = source;
676             } else {
677                 mVideoTrack = source;
678             }
679 
680             info.mSource = source;
681         }
682 
683         mTracks.push(info);
684     }
685 
686     mState = CONNECTED;
687 }
688 
onSDPLoaded(const sp<AMessage> & msg)689 void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
690     status_t err;
691     CHECK(msg->findInt32("result", &err));
692 
693     mSDPLoader.clear();
694 
695     if (mDisconnectReplyID != 0) {
696         err = UNKNOWN_ERROR;
697     }
698 
699     if (err == OK) {
700         sp<ASessionDescription> desc;
701         sp<RefBase> obj;
702         CHECK(msg->findObject("description", &obj));
703         desc = static_cast<ASessionDescription *>(obj.get());
704 
705         AString rtspUri;
706         if (!desc->findAttribute(0, "a=control", &rtspUri)) {
707             ALOGE("Unable to find url in SDP");
708             err = UNKNOWN_ERROR;
709         } else {
710             sp<AMessage> notify = new AMessage(kWhatNotify, this);
711 
712             mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
713             mLooper->registerHandler(mHandler);
714 
715             mHandler->loadSDP(desc);
716         }
717     }
718 
719     if (err != OK) {
720         if (mState == CONNECTING) {
721             // We're still in the preparation phase, signal that it
722             // failed.
723             notifyPrepared(err);
724         }
725 
726         mState = DISCONNECTED;
727         setError(err);
728 
729         if (mDisconnectReplyID != 0) {
730             finishDisconnectIfPossible();
731         }
732     }
733 }
734 
onDisconnected(const sp<AMessage> & msg)735 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
736     if (mState == DISCONNECTED) {
737         return;
738     }
739 
740     status_t err;
741     CHECK(msg->findInt32("result", &err));
742     CHECK_NE(err, (status_t)OK);
743 
744     mLooper->unregisterHandler(mHandler->id());
745     mHandler.clear();
746 
747     if (mState == CONNECTING) {
748         // We're still in the preparation phase, signal that it
749         // failed.
750         notifyPrepared(err);
751     }
752 
753     mState = DISCONNECTED;
754     setError(err);
755 
756     if (mDisconnectReplyID != 0) {
757         finishDisconnectIfPossible();
758     }
759 }
760 
finishDisconnectIfPossible()761 void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
762     if (mState != DISCONNECTED) {
763         if (mHandler != NULL) {
764             mHandler->disconnect();
765         } else if (mSDPLoader != NULL) {
766             mSDPLoader->cancel();
767         }
768         return;
769     }
770 
771     (new AMessage)->postReply(mDisconnectReplyID);
772     mDisconnectReplyID = 0;
773 }
774 
setError(status_t err)775 void NuPlayer::RTSPSource::setError(status_t err) {
776     Mutex::Autolock _l(mBufferingLock);
777     mFinalResult = err;
778 }
779 
startBufferingIfNecessary()780 void NuPlayer::RTSPSource::startBufferingIfNecessary() {
781     Mutex::Autolock _l(mBufferingLock);
782 
783     if (!mBuffering) {
784         mBuffering = true;
785 
786         sp<AMessage> notify = dupNotify();
787         notify->setInt32("what", kWhatPauseOnBufferingStart);
788         notify->post();
789     }
790 }
791 
stopBufferingIfNecessary()792 bool NuPlayer::RTSPSource::stopBufferingIfNecessary() {
793     Mutex::Autolock _l(mBufferingLock);
794 
795     if (mBuffering) {
796         if (!haveSufficientDataOnAllTracks()) {
797             return false;
798         }
799 
800         mBuffering = false;
801 
802         sp<AMessage> notify = dupNotify();
803         notify->setInt32("what", kWhatResumeOnBufferingEnd);
804         notify->post();
805     }
806 
807     return true;
808 }
809 
finishSeek(status_t err)810 void NuPlayer::RTSPSource::finishSeek(status_t err) {
811     if (mSeekReplyID == NULL) {
812         return;
813     }
814     sp<AMessage> seekReply = new AMessage;
815     seekReply->setInt32("err", err);
816     seekReply->postReply(mSeekReplyID);
817     mSeekReplyID = NULL;
818 }
819 
820 }  // namespace android
821