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