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