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
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