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