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