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