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