NuPlayerRenderer.cpp revision 28a8a9ff2a2bfd5edbdbbadde50c6d804335ffdc
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 "NuPlayerRenderer" 19#include <utils/Log.h> 20 21#include "NuPlayerRenderer.h" 22 23#include <media/stagefright/foundation/ABuffer.h> 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/foundation/AMessage.h> 26#include <media/stagefright/MediaErrors.h> 27#include <media/stagefright/MetaData.h> 28 29#include <inttypes.h> 30 31namespace android { 32 33// static 34const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; 35 36NuPlayer::Renderer::Renderer( 37 const sp<MediaPlayerBase::AudioSink> &sink, 38 const sp<AMessage> ¬ify, 39 uint32_t flags) 40 : mAudioSink(sink), 41 mNotify(notify), 42 mFlags(flags), 43 mNumFramesWritten(0), 44 mDrainAudioQueuePending(false), 45 mDrainVideoQueuePending(false), 46 mAudioQueueGeneration(0), 47 mVideoQueueGeneration(0), 48 mFirstAudioTimeUs(-1), 49 mAnchorTimeMediaUs(-1), 50 mAnchorTimeRealUs(-1), 51 mFlushingAudio(false), 52 mFlushingVideo(false), 53 mHasAudio(false), 54 mHasVideo(false), 55 mSyncQueues(false), 56 mPaused(false), 57 mVideoRenderingStarted(false), 58 mVideoRenderingStartGeneration(0), 59 mAudioRenderingStartGeneration(0), 60 mLastPositionUpdateUs(-1ll), 61 mVideoLateByUs(0ll) { 62} 63 64NuPlayer::Renderer::~Renderer() { 65 if (offloadingAudio()) { 66 mAudioSink->stop(); 67 mAudioSink->flush(); 68 mAudioSink->close(); 69 } 70} 71 72void NuPlayer::Renderer::queueBuffer( 73 bool audio, 74 const sp<ABuffer> &buffer, 75 const sp<AMessage> ¬ifyConsumed) { 76 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id()); 77 msg->setInt32("audio", static_cast<int32_t>(audio)); 78 msg->setBuffer("buffer", buffer); 79 msg->setMessage("notifyConsumed", notifyConsumed); 80 msg->post(); 81} 82 83void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { 84 CHECK_NE(finalResult, (status_t)OK); 85 86 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id()); 87 msg->setInt32("audio", static_cast<int32_t>(audio)); 88 msg->setInt32("finalResult", finalResult); 89 msg->post(); 90} 91 92void NuPlayer::Renderer::flush(bool audio) { 93 { 94 Mutex::Autolock autoLock(mFlushLock); 95 if (audio) { 96 if (mFlushingAudio) { 97 return; 98 } 99 mFlushingAudio = true; 100 } else { 101 if (mFlushingVideo) { 102 return; 103 } 104 mFlushingVideo = true; 105 } 106 } 107 108 sp<AMessage> msg = new AMessage(kWhatFlush, id()); 109 msg->setInt32("audio", static_cast<int32_t>(audio)); 110 msg->post(); 111} 112 113void NuPlayer::Renderer::signalTimeDiscontinuity() { 114 Mutex::Autolock autoLock(mLock); 115 // CHECK(mAudioQueue.empty()); 116 // CHECK(mVideoQueue.empty()); 117 mAnchorTimeMediaUs = -1; 118 mAnchorTimeRealUs = -1; 119 mSyncQueues = false; 120} 121 122void NuPlayer::Renderer::signalAudioSinkChanged() { 123 (new AMessage(kWhatAudioSinkChanged, id()))->post(); 124} 125 126void NuPlayer::Renderer::signalDisableOffloadAudio() { 127 (new AMessage(kWhatDisableOffloadAudio, id()))->post(); 128} 129 130void NuPlayer::Renderer::pause() { 131 (new AMessage(kWhatPause, id()))->post(); 132} 133 134void NuPlayer::Renderer::resume() { 135 (new AMessage(kWhatResume, id()))->post(); 136} 137 138void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { 139 switch (msg->what()) { 140 case kWhatStopAudioSink: 141 { 142 mAudioSink->stop(); 143 break; 144 } 145 146 case kWhatDrainAudioQueue: 147 { 148 int32_t generation; 149 CHECK(msg->findInt32("generation", &generation)); 150 if (generation != mAudioQueueGeneration) { 151 break; 152 } 153 154 mDrainAudioQueuePending = false; 155 156 if (onDrainAudioQueue()) { 157 uint32_t numFramesPlayed; 158 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), 159 (status_t)OK); 160 161 uint32_t numFramesPendingPlayout = 162 mNumFramesWritten - numFramesPlayed; 163 164 // This is how long the audio sink will have data to 165 // play back. 166 int64_t delayUs = 167 mAudioSink->msecsPerFrame() 168 * numFramesPendingPlayout * 1000ll; 169 170 // Let's give it more data after about half that time 171 // has elapsed. 172 // kWhatDrainAudioQueue is used for non-offloading mode, 173 // and mLock is used only for offloading mode. Therefore, 174 // no need to acquire mLock here. 175 postDrainAudioQueue_l(delayUs / 2); 176 } 177 break; 178 } 179 180 case kWhatDrainVideoQueue: 181 { 182 int32_t generation; 183 CHECK(msg->findInt32("generation", &generation)); 184 if (generation != mVideoQueueGeneration) { 185 break; 186 } 187 188 mDrainVideoQueuePending = false; 189 190 onDrainVideoQueue(); 191 192 postDrainVideoQueue(); 193 break; 194 } 195 196 case kWhatQueueBuffer: 197 { 198 onQueueBuffer(msg); 199 break; 200 } 201 202 case kWhatQueueEOS: 203 { 204 onQueueEOS(msg); 205 break; 206 } 207 208 case kWhatFlush: 209 { 210 onFlush(msg); 211 break; 212 } 213 214 case kWhatAudioSinkChanged: 215 { 216 onAudioSinkChanged(); 217 break; 218 } 219 220 case kWhatDisableOffloadAudio: 221 { 222 onDisableOffloadAudio(); 223 break; 224 } 225 226 case kWhatPause: 227 { 228 onPause(); 229 break; 230 } 231 232 case kWhatResume: 233 { 234 onResume(); 235 break; 236 } 237 238 case kWhatAudioOffloadTearDown: 239 { 240 onAudioOffloadTearDown(); 241 break; 242 } 243 244 default: 245 TRESPASS(); 246 break; 247 } 248} 249 250void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { 251 if (mDrainAudioQueuePending || mSyncQueues || mPaused 252 || offloadingAudio()) { 253 return; 254 } 255 256 if (mAudioQueue.empty()) { 257 return; 258 } 259 260 mDrainAudioQueuePending = true; 261 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id()); 262 msg->setInt32("generation", mAudioQueueGeneration); 263 msg->post(delayUs); 264} 265 266void NuPlayer::Renderer::prepareForMediaRenderingStart() { 267 mAudioRenderingStartGeneration = mAudioQueueGeneration; 268 mVideoRenderingStartGeneration = mVideoQueueGeneration; 269} 270 271void NuPlayer::Renderer::notifyIfMediaRenderingStarted() { 272 if (mVideoRenderingStartGeneration == mVideoQueueGeneration && 273 mAudioRenderingStartGeneration == mAudioQueueGeneration) { 274 mVideoRenderingStartGeneration = -1; 275 mAudioRenderingStartGeneration = -1; 276 277 sp<AMessage> notify = mNotify->dup(); 278 notify->setInt32("what", kWhatMediaRenderingStart); 279 notify->post(); 280 } 281} 282 283// static 284size_t NuPlayer::Renderer::AudioSinkCallback( 285 MediaPlayerBase::AudioSink * /* audioSink */, 286 void *buffer, 287 size_t size, 288 void *cookie, 289 MediaPlayerBase::AudioSink::cb_event_t event) { 290 NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie; 291 292 switch (event) { 293 case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER: 294 { 295 return me->fillAudioBuffer(buffer, size); 296 break; 297 } 298 299 case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END: 300 { 301 me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM); 302 break; 303 } 304 305 case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN: 306 { 307 me->notifyAudioOffloadTearDown(); 308 break; 309 } 310 } 311 312 return 0; 313} 314 315size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { 316 Mutex::Autolock autoLock(mLock); 317 318 if (!offloadingAudio()) { 319 return 0; 320 } 321 322 bool hasEOS = false; 323 324 size_t sizeCopied = 0; 325 while (sizeCopied < size && !mAudioQueue.empty()) { 326 QueueEntry *entry = &*mAudioQueue.begin(); 327 328 if (entry->mBuffer == NULL) { // EOS 329 hasEOS = true; 330 mAudioQueue.erase(mAudioQueue.begin()); 331 entry = NULL; 332 break; 333 } 334 335 if (entry->mOffset == 0) { 336 int64_t mediaTimeUs; 337 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 338 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 339 if (mFirstAudioTimeUs == -1) { 340 mFirstAudioTimeUs = mediaTimeUs; 341 } 342 mAnchorTimeMediaUs = mediaTimeUs; 343 344 uint32_t numFramesPlayed; 345 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 346 347 // TODO: figure out how to calculate initial latency. 348 // Otherwise, the initial time is not correct till the first sample 349 // is played. 350 mAnchorTimeMediaUs = mFirstAudioTimeUs 351 + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; 352 mAnchorTimeRealUs = ALooper::GetNowUs(); 353 } 354 355 size_t copy = entry->mBuffer->size() - entry->mOffset; 356 size_t sizeRemaining = size - sizeCopied; 357 if (copy > sizeRemaining) { 358 copy = sizeRemaining; 359 } 360 361 memcpy((char *)buffer + sizeCopied, 362 entry->mBuffer->data() + entry->mOffset, 363 copy); 364 365 entry->mOffset += copy; 366 if (entry->mOffset == entry->mBuffer->size()) { 367 entry->mNotifyConsumed->post(); 368 mAudioQueue.erase(mAudioQueue.begin()); 369 entry = NULL; 370 } 371 sizeCopied += copy; 372 notifyIfMediaRenderingStarted(); 373 } 374 375 if (sizeCopied != 0) { 376 notifyPosition(); 377 } 378 379 if (hasEOS) { 380 (new AMessage(kWhatStopAudioSink, id()))->post(); 381 } 382 383 return sizeCopied; 384} 385 386bool NuPlayer::Renderer::onDrainAudioQueue() { 387 uint32_t numFramesPlayed; 388 if (mAudioSink->getPosition(&numFramesPlayed) != OK) { 389 return false; 390 } 391 392 ssize_t numFramesAvailableToWrite = 393 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); 394 395#if 0 396 if (numFramesAvailableToWrite == mAudioSink->frameCount()) { 397 ALOGI("audio sink underrun"); 398 } else { 399 ALOGV("audio queue has %d frames left to play", 400 mAudioSink->frameCount() - numFramesAvailableToWrite); 401 } 402#endif 403 404 size_t numBytesAvailableToWrite = 405 numFramesAvailableToWrite * mAudioSink->frameSize(); 406 407 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) { 408 QueueEntry *entry = &*mAudioQueue.begin(); 409 410 if (entry->mBuffer == NULL) { 411 // EOS 412 413 notifyEOS(true /* audio */, entry->mFinalResult); 414 415 mAudioQueue.erase(mAudioQueue.begin()); 416 entry = NULL; 417 return false; 418 } 419 420 if (entry->mOffset == 0) { 421 int64_t mediaTimeUs; 422 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 423 424 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 425 426 mAnchorTimeMediaUs = mediaTimeUs; 427 428 uint32_t numFramesPlayed; 429 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 430 431 uint32_t numFramesPendingPlayout = 432 mNumFramesWritten - numFramesPlayed; 433 434 int64_t realTimeOffsetUs = 435 (mAudioSink->latency() / 2 /* XXX */ 436 + numFramesPendingPlayout 437 * mAudioSink->msecsPerFrame()) * 1000ll; 438 439 // ALOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs); 440 441 mAnchorTimeRealUs = 442 ALooper::GetNowUs() + realTimeOffsetUs; 443 } 444 445 size_t copy = entry->mBuffer->size() - entry->mOffset; 446 if (copy > numBytesAvailableToWrite) { 447 copy = numBytesAvailableToWrite; 448 } 449 450 CHECK_EQ(mAudioSink->write( 451 entry->mBuffer->data() + entry->mOffset, copy), 452 (ssize_t)copy); 453 454 entry->mOffset += copy; 455 if (entry->mOffset == entry->mBuffer->size()) { 456 entry->mNotifyConsumed->post(); 457 mAudioQueue.erase(mAudioQueue.begin()); 458 459 entry = NULL; 460 } 461 462 numBytesAvailableToWrite -= copy; 463 size_t copiedFrames = copy / mAudioSink->frameSize(); 464 mNumFramesWritten += copiedFrames; 465 466 notifyIfMediaRenderingStarted(); 467 } 468 469 notifyPosition(); 470 471 return !mAudioQueue.empty(); 472} 473 474void NuPlayer::Renderer::postDrainVideoQueue() { 475 if (mDrainVideoQueuePending || mSyncQueues || mPaused) { 476 return; 477 } 478 479 if (mVideoQueue.empty()) { 480 return; 481 } 482 483 QueueEntry &entry = *mVideoQueue.begin(); 484 485 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id()); 486 msg->setInt32("generation", mVideoQueueGeneration); 487 488 int64_t delayUs; 489 490 if (entry.mBuffer == NULL) { 491 // EOS doesn't carry a timestamp. 492 delayUs = 0; 493 } else if (mFlags & FLAG_REAL_TIME) { 494 int64_t mediaTimeUs; 495 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 496 497 delayUs = mediaTimeUs - ALooper::GetNowUs(); 498 } else { 499 int64_t mediaTimeUs; 500 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 501 502 if (mAnchorTimeMediaUs < 0) { 503 delayUs = 0; 504 505 if (!mHasAudio) { 506 mAnchorTimeMediaUs = mediaTimeUs; 507 mAnchorTimeRealUs = ALooper::GetNowUs(); 508 } 509 } else { 510 int64_t realTimeUs = 511 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs; 512 513 delayUs = realTimeUs - ALooper::GetNowUs(); 514 } 515 } 516 517 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); 518 msg->post(delayUs); 519 520 mDrainVideoQueuePending = true; 521} 522 523void NuPlayer::Renderer::onDrainVideoQueue() { 524 if (mVideoQueue.empty()) { 525 return; 526 } 527 528 QueueEntry *entry = &*mVideoQueue.begin(); 529 530 if (entry->mBuffer == NULL) { 531 // EOS 532 533 notifyEOS(false /* audio */, entry->mFinalResult); 534 535 mVideoQueue.erase(mVideoQueue.begin()); 536 entry = NULL; 537 538 mVideoLateByUs = 0ll; 539 540 notifyPosition(); 541 return; 542 } 543 544 int64_t realTimeUs; 545 if (mFlags & FLAG_REAL_TIME) { 546 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs)); 547 } else { 548 int64_t mediaTimeUs; 549 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 550 551 realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs; 552 } 553 554 mVideoLateByUs = ALooper::GetNowUs() - realTimeUs; 555 bool tooLate = (mVideoLateByUs > 40000); 556 557 if (tooLate) { 558 ALOGV("video late by %lld us (%.2f secs)", 559 mVideoLateByUs, mVideoLateByUs / 1E6); 560 } else { 561 ALOGV("rendering video at media time %.2f secs", 562 (mFlags & FLAG_REAL_TIME ? realTimeUs : 563 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); 564 } 565 566 entry->mNotifyConsumed->setInt32("render", !tooLate); 567 entry->mNotifyConsumed->post(); 568 mVideoQueue.erase(mVideoQueue.begin()); 569 entry = NULL; 570 571 if (!mVideoRenderingStarted) { 572 mVideoRenderingStarted = true; 573 notifyVideoRenderingStart(); 574 } 575 576 notifyIfMediaRenderingStarted(); 577 578 notifyPosition(); 579} 580 581void NuPlayer::Renderer::notifyVideoRenderingStart() { 582 sp<AMessage> notify = mNotify->dup(); 583 notify->setInt32("what", kWhatVideoRenderingStart); 584 notify->post(); 585} 586 587void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) { 588 sp<AMessage> notify = mNotify->dup(); 589 notify->setInt32("what", kWhatEOS); 590 notify->setInt32("audio", static_cast<int32_t>(audio)); 591 notify->setInt32("finalResult", finalResult); 592 notify->post(); 593} 594 595void NuPlayer::Renderer::notifyAudioOffloadTearDown() { 596 (new AMessage(kWhatAudioOffloadTearDown, id()))->post(); 597} 598 599void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { 600 int32_t audio; 601 CHECK(msg->findInt32("audio", &audio)); 602 603 if (audio) { 604 mHasAudio = true; 605 } else { 606 mHasVideo = true; 607 } 608 609 if (dropBufferWhileFlushing(audio, msg)) { 610 return; 611 } 612 613 sp<ABuffer> buffer; 614 CHECK(msg->findBuffer("buffer", &buffer)); 615 616 sp<AMessage> notifyConsumed; 617 CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); 618 619 QueueEntry entry; 620 entry.mBuffer = buffer; 621 entry.mNotifyConsumed = notifyConsumed; 622 entry.mOffset = 0; 623 entry.mFinalResult = OK; 624 625 if (audio) { 626 Mutex::Autolock autoLock(mLock); 627 mAudioQueue.push_back(entry); 628 postDrainAudioQueue_l(); 629 } else { 630 mVideoQueue.push_back(entry); 631 postDrainVideoQueue(); 632 } 633 634 Mutex::Autolock autoLock(mLock); 635 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { 636 return; 637 } 638 639 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; 640 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; 641 642 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { 643 // EOS signalled on either queue. 644 syncQueuesDone_l(); 645 return; 646 } 647 648 int64_t firstAudioTimeUs; 649 int64_t firstVideoTimeUs; 650 CHECK(firstAudioBuffer->meta() 651 ->findInt64("timeUs", &firstAudioTimeUs)); 652 CHECK(firstVideoBuffer->meta() 653 ->findInt64("timeUs", &firstVideoTimeUs)); 654 655 int64_t diff = firstVideoTimeUs - firstAudioTimeUs; 656 657 ALOGV("queueDiff = %.2f secs", diff / 1E6); 658 659 if (diff > 100000ll) { 660 // Audio data starts More than 0.1 secs before video. 661 // Drop some audio. 662 663 (*mAudioQueue.begin()).mNotifyConsumed->post(); 664 mAudioQueue.erase(mAudioQueue.begin()); 665 return; 666 } 667 668 syncQueuesDone_l(); 669} 670 671void NuPlayer::Renderer::syncQueuesDone_l() { 672 if (!mSyncQueues) { 673 return; 674 } 675 676 mSyncQueues = false; 677 678 if (!mAudioQueue.empty()) { 679 postDrainAudioQueue_l(); 680 } 681 682 if (!mVideoQueue.empty()) { 683 postDrainVideoQueue(); 684 } 685} 686 687void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { 688 int32_t audio; 689 CHECK(msg->findInt32("audio", &audio)); 690 691 if (dropBufferWhileFlushing(audio, msg)) { 692 return; 693 } 694 695 int32_t finalResult; 696 CHECK(msg->findInt32("finalResult", &finalResult)); 697 698 QueueEntry entry; 699 entry.mOffset = 0; 700 entry.mFinalResult = finalResult; 701 702 if (audio) { 703 Mutex::Autolock autoLock(mLock); 704 if (mAudioQueue.empty() && mSyncQueues) { 705 syncQueuesDone_l(); 706 } 707 mAudioQueue.push_back(entry); 708 postDrainAudioQueue_l(); 709 } else { 710 if (mVideoQueue.empty() && mSyncQueues) { 711 Mutex::Autolock autoLock(mLock); 712 syncQueuesDone_l(); 713 } 714 mVideoQueue.push_back(entry); 715 postDrainVideoQueue(); 716 } 717} 718 719void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { 720 int32_t audio; 721 CHECK(msg->findInt32("audio", &audio)); 722 723 { 724 Mutex::Autolock autoLock(mFlushLock); 725 if (audio) { 726 mFlushingAudio = false; 727 } else { 728 mFlushingVideo = false; 729 } 730 } 731 732 // If we're currently syncing the queues, i.e. dropping audio while 733 // aligning the first audio/video buffer times and only one of the 734 // two queues has data, we may starve that queue by not requesting 735 // more buffers from the decoder. If the other source then encounters 736 // a discontinuity that leads to flushing, we'll never find the 737 // corresponding discontinuity on the other queue. 738 // Therefore we'll stop syncing the queues if at least one of them 739 // is flushed. 740 { 741 Mutex::Autolock autoLock(mLock); 742 syncQueuesDone_l(); 743 } 744 745 ALOGV("flushing %s", audio ? "audio" : "video"); 746 if (audio) { 747 { 748 Mutex::Autolock autoLock(mLock); 749 flushQueue(&mAudioQueue); 750 751 ++mAudioQueueGeneration; 752 prepareForMediaRenderingStart(); 753 754 if (offloadingAudio()) { 755 mFirstAudioTimeUs = -1; 756 } 757 } 758 759 mDrainAudioQueuePending = false; 760 761 if (offloadingAudio()) { 762 mAudioSink->pause(); 763 mAudioSink->flush(); 764 mAudioSink->start(); 765 } 766 } else { 767 flushQueue(&mVideoQueue); 768 769 mDrainVideoQueuePending = false; 770 ++mVideoQueueGeneration; 771 772 prepareForMediaRenderingStart(); 773 } 774 775 notifyFlushComplete(audio); 776} 777 778void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { 779 while (!queue->empty()) { 780 QueueEntry *entry = &*queue->begin(); 781 782 if (entry->mBuffer != NULL) { 783 entry->mNotifyConsumed->post(); 784 } 785 786 queue->erase(queue->begin()); 787 entry = NULL; 788 } 789} 790 791void NuPlayer::Renderer::notifyFlushComplete(bool audio) { 792 sp<AMessage> notify = mNotify->dup(); 793 notify->setInt32("what", kWhatFlushComplete); 794 notify->setInt32("audio", static_cast<int32_t>(audio)); 795 notify->post(); 796} 797 798bool NuPlayer::Renderer::dropBufferWhileFlushing( 799 bool audio, const sp<AMessage> &msg) { 800 bool flushing = false; 801 802 { 803 Mutex::Autolock autoLock(mFlushLock); 804 if (audio) { 805 flushing = mFlushingAudio; 806 } else { 807 flushing = mFlushingVideo; 808 } 809 } 810 811 if (!flushing) { 812 return false; 813 } 814 815 sp<AMessage> notifyConsumed; 816 if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) { 817 notifyConsumed->post(); 818 } 819 820 return true; 821} 822 823void NuPlayer::Renderer::onAudioSinkChanged() { 824 if (offloadingAudio()) { 825 return; 826 } 827 CHECK(!mDrainAudioQueuePending); 828 mNumFramesWritten = 0; 829 uint32_t written; 830 if (mAudioSink->getFramesWritten(&written) == OK) { 831 mNumFramesWritten = written; 832 } 833} 834 835void NuPlayer::Renderer::onDisableOffloadAudio() { 836 Mutex::Autolock autoLock(mLock); 837 mFlags &= ~FLAG_OFFLOAD_AUDIO; 838 ++mAudioQueueGeneration; 839} 840 841void NuPlayer::Renderer::notifyPosition() { 842 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { 843 return; 844 } 845 846 int64_t nowUs = ALooper::GetNowUs(); 847 848 if (mLastPositionUpdateUs >= 0 849 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) { 850 return; 851 } 852 mLastPositionUpdateUs = nowUs; 853 854 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; 855 856 sp<AMessage> notify = mNotify->dup(); 857 notify->setInt32("what", kWhatPosition); 858 notify->setInt64("positionUs", positionUs); 859 notify->setInt64("videoLateByUs", mVideoLateByUs); 860 notify->post(); 861} 862 863void NuPlayer::Renderer::onPause() { 864 CHECK(!mPaused); 865 866 { 867 Mutex::Autolock autoLock(mLock); 868 ++mAudioQueueGeneration; 869 ++mVideoQueueGeneration; 870 prepareForMediaRenderingStart(); 871 } 872 873 mDrainAudioQueuePending = false; 874 mDrainVideoQueuePending = false; 875 876 if (mHasAudio) { 877 mAudioSink->pause(); 878 } 879 880 ALOGV("now paused audio queue has %d entries, video has %d entries", 881 mAudioQueue.size(), mVideoQueue.size()); 882 883 mPaused = true; 884} 885 886void NuPlayer::Renderer::onResume() { 887 if (!mPaused) { 888 return; 889 } 890 891 if (mHasAudio) { 892 mAudioSink->start(); 893 } 894 895 mPaused = false; 896 897 Mutex::Autolock autoLock(mLock); 898 if (!mAudioQueue.empty()) { 899 postDrainAudioQueue_l(); 900 } 901 902 if (!mVideoQueue.empty()) { 903 postDrainVideoQueue(); 904 } 905} 906 907void NuPlayer::Renderer::onAudioOffloadTearDown() { 908 uint32_t numFramesPlayed; 909 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 910 911 int64_t firstAudioTimeUs; 912 { 913 Mutex::Autolock autoLock(mLock); 914 firstAudioTimeUs = mFirstAudioTimeUs; 915 } 916 int64_t currentPositionUs = firstAudioTimeUs 917 + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; 918 919 mAudioSink->stop(); 920 mAudioSink->flush(); 921 922 sp<AMessage> notify = mNotify->dup(); 923 notify->setInt32("what", kWhatAudioOffloadTearDown); 924 notify->setInt64("positionUs", currentPositionUs); 925 notify->post(); 926} 927 928} // namespace android 929 930