NuPlayerRenderer.cpp revision 5095d7091874cb9e9c95ecc4fe762076ed05e624
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 bool firstEntry = true; 326 while (sizeCopied < size && !mAudioQueue.empty()) { 327 QueueEntry *entry = &*mAudioQueue.begin(); 328 329 if (entry->mBuffer == NULL) { // EOS 330 hasEOS = true; 331 mAudioQueue.erase(mAudioQueue.begin()); 332 entry = NULL; 333 break; 334 } 335 336 if (firstEntry && entry->mOffset == 0) { 337 firstEntry = false; 338 int64_t mediaTimeUs; 339 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 340 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 341 if (mFirstAudioTimeUs == -1) { 342 mFirstAudioTimeUs = mediaTimeUs; 343 } 344 345 uint32_t numFramesPlayed; 346 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 347 348 // TODO: figure out how to calculate initial latency. 349 // Otherwise, the initial time is not correct till the first sample 350 // is played. 351 mAnchorTimeMediaUs = mFirstAudioTimeUs 352 + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; 353 mAnchorTimeRealUs = ALooper::GetNowUs(); 354 } 355 356 size_t copy = entry->mBuffer->size() - entry->mOffset; 357 size_t sizeRemaining = size - sizeCopied; 358 if (copy > sizeRemaining) { 359 copy = sizeRemaining; 360 } 361 362 memcpy((char *)buffer + sizeCopied, 363 entry->mBuffer->data() + entry->mOffset, 364 copy); 365 366 entry->mOffset += copy; 367 if (entry->mOffset == entry->mBuffer->size()) { 368 entry->mNotifyConsumed->post(); 369 mAudioQueue.erase(mAudioQueue.begin()); 370 entry = NULL; 371 } 372 sizeCopied += copy; 373 notifyIfMediaRenderingStarted(); 374 } 375 376 if (sizeCopied != 0) { 377 notifyPosition(); 378 } 379 380 if (hasEOS) { 381 (new AMessage(kWhatStopAudioSink, id()))->post(); 382 } 383 384 return sizeCopied; 385} 386 387bool NuPlayer::Renderer::onDrainAudioQueue() { 388 uint32_t numFramesPlayed; 389 if (mAudioSink->getPosition(&numFramesPlayed) != OK) { 390 return false; 391 } 392 393 ssize_t numFramesAvailableToWrite = 394 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); 395 396#if 0 397 if (numFramesAvailableToWrite == mAudioSink->frameCount()) { 398 ALOGI("audio sink underrun"); 399 } else { 400 ALOGV("audio queue has %d frames left to play", 401 mAudioSink->frameCount() - numFramesAvailableToWrite); 402 } 403#endif 404 405 size_t numBytesAvailableToWrite = 406 numFramesAvailableToWrite * mAudioSink->frameSize(); 407 408 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) { 409 QueueEntry *entry = &*mAudioQueue.begin(); 410 411 if (entry->mBuffer == NULL) { 412 // EOS 413 int64_t postEOSDelayUs = 0; 414 if (mAudioSink->needsTrailingPadding()) { 415 postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency(); 416 } 417 notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs); 418 419 mAudioQueue.erase(mAudioQueue.begin()); 420 entry = NULL; 421 return false; 422 } 423 424 if (entry->mOffset == 0) { 425 int64_t mediaTimeUs; 426 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 427 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 428 mAnchorTimeMediaUs = mediaTimeUs; 429 430 mAnchorTimeRealUs = ALooper::GetNowUs() 431 + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2; 432 } 433 434 size_t copy = entry->mBuffer->size() - entry->mOffset; 435 if (copy > numBytesAvailableToWrite) { 436 copy = numBytesAvailableToWrite; 437 } 438 439 ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy); 440 if (written < 0) { 441 // An error in AudioSink write is fatal here. 442 LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy); 443 } 444 445 entry->mOffset += written; 446 if (entry->mOffset == entry->mBuffer->size()) { 447 entry->mNotifyConsumed->post(); 448 mAudioQueue.erase(mAudioQueue.begin()); 449 450 entry = NULL; 451 } 452 453 numBytesAvailableToWrite -= written; 454 size_t copiedFrames = written / mAudioSink->frameSize(); 455 mNumFramesWritten += copiedFrames; 456 457 notifyIfMediaRenderingStarted(); 458 459 if (written != (ssize_t)copy) { 460 // A short count was received from AudioSink::write() 461 // 462 // AudioSink write should block until exactly the number of bytes are delivered. 463 // But it may return with a short count (without an error) when: 464 // 465 // 1) Size to be copied is not a multiple of the frame size. We consider this fatal. 466 // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded. 467 468 // (Case 1) 469 // Must be a multiple of the frame size. If it is not a multiple of a frame size, it 470 // needs to fail, as we should not carry over fractional frames between calls. 471 CHECK_EQ(copy % mAudioSink->frameSize(), 0); 472 473 // (Case 2) 474 // Return early to the caller. 475 // Beware of calling immediately again as this may busy-loop if you are not careful. 476 ALOGW("AudioSink write short frame count %zd < %zu", written, copy); 477 break; 478 } 479 } 480 notifyPosition(); 481 482 return !mAudioQueue.empty(); 483} 484 485int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() { 486 uint32_t numFramesPlayed; 487 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 488 489 uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed; 490 return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000; 491} 492 493void NuPlayer::Renderer::postDrainVideoQueue() { 494 if (mDrainVideoQueuePending || mSyncQueues || mPaused) { 495 return; 496 } 497 498 if (mVideoQueue.empty()) { 499 return; 500 } 501 502 QueueEntry &entry = *mVideoQueue.begin(); 503 504 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id()); 505 msg->setInt32("generation", mVideoQueueGeneration); 506 507 int64_t delayUs; 508 509 if (entry.mBuffer == NULL) { 510 // EOS doesn't carry a timestamp. 511 delayUs = 0; 512 } else if (mFlags & FLAG_REAL_TIME) { 513 int64_t mediaTimeUs; 514 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 515 516 delayUs = mediaTimeUs - ALooper::GetNowUs(); 517 } else { 518 int64_t mediaTimeUs; 519 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 520 521 if (mAnchorTimeMediaUs < 0) { 522 delayUs = 0; 523 524 if (!mHasAudio) { 525 mAnchorTimeMediaUs = mediaTimeUs; 526 mAnchorTimeRealUs = ALooper::GetNowUs(); 527 } 528 } else { 529 int64_t realTimeUs = 530 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs; 531 532 delayUs = realTimeUs - ALooper::GetNowUs(); 533 } 534 } 535 536 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); 537 msg->post(delayUs); 538 539 mDrainVideoQueuePending = true; 540} 541 542void NuPlayer::Renderer::onDrainVideoQueue() { 543 if (mVideoQueue.empty()) { 544 return; 545 } 546 547 QueueEntry *entry = &*mVideoQueue.begin(); 548 549 if (entry->mBuffer == NULL) { 550 // EOS 551 552 notifyEOS(false /* audio */, entry->mFinalResult); 553 554 mVideoQueue.erase(mVideoQueue.begin()); 555 entry = NULL; 556 557 mVideoLateByUs = 0ll; 558 559 notifyPosition(); 560 return; 561 } 562 563 int64_t realTimeUs; 564 if (mFlags & FLAG_REAL_TIME) { 565 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs)); 566 } else { 567 int64_t mediaTimeUs; 568 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 569 570 realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs; 571 } 572 573 mVideoLateByUs = ALooper::GetNowUs() - realTimeUs; 574 bool tooLate = (mVideoLateByUs > 40000); 575 576 if (tooLate) { 577 ALOGV("video late by %lld us (%.2f secs)", 578 mVideoLateByUs, mVideoLateByUs / 1E6); 579 } else { 580 ALOGV("rendering video at media time %.2f secs", 581 (mFlags & FLAG_REAL_TIME ? realTimeUs : 582 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); 583 } 584 585 entry->mNotifyConsumed->setInt32("render", !tooLate); 586 entry->mNotifyConsumed->post(); 587 mVideoQueue.erase(mVideoQueue.begin()); 588 entry = NULL; 589 590 if (!mVideoRenderingStarted) { 591 mVideoRenderingStarted = true; 592 notifyVideoRenderingStart(); 593 } 594 595 notifyIfMediaRenderingStarted(); 596 597 notifyPosition(); 598} 599 600void NuPlayer::Renderer::notifyVideoRenderingStart() { 601 sp<AMessage> notify = mNotify->dup(); 602 notify->setInt32("what", kWhatVideoRenderingStart); 603 notify->post(); 604} 605 606void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) { 607 sp<AMessage> notify = mNotify->dup(); 608 notify->setInt32("what", kWhatEOS); 609 notify->setInt32("audio", static_cast<int32_t>(audio)); 610 notify->setInt32("finalResult", finalResult); 611 notify->post(delayUs); 612} 613 614void NuPlayer::Renderer::notifyAudioOffloadTearDown() { 615 (new AMessage(kWhatAudioOffloadTearDown, id()))->post(); 616} 617 618void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { 619 int32_t audio; 620 CHECK(msg->findInt32("audio", &audio)); 621 622 if (audio) { 623 mHasAudio = true; 624 } else { 625 mHasVideo = true; 626 } 627 628 if (dropBufferWhileFlushing(audio, msg)) { 629 return; 630 } 631 632 sp<ABuffer> buffer; 633 CHECK(msg->findBuffer("buffer", &buffer)); 634 635 sp<AMessage> notifyConsumed; 636 CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); 637 638 QueueEntry entry; 639 entry.mBuffer = buffer; 640 entry.mNotifyConsumed = notifyConsumed; 641 entry.mOffset = 0; 642 entry.mFinalResult = OK; 643 644 if (audio) { 645 Mutex::Autolock autoLock(mLock); 646 mAudioQueue.push_back(entry); 647 postDrainAudioQueue_l(); 648 } else { 649 mVideoQueue.push_back(entry); 650 postDrainVideoQueue(); 651 } 652 653 Mutex::Autolock autoLock(mLock); 654 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { 655 return; 656 } 657 658 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; 659 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; 660 661 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { 662 // EOS signalled on either queue. 663 syncQueuesDone_l(); 664 return; 665 } 666 667 int64_t firstAudioTimeUs; 668 int64_t firstVideoTimeUs; 669 CHECK(firstAudioBuffer->meta() 670 ->findInt64("timeUs", &firstAudioTimeUs)); 671 CHECK(firstVideoBuffer->meta() 672 ->findInt64("timeUs", &firstVideoTimeUs)); 673 674 int64_t diff = firstVideoTimeUs - firstAudioTimeUs; 675 676 ALOGV("queueDiff = %.2f secs", diff / 1E6); 677 678 if (diff > 100000ll) { 679 // Audio data starts More than 0.1 secs before video. 680 // Drop some audio. 681 682 (*mAudioQueue.begin()).mNotifyConsumed->post(); 683 mAudioQueue.erase(mAudioQueue.begin()); 684 return; 685 } 686 687 syncQueuesDone_l(); 688} 689 690void NuPlayer::Renderer::syncQueuesDone_l() { 691 if (!mSyncQueues) { 692 return; 693 } 694 695 mSyncQueues = false; 696 697 if (!mAudioQueue.empty()) { 698 postDrainAudioQueue_l(); 699 } 700 701 if (!mVideoQueue.empty()) { 702 postDrainVideoQueue(); 703 } 704} 705 706void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { 707 int32_t audio; 708 CHECK(msg->findInt32("audio", &audio)); 709 710 if (dropBufferWhileFlushing(audio, msg)) { 711 return; 712 } 713 714 int32_t finalResult; 715 CHECK(msg->findInt32("finalResult", &finalResult)); 716 717 QueueEntry entry; 718 entry.mOffset = 0; 719 entry.mFinalResult = finalResult; 720 721 if (audio) { 722 Mutex::Autolock autoLock(mLock); 723 if (mAudioQueue.empty() && mSyncQueues) { 724 syncQueuesDone_l(); 725 } 726 mAudioQueue.push_back(entry); 727 postDrainAudioQueue_l(); 728 } else { 729 if (mVideoQueue.empty() && mSyncQueues) { 730 Mutex::Autolock autoLock(mLock); 731 syncQueuesDone_l(); 732 } 733 mVideoQueue.push_back(entry); 734 postDrainVideoQueue(); 735 } 736} 737 738void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { 739 int32_t audio; 740 CHECK(msg->findInt32("audio", &audio)); 741 742 { 743 Mutex::Autolock autoLock(mFlushLock); 744 if (audio) { 745 mFlushingAudio = false; 746 } else { 747 mFlushingVideo = false; 748 } 749 } 750 751 // If we're currently syncing the queues, i.e. dropping audio while 752 // aligning the first audio/video buffer times and only one of the 753 // two queues has data, we may starve that queue by not requesting 754 // more buffers from the decoder. If the other source then encounters 755 // a discontinuity that leads to flushing, we'll never find the 756 // corresponding discontinuity on the other queue. 757 // Therefore we'll stop syncing the queues if at least one of them 758 // is flushed. 759 { 760 Mutex::Autolock autoLock(mLock); 761 syncQueuesDone_l(); 762 } 763 764 ALOGV("flushing %s", audio ? "audio" : "video"); 765 if (audio) { 766 { 767 Mutex::Autolock autoLock(mLock); 768 flushQueue(&mAudioQueue); 769 770 ++mAudioQueueGeneration; 771 prepareForMediaRenderingStart(); 772 773 if (offloadingAudio()) { 774 mFirstAudioTimeUs = -1; 775 } 776 } 777 778 mDrainAudioQueuePending = false; 779 780 if (offloadingAudio()) { 781 mAudioSink->pause(); 782 mAudioSink->flush(); 783 mAudioSink->start(); 784 } 785 } else { 786 flushQueue(&mVideoQueue); 787 788 mDrainVideoQueuePending = false; 789 ++mVideoQueueGeneration; 790 791 prepareForMediaRenderingStart(); 792 } 793 794 notifyFlushComplete(audio); 795} 796 797void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { 798 while (!queue->empty()) { 799 QueueEntry *entry = &*queue->begin(); 800 801 if (entry->mBuffer != NULL) { 802 entry->mNotifyConsumed->post(); 803 } 804 805 queue->erase(queue->begin()); 806 entry = NULL; 807 } 808} 809 810void NuPlayer::Renderer::notifyFlushComplete(bool audio) { 811 sp<AMessage> notify = mNotify->dup(); 812 notify->setInt32("what", kWhatFlushComplete); 813 notify->setInt32("audio", static_cast<int32_t>(audio)); 814 notify->post(); 815} 816 817bool NuPlayer::Renderer::dropBufferWhileFlushing( 818 bool audio, const sp<AMessage> &msg) { 819 bool flushing = false; 820 821 { 822 Mutex::Autolock autoLock(mFlushLock); 823 if (audio) { 824 flushing = mFlushingAudio; 825 } else { 826 flushing = mFlushingVideo; 827 } 828 } 829 830 if (!flushing) { 831 return false; 832 } 833 834 sp<AMessage> notifyConsumed; 835 if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) { 836 notifyConsumed->post(); 837 } 838 839 return true; 840} 841 842void NuPlayer::Renderer::onAudioSinkChanged() { 843 if (offloadingAudio()) { 844 return; 845 } 846 CHECK(!mDrainAudioQueuePending); 847 mNumFramesWritten = 0; 848 uint32_t written; 849 if (mAudioSink->getFramesWritten(&written) == OK) { 850 mNumFramesWritten = written; 851 } 852} 853 854void NuPlayer::Renderer::onDisableOffloadAudio() { 855 Mutex::Autolock autoLock(mLock); 856 mFlags &= ~FLAG_OFFLOAD_AUDIO; 857 ++mAudioQueueGeneration; 858} 859 860void NuPlayer::Renderer::notifyPosition() { 861 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { 862 return; 863 } 864 865 int64_t nowUs = ALooper::GetNowUs(); 866 867 if (mLastPositionUpdateUs >= 0 868 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) { 869 return; 870 } 871 mLastPositionUpdateUs = nowUs; 872 873 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; 874 875 sp<AMessage> notify = mNotify->dup(); 876 notify->setInt32("what", kWhatPosition); 877 notify->setInt64("positionUs", positionUs); 878 notify->setInt64("videoLateByUs", mVideoLateByUs); 879 notify->post(); 880} 881 882void NuPlayer::Renderer::onPause() { 883 CHECK(!mPaused); 884 885 { 886 Mutex::Autolock autoLock(mLock); 887 ++mAudioQueueGeneration; 888 ++mVideoQueueGeneration; 889 prepareForMediaRenderingStart(); 890 } 891 892 mDrainAudioQueuePending = false; 893 mDrainVideoQueuePending = false; 894 895 if (mHasAudio) { 896 mAudioSink->pause(); 897 } 898 899 ALOGV("now paused audio queue has %d entries, video has %d entries", 900 mAudioQueue.size(), mVideoQueue.size()); 901 902 mPaused = true; 903} 904 905void NuPlayer::Renderer::onResume() { 906 if (!mPaused) { 907 return; 908 } 909 910 if (mHasAudio) { 911 mAudioSink->start(); 912 } 913 914 mPaused = false; 915 916 Mutex::Autolock autoLock(mLock); 917 if (!mAudioQueue.empty()) { 918 postDrainAudioQueue_l(); 919 } 920 921 if (!mVideoQueue.empty()) { 922 postDrainVideoQueue(); 923 } 924} 925 926void NuPlayer::Renderer::onAudioOffloadTearDown() { 927 uint32_t numFramesPlayed; 928 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); 929 930 int64_t firstAudioTimeUs; 931 { 932 Mutex::Autolock autoLock(mLock); 933 firstAudioTimeUs = mFirstAudioTimeUs; 934 } 935 int64_t currentPositionUs = firstAudioTimeUs 936 + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll; 937 938 mAudioSink->stop(); 939 mAudioSink->flush(); 940 941 sp<AMessage> notify = mNotify->dup(); 942 notify->setInt32("what", kWhatAudioOffloadTearDown); 943 notify->setInt64("positionUs", currentPositionUs); 944 notify->post(); 945} 946 947} // namespace android 948 949