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