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