• 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     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 
onPollBuffering()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 
onMessageReceived(const sp<AMessage> & msg)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 
onConnected()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 
onSDPLoaded(const sp<AMessage> & msg)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 
onDisconnected(const sp<AMessage> & msg)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 
finishDisconnectIfPossible()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 
setError(status_t err)769 void NuPlayer::RTSPSource::setError(status_t err) {
770     Mutex::Autolock _l(mBufferingLock);
771     mFinalResult = err;
772 }
773 
startBufferingIfNecessary()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 
stopBufferingIfNecessary()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 
finishSeek(status_t err)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