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 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 81 NuPlayer::RTSPSource::~RTSPSource() { 82 if (mLooper != NULL) { 83 mLooper->unregisterHandler(id()); 84 mLooper->stop(); 85 } 86 } 87 88 status_t NuPlayer::RTSPSource::getBufferingSettings( 89 BufferingSettings* buffering /* nonnull */) { 90 Mutex::Autolock _l(mBufferingSettingsLock); 91 *buffering = mBufferingSettings; 92 return OK; 93 } 94 95 status_t NuPlayer::RTSPSource::setBufferingSettings(const BufferingSettings& buffering) { 96 Mutex::Autolock _l(mBufferingSettingsLock); 97 mBufferingSettings = buffering; 98 return OK; 99 } 100 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 140 void NuPlayer::RTSPSource::start() { 141 } 142 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 153 status_t NuPlayer::RTSPSource::feedMoreTSData() { 154 Mutex::Autolock _l(mBufferingLock); 155 return mFinalResult; 156 } 157 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 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 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 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 267 void NuPlayer::RTSPSource::setEOSTimeout(bool audio, int64_t timeout) { 268 if (audio) { 269 mEOSTimeoutAudio = timeout; 270 } else { 271 mEOSTimeoutVideo = timeout; 272 } 273 } 274 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 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 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 323 void NuPlayer::RTSPSource::schedulePollBuffering() { 324 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); 325 msg->post(1000000ll); // 1 second intervals 326 } 327 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 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 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 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 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 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 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 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 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 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 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 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 859 void NuPlayer::RTSPSource::setError(status_t err) { 860 Mutex::Autolock _l(mBufferingLock); 861 mFinalResult = err; 862 } 863 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 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 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