NuPlayerRenderer.cpp revision cec7febc48ff76b293ace0cc12a6288f13f72293
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/foundation/AUtils.h> 27#include <media/stagefright/MediaErrors.h> 28#include <media/stagefright/MetaData.h> 29#include <media/stagefright/Utils.h> 30 31#include <VideoFrameScheduler.h> 32 33#include <inttypes.h> 34 35namespace android { 36 37// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink 38// is closed to allow the audio DSP to power down. 39static const int64_t kOffloadPauseMaxUs = 10000000ll; 40 41// static 42const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; 43 44NuPlayer::Renderer::Renderer( 45 const sp<MediaPlayerBase::AudioSink> &sink, 46 const sp<AMessage> ¬ify, 47 uint32_t flags) 48 : mAudioSink(sink), 49 mNotify(notify), 50 mFlags(flags), 51 mNumFramesWritten(0), 52 mDrainAudioQueuePending(false), 53 mDrainVideoQueuePending(false), 54 mAudioQueueGeneration(0), 55 mVideoQueueGeneration(0), 56 mAudioFirstAnchorTimeMediaUs(-1), 57 mAnchorTimeMediaUs(-1), 58 mAnchorTimeRealUs(-1), 59 mAnchorNumFramesWritten(-1), 60 mAnchorMaxMediaUs(-1), 61 mVideoLateByUs(0ll), 62 mHasAudio(false), 63 mHasVideo(false), 64 mPauseStartedTimeRealUs(-1), 65 mFlushingAudio(false), 66 mFlushingVideo(false), 67 mNotifyCompleteAudio(false), 68 mNotifyCompleteVideo(false), 69 mSyncQueues(false), 70 mPaused(false), 71 mPausePositionMediaTimeUs(-1), 72 mVideoSampleReceived(false), 73 mVideoRenderingStarted(false), 74 mVideoRenderingStartGeneration(0), 75 mAudioRenderingStartGeneration(0), 76 mAudioOffloadPauseTimeoutGeneration(0), 77 mAudioOffloadTornDown(false), 78 mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), 79 mTotalBuffersQueued(0), 80 mLastAudioBufferDrained(0) { 81} 82 83NuPlayer::Renderer::~Renderer() { 84 if (offloadingAudio()) { 85 mAudioSink->stop(); 86 mAudioSink->flush(); 87 mAudioSink->close(); 88 } 89} 90 91void NuPlayer::Renderer::queueBuffer( 92 bool audio, 93 const sp<ABuffer> &buffer, 94 const sp<AMessage> ¬ifyConsumed) { 95 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id()); 96 msg->setInt32("audio", static_cast<int32_t>(audio)); 97 msg->setBuffer("buffer", buffer); 98 msg->setMessage("notifyConsumed", notifyConsumed); 99 msg->post(); 100} 101 102void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { 103 CHECK_NE(finalResult, (status_t)OK); 104 105 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id()); 106 msg->setInt32("audio", static_cast<int32_t>(audio)); 107 msg->setInt32("finalResult", finalResult); 108 msg->post(); 109} 110 111void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) { 112 { 113 Mutex::Autolock autoLock(mFlushLock); 114 if (audio) { 115 mNotifyCompleteAudio |= notifyComplete; 116 if (mFlushingAudio) { 117 return; 118 } 119 mFlushingAudio = true; 120 } else { 121 mNotifyCompleteVideo |= notifyComplete; 122 if (mFlushingVideo) { 123 return; 124 } 125 mFlushingVideo = true; 126 } 127 } 128 129 sp<AMessage> msg = new AMessage(kWhatFlush, id()); 130 msg->setInt32("audio", static_cast<int32_t>(audio)); 131 msg->post(); 132} 133 134void NuPlayer::Renderer::signalTimeDiscontinuity() { 135 Mutex::Autolock autoLock(mLock); 136 // CHECK(mAudioQueue.empty()); 137 // CHECK(mVideoQueue.empty()); 138 setAudioFirstAnchorTime(-1); 139 setAnchorTime(-1, -1); 140 setVideoLateByUs(0); 141 mSyncQueues = false; 142} 143 144void NuPlayer::Renderer::signalAudioSinkChanged() { 145 (new AMessage(kWhatAudioSinkChanged, id()))->post(); 146} 147 148void NuPlayer::Renderer::signalDisableOffloadAudio() { 149 (new AMessage(kWhatDisableOffloadAudio, id()))->post(); 150} 151 152void NuPlayer::Renderer::signalEnableOffloadAudio() { 153 (new AMessage(kWhatEnableOffloadAudio, id()))->post(); 154} 155 156void NuPlayer::Renderer::pause() { 157 (new AMessage(kWhatPause, id()))->post(); 158} 159 160void NuPlayer::Renderer::resume() { 161 (new AMessage(kWhatResume, id()))->post(); 162} 163 164void NuPlayer::Renderer::setVideoFrameRate(float fps) { 165 sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, id()); 166 msg->setFloat("frame-rate", fps); 167 msg->post(); 168} 169 170// Called on any threads, except renderer's thread. 171status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) { 172 { 173 Mutex::Autolock autoLock(mLock); 174 int64_t currentPositionUs; 175 if (getCurrentPositionIfPaused_l(¤tPositionUs)) { 176 *mediaUs = currentPositionUs; 177 return OK; 178 } 179 } 180 return getCurrentPositionFromAnchor(mediaUs, ALooper::GetNowUs()); 181} 182 183// Called on only renderer's thread. 184status_t NuPlayer::Renderer::getCurrentPositionOnLooper(int64_t *mediaUs) { 185 return getCurrentPositionOnLooper(mediaUs, ALooper::GetNowUs()); 186} 187 188// Called on only renderer's thread. 189// Since mPaused and mPausePositionMediaTimeUs are changed only on renderer's 190// thread, no need to acquire mLock. 191status_t NuPlayer::Renderer::getCurrentPositionOnLooper( 192 int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) { 193 int64_t currentPositionUs; 194 if (getCurrentPositionIfPaused_l(¤tPositionUs)) { 195 *mediaUs = currentPositionUs; 196 return OK; 197 } 198 return getCurrentPositionFromAnchor(mediaUs, nowUs, allowPastQueuedVideo); 199} 200 201// Called either with mLock acquired or on renderer's thread. 202bool NuPlayer::Renderer::getCurrentPositionIfPaused_l(int64_t *mediaUs) { 203 if (!mPaused || mPausePositionMediaTimeUs < 0ll) { 204 return false; 205 } 206 *mediaUs = mPausePositionMediaTimeUs; 207 return true; 208} 209 210// Called on any threads. 211status_t NuPlayer::Renderer::getCurrentPositionFromAnchor( 212 int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) { 213 Mutex::Autolock autoLock(mTimeLock); 214 if (!mHasAudio && !mHasVideo) { 215 return NO_INIT; 216 } 217 218 if (mAnchorTimeMediaUs < 0) { 219 return NO_INIT; 220 } 221 222 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; 223 224 if (mPauseStartedTimeRealUs != -1) { 225 positionUs -= (nowUs - mPauseStartedTimeRealUs); 226 } 227 228 // limit position to the last queued media time (for video only stream 229 // position will be discrete as we don't know how long each frame lasts) 230 if (mAnchorMaxMediaUs >= 0 && !allowPastQueuedVideo) { 231 if (positionUs > mAnchorMaxMediaUs) { 232 positionUs = mAnchorMaxMediaUs; 233 } 234 } 235 236 if (positionUs < mAudioFirstAnchorTimeMediaUs) { 237 positionUs = mAudioFirstAnchorTimeMediaUs; 238 } 239 240 *mediaUs = (positionUs <= 0) ? 0 : positionUs; 241 return OK; 242} 243 244void NuPlayer::Renderer::setHasMedia(bool audio) { 245 Mutex::Autolock autoLock(mTimeLock); 246 if (audio) { 247 mHasAudio = true; 248 } else { 249 mHasVideo = true; 250 } 251} 252 253void NuPlayer::Renderer::setAudioFirstAnchorTime(int64_t mediaUs) { 254 Mutex::Autolock autoLock(mTimeLock); 255 mAudioFirstAnchorTimeMediaUs = mediaUs; 256} 257 258void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) { 259 Mutex::Autolock autoLock(mTimeLock); 260 if (mAudioFirstAnchorTimeMediaUs == -1) { 261 mAudioFirstAnchorTimeMediaUs = mediaUs; 262 } 263} 264 265void NuPlayer::Renderer::setAnchorTime( 266 int64_t mediaUs, int64_t realUs, int64_t numFramesWritten, bool resume) { 267 Mutex::Autolock autoLock(mTimeLock); 268 mAnchorTimeMediaUs = mediaUs; 269 mAnchorTimeRealUs = realUs; 270 mAnchorNumFramesWritten = numFramesWritten; 271 if (resume) { 272 mPauseStartedTimeRealUs = -1; 273 } 274} 275 276void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) { 277 Mutex::Autolock autoLock(mTimeLock); 278 mVideoLateByUs = lateUs; 279} 280 281int64_t NuPlayer::Renderer::getVideoLateByUs() { 282 Mutex::Autolock autoLock(mTimeLock); 283 return mVideoLateByUs; 284} 285 286void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) { 287 Mutex::Autolock autoLock(mTimeLock); 288 mPauseStartedTimeRealUs = realUs; 289} 290 291status_t NuPlayer::Renderer::openAudioSink( 292 const sp<AMessage> &format, 293 bool offloadOnly, 294 bool hasVideo, 295 uint32_t flags, 296 bool *isOffloaded) { 297 sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, id()); 298 msg->setMessage("format", format); 299 msg->setInt32("offload-only", offloadOnly); 300 msg->setInt32("has-video", hasVideo); 301 msg->setInt32("flags", flags); 302 303 sp<AMessage> response; 304 msg->postAndAwaitResponse(&response); 305 306 int32_t err; 307 if (!response->findInt32("err", &err)) { 308 err = INVALID_OPERATION; 309 } else if (err == OK && isOffloaded != NULL) { 310 int32_t offload; 311 CHECK(response->findInt32("offload", &offload)); 312 *isOffloaded = (offload != 0); 313 } 314 return err; 315} 316 317void NuPlayer::Renderer::closeAudioSink() { 318 sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, id()); 319 320 sp<AMessage> response; 321 msg->postAndAwaitResponse(&response); 322} 323 324void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { 325 switch (msg->what()) { 326 case kWhatOpenAudioSink: 327 { 328 sp<AMessage> format; 329 CHECK(msg->findMessage("format", &format)); 330 331 int32_t offloadOnly; 332 CHECK(msg->findInt32("offload-only", &offloadOnly)); 333 334 int32_t hasVideo; 335 CHECK(msg->findInt32("has-video", &hasVideo)); 336 337 uint32_t flags; 338 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 339 340 status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags); 341 342 sp<AMessage> response = new AMessage; 343 response->setInt32("err", err); 344 response->setInt32("offload", offloadingAudio()); 345 346 uint32_t replyID; 347 CHECK(msg->senderAwaitsResponse(&replyID)); 348 response->postReply(replyID); 349 350 break; 351 } 352 353 case kWhatCloseAudioSink: 354 { 355 uint32_t replyID; 356 CHECK(msg->senderAwaitsResponse(&replyID)); 357 358 onCloseAudioSink(); 359 360 sp<AMessage> response = new AMessage; 361 response->postReply(replyID); 362 break; 363 } 364 365 case kWhatStopAudioSink: 366 { 367 mAudioSink->stop(); 368 break; 369 } 370 371 case kWhatDrainAudioQueue: 372 { 373 int32_t generation; 374 CHECK(msg->findInt32("generation", &generation)); 375 if (generation != mAudioQueueGeneration) { 376 break; 377 } 378 379 mDrainAudioQueuePending = false; 380 381 if (onDrainAudioQueue()) { 382 uint32_t numFramesPlayed; 383 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), 384 (status_t)OK); 385 386 uint32_t numFramesPendingPlayout = 387 mNumFramesWritten - numFramesPlayed; 388 389 // This is how long the audio sink will have data to 390 // play back. 391 int64_t delayUs = 392 mAudioSink->msecsPerFrame() 393 * numFramesPendingPlayout * 1000ll; 394 395 // Let's give it more data after about half that time 396 // has elapsed. 397 // kWhatDrainAudioQueue is used for non-offloading mode, 398 // and mLock is used only for offloading mode. Therefore, 399 // no need to acquire mLock here. 400 postDrainAudioQueue_l(delayUs / 2); 401 } 402 break; 403 } 404 405 case kWhatDrainVideoQueue: 406 { 407 int32_t generation; 408 CHECK(msg->findInt32("generation", &generation)); 409 if (generation != mVideoQueueGeneration) { 410 break; 411 } 412 413 mDrainVideoQueuePending = false; 414 415 onDrainVideoQueue(); 416 417 postDrainVideoQueue(); 418 break; 419 } 420 421 case kWhatPostDrainVideoQueue: 422 { 423 int32_t generation; 424 CHECK(msg->findInt32("generation", &generation)); 425 if (generation != mVideoQueueGeneration) { 426 break; 427 } 428 429 mDrainVideoQueuePending = false; 430 postDrainVideoQueue(); 431 break; 432 } 433 434 case kWhatQueueBuffer: 435 { 436 onQueueBuffer(msg); 437 break; 438 } 439 440 case kWhatQueueEOS: 441 { 442 onQueueEOS(msg); 443 break; 444 } 445 446 case kWhatFlush: 447 { 448 onFlush(msg); 449 break; 450 } 451 452 case kWhatAudioSinkChanged: 453 { 454 onAudioSinkChanged(); 455 break; 456 } 457 458 case kWhatDisableOffloadAudio: 459 { 460 onDisableOffloadAudio(); 461 break; 462 } 463 464 case kWhatEnableOffloadAudio: 465 { 466 onEnableOffloadAudio(); 467 break; 468 } 469 470 case kWhatPause: 471 { 472 onPause(); 473 break; 474 } 475 476 case kWhatResume: 477 { 478 onResume(); 479 break; 480 } 481 482 case kWhatSetVideoFrameRate: 483 { 484 float fps; 485 CHECK(msg->findFloat("frame-rate", &fps)); 486 onSetVideoFrameRate(fps); 487 break; 488 } 489 490 case kWhatAudioOffloadTearDown: 491 { 492 onAudioOffloadTearDown(kDueToError); 493 break; 494 } 495 496 case kWhatAudioOffloadPauseTimeout: 497 { 498 int32_t generation; 499 CHECK(msg->findInt32("generation", &generation)); 500 if (generation != mAudioOffloadPauseTimeoutGeneration) { 501 break; 502 } 503 ALOGV("Audio Offload tear down due to pause timeout."); 504 onAudioOffloadTearDown(kDueToTimeout); 505 break; 506 } 507 508 default: 509 TRESPASS(); 510 break; 511 } 512} 513 514void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { 515 if (mDrainAudioQueuePending || mSyncQueues || mPaused 516 || offloadingAudio()) { 517 return; 518 } 519 520 if (mAudioQueue.empty()) { 521 return; 522 } 523 524 mDrainAudioQueuePending = true; 525 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id()); 526 msg->setInt32("generation", mAudioQueueGeneration); 527 msg->post(delayUs); 528} 529 530void NuPlayer::Renderer::prepareForMediaRenderingStart() { 531 mAudioRenderingStartGeneration = mAudioQueueGeneration; 532 mVideoRenderingStartGeneration = mVideoQueueGeneration; 533} 534 535void NuPlayer::Renderer::notifyIfMediaRenderingStarted() { 536 if (mVideoRenderingStartGeneration == mVideoQueueGeneration && 537 mAudioRenderingStartGeneration == mAudioQueueGeneration) { 538 mVideoRenderingStartGeneration = -1; 539 mAudioRenderingStartGeneration = -1; 540 541 sp<AMessage> notify = mNotify->dup(); 542 notify->setInt32("what", kWhatMediaRenderingStart); 543 notify->post(); 544 } 545} 546 547// static 548size_t NuPlayer::Renderer::AudioSinkCallback( 549 MediaPlayerBase::AudioSink * /* audioSink */, 550 void *buffer, 551 size_t size, 552 void *cookie, 553 MediaPlayerBase::AudioSink::cb_event_t event) { 554 NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie; 555 556 switch (event) { 557 case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER: 558 { 559 return me->fillAudioBuffer(buffer, size); 560 break; 561 } 562 563 case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END: 564 { 565 me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM); 566 break; 567 } 568 569 case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN: 570 { 571 me->notifyAudioOffloadTearDown(); 572 break; 573 } 574 } 575 576 return 0; 577} 578 579size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { 580 Mutex::Autolock autoLock(mLock); 581 582 if (!offloadingAudio() || mPaused) { 583 return 0; 584 } 585 586 bool hasEOS = false; 587 588 size_t sizeCopied = 0; 589 bool firstEntry = true; 590 while (sizeCopied < size && !mAudioQueue.empty()) { 591 QueueEntry *entry = &*mAudioQueue.begin(); 592 593 if (entry->mBuffer == NULL) { // EOS 594 hasEOS = true; 595 mAudioQueue.erase(mAudioQueue.begin()); 596 entry = NULL; 597 break; 598 } 599 600 if (firstEntry && entry->mOffset == 0) { 601 firstEntry = false; 602 int64_t mediaTimeUs; 603 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 604 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 605 setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); 606 } 607 608 size_t copy = entry->mBuffer->size() - entry->mOffset; 609 size_t sizeRemaining = size - sizeCopied; 610 if (copy > sizeRemaining) { 611 copy = sizeRemaining; 612 } 613 614 memcpy((char *)buffer + sizeCopied, 615 entry->mBuffer->data() + entry->mOffset, 616 copy); 617 618 entry->mOffset += copy; 619 if (entry->mOffset == entry->mBuffer->size()) { 620 entry->mNotifyConsumed->post(); 621 mAudioQueue.erase(mAudioQueue.begin()); 622 entry = NULL; 623 } 624 sizeCopied += copy; 625 notifyIfMediaRenderingStarted(); 626 } 627 628 if (mAudioFirstAnchorTimeMediaUs >= 0) { 629 int64_t nowUs = ALooper::GetNowUs(); 630 setAnchorTime(mAudioFirstAnchorTimeMediaUs, nowUs - getPlayedOutAudioDurationUs(nowUs)); 631 } 632 633 // we don't know how much data we are queueing for offloaded tracks 634 mAnchorMaxMediaUs = -1; 635 636 if (hasEOS) { 637 (new AMessage(kWhatStopAudioSink, id()))->post(); 638 } 639 640 return sizeCopied; 641} 642 643bool NuPlayer::Renderer::onDrainAudioQueue() { 644 uint32_t numFramesPlayed; 645 if (mAudioSink->getPosition(&numFramesPlayed) != OK) { 646 return false; 647 } 648 649 ssize_t numFramesAvailableToWrite = 650 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); 651 652#if 0 653 if (numFramesAvailableToWrite == mAudioSink->frameCount()) { 654 ALOGI("audio sink underrun"); 655 } else { 656 ALOGV("audio queue has %d frames left to play", 657 mAudioSink->frameCount() - numFramesAvailableToWrite); 658 } 659#endif 660 661 size_t numBytesAvailableToWrite = 662 numFramesAvailableToWrite * mAudioSink->frameSize(); 663 664 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) { 665 QueueEntry *entry = &*mAudioQueue.begin(); 666 667 mLastAudioBufferDrained = entry->mBufferOrdinal; 668 669 if (entry->mBuffer == NULL) { 670 // EOS 671 int64_t postEOSDelayUs = 0; 672 if (mAudioSink->needsTrailingPadding()) { 673 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs()); 674 } 675 notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs); 676 677 mAudioQueue.erase(mAudioQueue.begin()); 678 entry = NULL; 679 if (mAudioSink->needsTrailingPadding()) { 680 // If we're not in gapless playback (i.e. through setNextPlayer), we 681 // need to stop the track here, because that will play out the last 682 // little bit at the end of the file. Otherwise short files won't play. 683 mAudioSink->stop(); 684 mNumFramesWritten = 0; 685 } 686 return false; 687 } 688 689 if (entry->mOffset == 0) { 690 int64_t mediaTimeUs; 691 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 692 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 693 onNewAudioMediaTime(mediaTimeUs); 694 } 695 696 size_t copy = entry->mBuffer->size() - entry->mOffset; 697 if (copy > numBytesAvailableToWrite) { 698 copy = numBytesAvailableToWrite; 699 } 700 701 ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy); 702 if (written < 0) { 703 // An error in AudioSink write. Perhaps the AudioSink was not properly opened. 704 ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy); 705 break; 706 } 707 708 entry->mOffset += written; 709 if (entry->mOffset == entry->mBuffer->size()) { 710 entry->mNotifyConsumed->post(); 711 mAudioQueue.erase(mAudioQueue.begin()); 712 713 entry = NULL; 714 } 715 716 numBytesAvailableToWrite -= written; 717 size_t copiedFrames = written / mAudioSink->frameSize(); 718 mNumFramesWritten += copiedFrames; 719 720 notifyIfMediaRenderingStarted(); 721 722 if (written != (ssize_t)copy) { 723 // A short count was received from AudioSink::write() 724 // 725 // AudioSink write should block until exactly the number of bytes are delivered. 726 // But it may return with a short count (without an error) when: 727 // 728 // 1) Size to be copied is not a multiple of the frame size. We consider this fatal. 729 // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded. 730 731 // (Case 1) 732 // Must be a multiple of the frame size. If it is not a multiple of a frame size, it 733 // needs to fail, as we should not carry over fractional frames between calls. 734 CHECK_EQ(copy % mAudioSink->frameSize(), 0); 735 736 // (Case 2) 737 // Return early to the caller. 738 // Beware of calling immediately again as this may busy-loop if you are not careful. 739 ALOGW("AudioSink write short frame count %zd < %zu", written, copy); 740 break; 741 } 742 } 743 mAnchorMaxMediaUs = 744 mAnchorTimeMediaUs + 745 (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL) 746 * 1000LL * mAudioSink->msecsPerFrame()); 747 748 return !mAudioQueue.empty(); 749} 750 751int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { 752 int64_t writtenAudioDurationUs = 753 mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame(); 754 return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs); 755} 756 757int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) { 758 int64_t currentPositionUs; 759 if (getCurrentPositionOnLooper( 760 ¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) { 761 // If failed to get current position, e.g. due to audio clock is not ready, then just 762 // play out video immediately without delay. 763 return nowUs; 764 } 765 return (mediaTimeUs - currentPositionUs) + nowUs; 766} 767 768void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { 769 // TRICKY: vorbis decoder generates multiple frames with the same 770 // timestamp, so only update on the first frame with a given timestamp 771 if (mediaTimeUs == mAnchorTimeMediaUs) { 772 return; 773 } 774 setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); 775 int64_t nowUs = ALooper::GetNowUs(); 776 setAnchorTime( 777 mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs), mNumFramesWritten); 778} 779 780void NuPlayer::Renderer::postDrainVideoQueue() { 781 if (mDrainVideoQueuePending 782 || mSyncQueues 783 || (mPaused && mVideoSampleReceived)) { 784 return; 785 } 786 787 if (mVideoQueue.empty()) { 788 return; 789 } 790 791 QueueEntry &entry = *mVideoQueue.begin(); 792 793 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id()); 794 msg->setInt32("generation", mVideoQueueGeneration); 795 796 if (entry.mBuffer == NULL) { 797 // EOS doesn't carry a timestamp. 798 msg->post(); 799 mDrainVideoQueuePending = true; 800 return; 801 } 802 803 int64_t delayUs; 804 int64_t nowUs = ALooper::GetNowUs(); 805 int64_t realTimeUs; 806 if (mFlags & FLAG_REAL_TIME) { 807 int64_t mediaTimeUs; 808 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 809 realTimeUs = mediaTimeUs; 810 } else { 811 int64_t mediaTimeUs; 812 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 813 814 if (mAnchorTimeMediaUs < 0) { 815 setAnchorTime(mediaTimeUs, nowUs); 816 mAnchorMaxMediaUs = mediaTimeUs; 817 realTimeUs = nowUs; 818 } else { 819 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); 820 } 821 if (!mHasAudio) { 822 mAnchorMaxMediaUs = mediaTimeUs + 100000; // smooth out videos >= 10fps 823 } 824 825 // Heuristics to handle situation when media time changed without a 826 // discontinuity. If we have not drained an audio buffer that was 827 // received after this buffer, repost in 10 msec. Otherwise repost 828 // in 500 msec. 829 delayUs = realTimeUs - nowUs; 830 if (delayUs > 500000) { 831 int64_t postDelayUs = 500000; 832 if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) { 833 postDelayUs = 10000; 834 } 835 msg->setWhat(kWhatPostDrainVideoQueue); 836 msg->post(postDelayUs); 837 mVideoScheduler->restart(); 838 ALOGI("possible video time jump of %dms, retrying in %dms", 839 (int)(delayUs / 1000), (int)(postDelayUs / 1000)); 840 mDrainVideoQueuePending = true; 841 return; 842 } 843 } 844 845 realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000; 846 int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000); 847 848 delayUs = realTimeUs - nowUs; 849 850 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); 851 // post 2 display refreshes before rendering is due 852 msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); 853 854 mDrainVideoQueuePending = true; 855} 856 857void NuPlayer::Renderer::onDrainVideoQueue() { 858 if (mVideoQueue.empty()) { 859 return; 860 } 861 862 QueueEntry *entry = &*mVideoQueue.begin(); 863 864 if (entry->mBuffer == NULL) { 865 // EOS 866 867 notifyEOS(false /* audio */, entry->mFinalResult); 868 869 mVideoQueue.erase(mVideoQueue.begin()); 870 entry = NULL; 871 872 setVideoLateByUs(0); 873 return; 874 } 875 876 int64_t nowUs = -1; 877 int64_t realTimeUs; 878 if (mFlags & FLAG_REAL_TIME) { 879 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs)); 880 } else { 881 int64_t mediaTimeUs; 882 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 883 884 nowUs = ALooper::GetNowUs(); 885 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); 886 } 887 888 bool tooLate = false; 889 890 if (!mPaused) { 891 if (nowUs == -1) { 892 nowUs = ALooper::GetNowUs(); 893 } 894 setVideoLateByUs(nowUs - realTimeUs); 895 tooLate = (mVideoLateByUs > 40000); 896 897 if (tooLate) { 898 ALOGV("video late by %lld us (%.2f secs)", 899 mVideoLateByUs, mVideoLateByUs / 1E6); 900 } else { 901 ALOGV("rendering video at media time %.2f secs", 902 (mFlags & FLAG_REAL_TIME ? realTimeUs : 903 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); 904 } 905 } else { 906 setVideoLateByUs(0); 907 if (!mVideoSampleReceived && !mHasAudio) { 908 // This will ensure that the first frame after a flush won't be used as anchor 909 // when renderer is in paused state, because resume can happen any time after seek. 910 setAnchorTime(-1, -1); 911 } 912 } 913 914 entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll); 915 entry->mNotifyConsumed->setInt32("render", !tooLate); 916 entry->mNotifyConsumed->post(); 917 mVideoQueue.erase(mVideoQueue.begin()); 918 entry = NULL; 919 920 mVideoSampleReceived = true; 921 922 if (!mPaused) { 923 if (!mVideoRenderingStarted) { 924 mVideoRenderingStarted = true; 925 notifyVideoRenderingStart(); 926 } 927 notifyIfMediaRenderingStarted(); 928 } 929} 930 931void NuPlayer::Renderer::notifyVideoRenderingStart() { 932 sp<AMessage> notify = mNotify->dup(); 933 notify->setInt32("what", kWhatVideoRenderingStart); 934 notify->post(); 935} 936 937void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) { 938 sp<AMessage> notify = mNotify->dup(); 939 notify->setInt32("what", kWhatEOS); 940 notify->setInt32("audio", static_cast<int32_t>(audio)); 941 notify->setInt32("finalResult", finalResult); 942 notify->post(delayUs); 943} 944 945void NuPlayer::Renderer::notifyAudioOffloadTearDown() { 946 (new AMessage(kWhatAudioOffloadTearDown, id()))->post(); 947} 948 949void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { 950 int32_t audio; 951 CHECK(msg->findInt32("audio", &audio)); 952 953 setHasMedia(audio); 954 955 if (mHasVideo) { 956 if (mVideoScheduler == NULL) { 957 mVideoScheduler = new VideoFrameScheduler(); 958 mVideoScheduler->init(); 959 } 960 } 961 962 if (dropBufferWhileFlushing(audio, msg)) { 963 return; 964 } 965 966 sp<ABuffer> buffer; 967 CHECK(msg->findBuffer("buffer", &buffer)); 968 969 sp<AMessage> notifyConsumed; 970 CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); 971 972 QueueEntry entry; 973 entry.mBuffer = buffer; 974 entry.mNotifyConsumed = notifyConsumed; 975 entry.mOffset = 0; 976 entry.mFinalResult = OK; 977 entry.mBufferOrdinal = ++mTotalBuffersQueued; 978 979 if (audio) { 980 Mutex::Autolock autoLock(mLock); 981 mAudioQueue.push_back(entry); 982 postDrainAudioQueue_l(); 983 } else { 984 mVideoQueue.push_back(entry); 985 postDrainVideoQueue(); 986 } 987 988 Mutex::Autolock autoLock(mLock); 989 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { 990 return; 991 } 992 993 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; 994 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; 995 996 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { 997 // EOS signalled on either queue. 998 syncQueuesDone_l(); 999 return; 1000 } 1001 1002 int64_t firstAudioTimeUs; 1003 int64_t firstVideoTimeUs; 1004 CHECK(firstAudioBuffer->meta() 1005 ->findInt64("timeUs", &firstAudioTimeUs)); 1006 CHECK(firstVideoBuffer->meta() 1007 ->findInt64("timeUs", &firstVideoTimeUs)); 1008 1009 int64_t diff = firstVideoTimeUs - firstAudioTimeUs; 1010 1011 ALOGV("queueDiff = %.2f secs", diff / 1E6); 1012 1013 if (diff > 100000ll) { 1014 // Audio data starts More than 0.1 secs before video. 1015 // Drop some audio. 1016 1017 (*mAudioQueue.begin()).mNotifyConsumed->post(); 1018 mAudioQueue.erase(mAudioQueue.begin()); 1019 return; 1020 } 1021 1022 syncQueuesDone_l(); 1023} 1024 1025void NuPlayer::Renderer::syncQueuesDone_l() { 1026 if (!mSyncQueues) { 1027 return; 1028 } 1029 1030 mSyncQueues = false; 1031 1032 if (!mAudioQueue.empty()) { 1033 postDrainAudioQueue_l(); 1034 } 1035 1036 if (!mVideoQueue.empty()) { 1037 postDrainVideoQueue(); 1038 } 1039} 1040 1041void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { 1042 int32_t audio; 1043 CHECK(msg->findInt32("audio", &audio)); 1044 1045 if (dropBufferWhileFlushing(audio, msg)) { 1046 return; 1047 } 1048 1049 int32_t finalResult; 1050 CHECK(msg->findInt32("finalResult", &finalResult)); 1051 1052 QueueEntry entry; 1053 entry.mOffset = 0; 1054 entry.mFinalResult = finalResult; 1055 1056 if (audio) { 1057 Mutex::Autolock autoLock(mLock); 1058 if (mAudioQueue.empty() && mSyncQueues) { 1059 syncQueuesDone_l(); 1060 } 1061 mAudioQueue.push_back(entry); 1062 postDrainAudioQueue_l(); 1063 } else { 1064 if (mVideoQueue.empty() && mSyncQueues) { 1065 Mutex::Autolock autoLock(mLock); 1066 syncQueuesDone_l(); 1067 } 1068 mVideoQueue.push_back(entry); 1069 postDrainVideoQueue(); 1070 } 1071} 1072 1073void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { 1074 int32_t audio, notifyComplete; 1075 CHECK(msg->findInt32("audio", &audio)); 1076 1077 { 1078 Mutex::Autolock autoLock(mFlushLock); 1079 if (audio) { 1080 mFlushingAudio = false; 1081 notifyComplete = mNotifyCompleteAudio; 1082 mNotifyCompleteAudio = false; 1083 } else { 1084 mFlushingVideo = false; 1085 notifyComplete = mNotifyCompleteVideo; 1086 mNotifyCompleteVideo = false; 1087 } 1088 } 1089 1090 // If we're currently syncing the queues, i.e. dropping audio while 1091 // aligning the first audio/video buffer times and only one of the 1092 // two queues has data, we may starve that queue by not requesting 1093 // more buffers from the decoder. If the other source then encounters 1094 // a discontinuity that leads to flushing, we'll never find the 1095 // corresponding discontinuity on the other queue. 1096 // Therefore we'll stop syncing the queues if at least one of them 1097 // is flushed. 1098 { 1099 Mutex::Autolock autoLock(mLock); 1100 syncQueuesDone_l(); 1101 setPauseStartedTimeRealUs(-1); 1102 setAnchorTime(-1, -1); 1103 } 1104 1105 ALOGV("flushing %s", audio ? "audio" : "video"); 1106 if (audio) { 1107 { 1108 Mutex::Autolock autoLock(mLock); 1109 flushQueue(&mAudioQueue); 1110 1111 ++mAudioQueueGeneration; 1112 prepareForMediaRenderingStart(); 1113 1114 if (offloadingAudio()) { 1115 setAudioFirstAnchorTime(-1); 1116 } 1117 } 1118 1119 mDrainAudioQueuePending = false; 1120 1121 if (offloadingAudio()) { 1122 mAudioSink->pause(); 1123 mAudioSink->flush(); 1124 mAudioSink->start(); 1125 } 1126 } else { 1127 flushQueue(&mVideoQueue); 1128 1129 mDrainVideoQueuePending = false; 1130 ++mVideoQueueGeneration; 1131 1132 if (mVideoScheduler != NULL) { 1133 mVideoScheduler->restart(); 1134 } 1135 1136 prepareForMediaRenderingStart(); 1137 } 1138 1139 mVideoSampleReceived = false; 1140 1141 if (notifyComplete) { 1142 notifyFlushComplete(audio); 1143 } 1144} 1145 1146void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { 1147 while (!queue->empty()) { 1148 QueueEntry *entry = &*queue->begin(); 1149 1150 if (entry->mBuffer != NULL) { 1151 entry->mNotifyConsumed->post(); 1152 } 1153 1154 queue->erase(queue->begin()); 1155 entry = NULL; 1156 } 1157} 1158 1159void NuPlayer::Renderer::notifyFlushComplete(bool audio) { 1160 sp<AMessage> notify = mNotify->dup(); 1161 notify->setInt32("what", kWhatFlushComplete); 1162 notify->setInt32("audio", static_cast<int32_t>(audio)); 1163 notify->post(); 1164} 1165 1166bool NuPlayer::Renderer::dropBufferWhileFlushing( 1167 bool audio, const sp<AMessage> &msg) { 1168 bool flushing = false; 1169 1170 { 1171 Mutex::Autolock autoLock(mFlushLock); 1172 if (audio) { 1173 flushing = mFlushingAudio; 1174 } else { 1175 flushing = mFlushingVideo; 1176 } 1177 } 1178 1179 if (!flushing) { 1180 return false; 1181 } 1182 1183 sp<AMessage> notifyConsumed; 1184 if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) { 1185 notifyConsumed->post(); 1186 } 1187 1188 return true; 1189} 1190 1191void NuPlayer::Renderer::onAudioSinkChanged() { 1192 if (offloadingAudio()) { 1193 return; 1194 } 1195 CHECK(!mDrainAudioQueuePending); 1196 mNumFramesWritten = 0; 1197 mAnchorNumFramesWritten = -1; 1198 uint32_t written; 1199 if (mAudioSink->getFramesWritten(&written) == OK) { 1200 mNumFramesWritten = written; 1201 } 1202} 1203 1204void NuPlayer::Renderer::onDisableOffloadAudio() { 1205 Mutex::Autolock autoLock(mLock); 1206 mFlags &= ~FLAG_OFFLOAD_AUDIO; 1207 ++mAudioQueueGeneration; 1208} 1209 1210void NuPlayer::Renderer::onEnableOffloadAudio() { 1211 Mutex::Autolock autoLock(mLock); 1212 mFlags |= FLAG_OFFLOAD_AUDIO; 1213 ++mAudioQueueGeneration; 1214} 1215 1216void NuPlayer::Renderer::onPause() { 1217 if (mPaused) { 1218 ALOGW("Renderer::onPause() called while already paused!"); 1219 return; 1220 } 1221 int64_t currentPositionUs; 1222 if (getCurrentPositionFromAnchor( 1223 ¤tPositionUs, ALooper::GetNowUs()) == OK) { 1224 mPausePositionMediaTimeUs = currentPositionUs; 1225 } else { 1226 // Set paused position to -1 (unavailabe) if we don't have anchor time 1227 // This could happen if client does a seekTo() immediately followed by 1228 // pause(). Renderer will be flushed with anchor time cleared. We don't 1229 // want to leave stale value in mPausePositionMediaTimeUs. 1230 mPausePositionMediaTimeUs = -1; 1231 } 1232 { 1233 Mutex::Autolock autoLock(mLock); 1234 ++mAudioQueueGeneration; 1235 ++mVideoQueueGeneration; 1236 prepareForMediaRenderingStart(); 1237 mPaused = true; 1238 setPauseStartedTimeRealUs(ALooper::GetNowUs()); 1239 } 1240 1241 mDrainAudioQueuePending = false; 1242 mDrainVideoQueuePending = false; 1243 1244 if (mHasAudio) { 1245 mAudioSink->pause(); 1246 startAudioOffloadPauseTimeout(); 1247 } 1248 1249 ALOGV("now paused audio queue has %d entries, video has %d entries", 1250 mAudioQueue.size(), mVideoQueue.size()); 1251} 1252 1253void NuPlayer::Renderer::onResume() { 1254 if (!mPaused) { 1255 return; 1256 } 1257 1258 if (mHasAudio) { 1259 cancelAudioOffloadPauseTimeout(); 1260 mAudioSink->start(); 1261 } 1262 1263 Mutex::Autolock autoLock(mLock); 1264 mPaused = false; 1265 if (mPauseStartedTimeRealUs != -1) { 1266 int64_t newAnchorRealUs = 1267 mAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; 1268 setAnchorTime( 1269 mAnchorTimeMediaUs, newAnchorRealUs, mAnchorNumFramesWritten, true /* resume */); 1270 } 1271 1272 if (!mAudioQueue.empty()) { 1273 postDrainAudioQueue_l(); 1274 } 1275 1276 if (!mVideoQueue.empty()) { 1277 postDrainVideoQueue(); 1278 } 1279} 1280 1281void NuPlayer::Renderer::onSetVideoFrameRate(float fps) { 1282 if (mVideoScheduler == NULL) { 1283 mVideoScheduler = new VideoFrameScheduler(); 1284 } 1285 mVideoScheduler->init(fps); 1286} 1287 1288// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs() 1289// as it acquires locks and may query the audio driver. 1290// 1291// Some calls could conceivably retrieve extrapolated data instead of 1292// accessing getTimestamp() or getPosition() every time a data buffer with 1293// a media time is received. 1294// 1295int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { 1296 uint32_t numFramesPlayed; 1297 int64_t numFramesPlayedAt; 1298 AudioTimestamp ts; 1299 static const int64_t kStaleTimestamp100ms = 100000; 1300 1301 status_t res = mAudioSink->getTimestamp(ts); 1302 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks. 1303 numFramesPlayed = ts.mPosition; 1304 numFramesPlayedAt = 1305 ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000; 1306 const int64_t timestampAge = nowUs - numFramesPlayedAt; 1307 if (timestampAge > kStaleTimestamp100ms) { 1308 // This is an audio FIXME. 1309 // getTimestamp returns a timestamp which may come from audio mixing threads. 1310 // After pausing, the MixerThread may go idle, thus the mTime estimate may 1311 // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms, 1312 // the max latency should be about 25ms with an average around 12ms (to be verified). 1313 // For safety we use 100ms. 1314 ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)", 1315 (long long)nowUs, (long long)numFramesPlayedAt); 1316 numFramesPlayedAt = nowUs - kStaleTimestamp100ms; 1317 } 1318 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt); 1319 } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track 1320 numFramesPlayed = 0; 1321 numFramesPlayedAt = nowUs; 1322 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld", 1323 // numFramesPlayed, (long long)numFramesPlayedAt); 1324 } else { // case 3: transitory at new track or audio fast tracks. 1325 res = mAudioSink->getPosition(&numFramesPlayed); 1326 CHECK_EQ(res, (status_t)OK); 1327 numFramesPlayedAt = nowUs; 1328 numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */ 1329 //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt); 1330 } 1331 1332 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. 1333 //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test 1334 int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()) 1335 + nowUs - numFramesPlayedAt; 1336 if (durationUs < 0) { 1337 // Occurs when numFramesPlayed position is very small and the following: 1338 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and 1339 // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed. 1340 // (2) In case 3, using getPosition and adding mAudioSink->latency() to 1341 // numFramesPlayedAt, by a time amount greater than numFramesPlayed. 1342 // 1343 // Both of these are transitory conditions. 1344 ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs); 1345 durationUs = 0; 1346 } 1347 ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)", 1348 (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt); 1349 return durationUs; 1350} 1351 1352void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) { 1353 if (mAudioOffloadTornDown) { 1354 return; 1355 } 1356 mAudioOffloadTornDown = true; 1357 1358 int64_t currentPositionUs; 1359 if (getCurrentPositionOnLooper(¤tPositionUs) != OK) { 1360 currentPositionUs = 0; 1361 } 1362 1363 mAudioSink->stop(); 1364 mAudioSink->flush(); 1365 1366 sp<AMessage> notify = mNotify->dup(); 1367 notify->setInt32("what", kWhatAudioOffloadTearDown); 1368 notify->setInt64("positionUs", currentPositionUs); 1369 notify->setInt32("reason", reason); 1370 notify->post(); 1371} 1372 1373void NuPlayer::Renderer::startAudioOffloadPauseTimeout() { 1374 if (offloadingAudio()) { 1375 sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id()); 1376 msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration); 1377 msg->post(kOffloadPauseMaxUs); 1378 } 1379} 1380 1381void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { 1382 if (offloadingAudio()) { 1383 ++mAudioOffloadPauseTimeoutGeneration; 1384 } 1385} 1386 1387status_t NuPlayer::Renderer::onOpenAudioSink( 1388 const sp<AMessage> &format, 1389 bool offloadOnly, 1390 bool hasVideo, 1391 uint32_t flags) { 1392 ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)", 1393 offloadOnly, offloadingAudio()); 1394 bool audioSinkChanged = false; 1395 1396 int32_t numChannels; 1397 CHECK(format->findInt32("channel-count", &numChannels)); 1398 1399 int32_t channelMask; 1400 if (!format->findInt32("channel-mask", &channelMask)) { 1401 // signal to the AudioSink to derive the mask from count. 1402 channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; 1403 } 1404 1405 int32_t sampleRate; 1406 CHECK(format->findInt32("sample-rate", &sampleRate)); 1407 1408 if (offloadingAudio()) { 1409 audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; 1410 AString mime; 1411 CHECK(format->findString("mime", &mime)); 1412 status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); 1413 1414 if (err != OK) { 1415 ALOGE("Couldn't map mime \"%s\" to a valid " 1416 "audio_format", mime.c_str()); 1417 onDisableOffloadAudio(); 1418 } else { 1419 ALOGV("Mime \"%s\" mapped to audio_format 0x%x", 1420 mime.c_str(), audioFormat); 1421 1422 int avgBitRate = -1; 1423 format->findInt32("bit-rate", &avgBitRate); 1424 1425 int32_t aacProfile = -1; 1426 if (audioFormat == AUDIO_FORMAT_AAC 1427 && format->findInt32("aac-profile", &aacProfile)) { 1428 // Redefine AAC format as per aac profile 1429 mapAACProfileToAudioFormat( 1430 audioFormat, 1431 aacProfile); 1432 } 1433 1434 audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; 1435 offloadInfo.duration_us = -1; 1436 format->findInt64( 1437 "durationUs", &offloadInfo.duration_us); 1438 offloadInfo.sample_rate = sampleRate; 1439 offloadInfo.channel_mask = channelMask; 1440 offloadInfo.format = audioFormat; 1441 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; 1442 offloadInfo.bit_rate = avgBitRate; 1443 offloadInfo.has_video = hasVideo; 1444 offloadInfo.is_streaming = true; 1445 1446 if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { 1447 ALOGV("openAudioSink: no change in offload mode"); 1448 // no change from previous configuration, everything ok. 1449 return OK; 1450 } 1451 ALOGV("openAudioSink: try to open AudioSink in offload mode"); 1452 uint32_t offloadFlags = flags; 1453 offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; 1454 offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 1455 audioSinkChanged = true; 1456 mAudioSink->close(); 1457 err = mAudioSink->open( 1458 sampleRate, 1459 numChannels, 1460 (audio_channel_mask_t)channelMask, 1461 audioFormat, 1462 8 /* bufferCount */, 1463 &NuPlayer::Renderer::AudioSinkCallback, 1464 this, 1465 (audio_output_flags_t)offloadFlags, 1466 &offloadInfo); 1467 1468 if (err == OK) { 1469 // If the playback is offloaded to h/w, we pass 1470 // the HAL some metadata information. 1471 // We don't want to do this for PCM because it 1472 // will be going through the AudioFlinger mixer 1473 // before reaching the hardware. 1474 // TODO 1475 mCurrentOffloadInfo = offloadInfo; 1476 err = mAudioSink->start(); 1477 ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); 1478 } 1479 if (err != OK) { 1480 // Clean up, fall back to non offload mode. 1481 mAudioSink->close(); 1482 onDisableOffloadAudio(); 1483 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1484 ALOGV("openAudioSink: offload failed"); 1485 } 1486 } 1487 } 1488 if (!offloadOnly && !offloadingAudio()) { 1489 ALOGV("openAudioSink: open AudioSink in NON-offload mode"); 1490 uint32_t pcmFlags = flags; 1491 pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; 1492 audioSinkChanged = true; 1493 mAudioSink->close(); 1494 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1495 status_t err = mAudioSink->open( 1496 sampleRate, 1497 numChannels, 1498 (audio_channel_mask_t)channelMask, 1499 AUDIO_FORMAT_PCM_16_BIT, 1500 8 /* bufferCount */, 1501 NULL, 1502 NULL, 1503 (audio_output_flags_t)pcmFlags); 1504 if (err != OK) { 1505 ALOGW("openAudioSink: non offloaded open failed status: %d", err); 1506 return err; 1507 } 1508 mAudioSink->start(); 1509 } 1510 if (audioSinkChanged) { 1511 onAudioSinkChanged(); 1512 } 1513 if (offloadingAudio()) { 1514 mAudioOffloadTornDown = false; 1515 } 1516 return OK; 1517} 1518 1519void NuPlayer::Renderer::onCloseAudioSink() { 1520 mAudioSink->close(); 1521 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1522} 1523 1524} // namespace android 1525 1526