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> ¬ify,
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