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