NuPlayerRenderer.cpp revision d4cdba18ba7d0057ae54ec7efa5871b1a9d8beca
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(0), 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) { 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 // Need to stop the track here, because that will play out the last 680 // little bit at the end of the file. Otherwise short files won't play. 681 mAudioSink->stop(); 682 mNumFramesWritten = 0; 683 return false; 684 } 685 686 if (entry->mOffset == 0) { 687 int64_t mediaTimeUs; 688 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 689 ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); 690 onNewAudioMediaTime(mediaTimeUs); 691 } 692 693 size_t copy = entry->mBuffer->size() - entry->mOffset; 694 if (copy > numBytesAvailableToWrite) { 695 copy = numBytesAvailableToWrite; 696 } 697 698 ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy); 699 if (written < 0) { 700 // An error in AudioSink write. Perhaps the AudioSink was not properly opened. 701 ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy); 702 break; 703 } 704 705 entry->mOffset += written; 706 if (entry->mOffset == entry->mBuffer->size()) { 707 entry->mNotifyConsumed->post(); 708 mAudioQueue.erase(mAudioQueue.begin()); 709 710 entry = NULL; 711 } 712 713 numBytesAvailableToWrite -= written; 714 size_t copiedFrames = written / mAudioSink->frameSize(); 715 mNumFramesWritten += copiedFrames; 716 717 notifyIfMediaRenderingStarted(); 718 719 if (written != (ssize_t)copy) { 720 // A short count was received from AudioSink::write() 721 // 722 // AudioSink write should block until exactly the number of bytes are delivered. 723 // But it may return with a short count (without an error) when: 724 // 725 // 1) Size to be copied is not a multiple of the frame size. We consider this fatal. 726 // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded. 727 728 // (Case 1) 729 // Must be a multiple of the frame size. If it is not a multiple of a frame size, it 730 // needs to fail, as we should not carry over fractional frames between calls. 731 CHECK_EQ(copy % mAudioSink->frameSize(), 0); 732 733 // (Case 2) 734 // Return early to the caller. 735 // Beware of calling immediately again as this may busy-loop if you are not careful. 736 ALOGW("AudioSink write short frame count %zd < %zu", written, copy); 737 break; 738 } 739 } 740 mAnchorMaxMediaUs = 741 mAnchorTimeMediaUs + 742 (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL) 743 * 1000LL * mAudioSink->msecsPerFrame()); 744 745 return !mAudioQueue.empty(); 746} 747 748int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { 749 int64_t writtenAudioDurationUs = 750 mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame(); 751 return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs); 752} 753 754int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) { 755 int64_t currentPositionUs; 756 if (getCurrentPositionOnLooper( 757 ¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) { 758 // If failed to get current position, e.g. due to audio clock is not ready, then just 759 // play out video immediately without delay. 760 return nowUs; 761 } 762 return (mediaTimeUs - currentPositionUs) + nowUs; 763} 764 765void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { 766 // TRICKY: vorbis decoder generates multiple frames with the same 767 // timestamp, so only update on the first frame with a given timestamp 768 if (mediaTimeUs == mAnchorTimeMediaUs) { 769 return; 770 } 771 setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); 772 int64_t nowUs = ALooper::GetNowUs(); 773 setAnchorTime( 774 mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs), mNumFramesWritten); 775} 776 777void NuPlayer::Renderer::postDrainVideoQueue() { 778 if (mDrainVideoQueuePending 779 || mSyncQueues 780 || (mPaused && mVideoSampleReceived)) { 781 return; 782 } 783 784 if (mVideoQueue.empty()) { 785 return; 786 } 787 788 QueueEntry &entry = *mVideoQueue.begin(); 789 790 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id()); 791 msg->setInt32("generation", mVideoQueueGeneration); 792 793 if (entry.mBuffer == NULL) { 794 // EOS doesn't carry a timestamp. 795 msg->post(); 796 mDrainVideoQueuePending = true; 797 return; 798 } 799 800 int64_t delayUs; 801 int64_t nowUs = ALooper::GetNowUs(); 802 int64_t realTimeUs; 803 if (mFlags & FLAG_REAL_TIME) { 804 int64_t mediaTimeUs; 805 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 806 realTimeUs = mediaTimeUs; 807 } else { 808 int64_t mediaTimeUs; 809 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 810 811 if (mAnchorTimeMediaUs < 0) { 812 setAnchorTime(mediaTimeUs, nowUs); 813 mAnchorMaxMediaUs = mediaTimeUs; 814 realTimeUs = nowUs; 815 } else { 816 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); 817 } 818 if (!mHasAudio) { 819 mAnchorMaxMediaUs = mediaTimeUs + 100000; // smooth out videos >= 10fps 820 } 821 822 // Heuristics to handle situation when media time changed without a 823 // discontinuity. If we have not drained an audio buffer that was 824 // received after this buffer, repost in 10 msec. Otherwise repost 825 // in 500 msec. 826 delayUs = realTimeUs - nowUs; 827 if (delayUs > 500000) { 828 int64_t postDelayUs = 500000; 829 if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) { 830 postDelayUs = 10000; 831 } 832 msg->setWhat(kWhatPostDrainVideoQueue); 833 msg->post(postDelayUs); 834 mVideoScheduler->restart(); 835 ALOGI("possible video time jump of %dms, retrying in %dms", 836 (int)(delayUs / 1000), (int)(postDelayUs / 1000)); 837 mDrainVideoQueuePending = true; 838 return; 839 } 840 } 841 842 realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000; 843 int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000); 844 845 delayUs = realTimeUs - nowUs; 846 847 ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); 848 // post 2 display refreshes before rendering is due 849 msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); 850 851 mDrainVideoQueuePending = true; 852} 853 854void NuPlayer::Renderer::onDrainVideoQueue() { 855 if (mVideoQueue.empty()) { 856 return; 857 } 858 859 QueueEntry *entry = &*mVideoQueue.begin(); 860 861 if (entry->mBuffer == NULL) { 862 // EOS 863 864 notifyEOS(false /* audio */, entry->mFinalResult); 865 866 mVideoQueue.erase(mVideoQueue.begin()); 867 entry = NULL; 868 869 setVideoLateByUs(0); 870 return; 871 } 872 873 int64_t nowUs = -1; 874 int64_t realTimeUs; 875 if (mFlags & FLAG_REAL_TIME) { 876 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs)); 877 } else { 878 int64_t mediaTimeUs; 879 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); 880 881 nowUs = ALooper::GetNowUs(); 882 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); 883 } 884 885 bool tooLate = false; 886 887 if (!mPaused) { 888 if (nowUs == -1) { 889 nowUs = ALooper::GetNowUs(); 890 } 891 setVideoLateByUs(nowUs - realTimeUs); 892 tooLate = (mVideoLateByUs > 40000); 893 894 if (tooLate) { 895 ALOGV("video late by %lld us (%.2f secs)", 896 mVideoLateByUs, mVideoLateByUs / 1E6); 897 } else { 898 ALOGV("rendering video at media time %.2f secs", 899 (mFlags & FLAG_REAL_TIME ? realTimeUs : 900 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); 901 } 902 } else { 903 setVideoLateByUs(0); 904 if (!mVideoSampleReceived && !mHasAudio) { 905 // This will ensure that the first frame after a flush won't be used as anchor 906 // when renderer is in paused state, because resume can happen any time after seek. 907 setAnchorTime(-1, -1); 908 } 909 } 910 911 entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll); 912 entry->mNotifyConsumed->setInt32("render", !tooLate); 913 entry->mNotifyConsumed->post(); 914 mVideoQueue.erase(mVideoQueue.begin()); 915 entry = NULL; 916 917 mVideoSampleReceived = true; 918 919 if (!mPaused) { 920 if (!mVideoRenderingStarted) { 921 mVideoRenderingStarted = true; 922 notifyVideoRenderingStart(); 923 } 924 notifyIfMediaRenderingStarted(); 925 } 926} 927 928void NuPlayer::Renderer::notifyVideoRenderingStart() { 929 sp<AMessage> notify = mNotify->dup(); 930 notify->setInt32("what", kWhatVideoRenderingStart); 931 notify->post(); 932} 933 934void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) { 935 sp<AMessage> notify = mNotify->dup(); 936 notify->setInt32("what", kWhatEOS); 937 notify->setInt32("audio", static_cast<int32_t>(audio)); 938 notify->setInt32("finalResult", finalResult); 939 notify->post(delayUs); 940} 941 942void NuPlayer::Renderer::notifyAudioOffloadTearDown() { 943 (new AMessage(kWhatAudioOffloadTearDown, id()))->post(); 944} 945 946void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { 947 int32_t audio; 948 CHECK(msg->findInt32("audio", &audio)); 949 950 setHasMedia(audio); 951 952 if (mHasVideo) { 953 if (mVideoScheduler == NULL) { 954 mVideoScheduler = new VideoFrameScheduler(); 955 mVideoScheduler->init(); 956 } 957 } 958 959 if (dropBufferWhileFlushing(audio, msg)) { 960 return; 961 } 962 963 sp<ABuffer> buffer; 964 CHECK(msg->findBuffer("buffer", &buffer)); 965 966 sp<AMessage> notifyConsumed; 967 CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); 968 969 QueueEntry entry; 970 entry.mBuffer = buffer; 971 entry.mNotifyConsumed = notifyConsumed; 972 entry.mOffset = 0; 973 entry.mFinalResult = OK; 974 entry.mBufferOrdinal = ++mTotalBuffersQueued; 975 976 if (audio) { 977 Mutex::Autolock autoLock(mLock); 978 mAudioQueue.push_back(entry); 979 postDrainAudioQueue_l(); 980 } else { 981 mVideoQueue.push_back(entry); 982 postDrainVideoQueue(); 983 } 984 985 Mutex::Autolock autoLock(mLock); 986 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { 987 return; 988 } 989 990 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; 991 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; 992 993 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { 994 // EOS signalled on either queue. 995 syncQueuesDone_l(); 996 return; 997 } 998 999 int64_t firstAudioTimeUs; 1000 int64_t firstVideoTimeUs; 1001 CHECK(firstAudioBuffer->meta() 1002 ->findInt64("timeUs", &firstAudioTimeUs)); 1003 CHECK(firstVideoBuffer->meta() 1004 ->findInt64("timeUs", &firstVideoTimeUs)); 1005 1006 int64_t diff = firstVideoTimeUs - firstAudioTimeUs; 1007 1008 ALOGV("queueDiff = %.2f secs", diff / 1E6); 1009 1010 if (diff > 100000ll) { 1011 // Audio data starts More than 0.1 secs before video. 1012 // Drop some audio. 1013 1014 (*mAudioQueue.begin()).mNotifyConsumed->post(); 1015 mAudioQueue.erase(mAudioQueue.begin()); 1016 return; 1017 } 1018 1019 syncQueuesDone_l(); 1020} 1021 1022void NuPlayer::Renderer::syncQueuesDone_l() { 1023 if (!mSyncQueues) { 1024 return; 1025 } 1026 1027 mSyncQueues = false; 1028 1029 if (!mAudioQueue.empty()) { 1030 postDrainAudioQueue_l(); 1031 } 1032 1033 if (!mVideoQueue.empty()) { 1034 postDrainVideoQueue(); 1035 } 1036} 1037 1038void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { 1039 int32_t audio; 1040 CHECK(msg->findInt32("audio", &audio)); 1041 1042 if (dropBufferWhileFlushing(audio, msg)) { 1043 return; 1044 } 1045 1046 int32_t finalResult; 1047 CHECK(msg->findInt32("finalResult", &finalResult)); 1048 1049 QueueEntry entry; 1050 entry.mOffset = 0; 1051 entry.mFinalResult = finalResult; 1052 1053 if (audio) { 1054 Mutex::Autolock autoLock(mLock); 1055 if (mAudioQueue.empty() && mSyncQueues) { 1056 syncQueuesDone_l(); 1057 } 1058 mAudioQueue.push_back(entry); 1059 postDrainAudioQueue_l(); 1060 } else { 1061 if (mVideoQueue.empty() && mSyncQueues) { 1062 Mutex::Autolock autoLock(mLock); 1063 syncQueuesDone_l(); 1064 } 1065 mVideoQueue.push_back(entry); 1066 postDrainVideoQueue(); 1067 } 1068} 1069 1070void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { 1071 int32_t audio, notifyComplete; 1072 CHECK(msg->findInt32("audio", &audio)); 1073 1074 { 1075 Mutex::Autolock autoLock(mFlushLock); 1076 if (audio) { 1077 mFlushingAudio = false; 1078 notifyComplete = mNotifyCompleteAudio; 1079 mNotifyCompleteAudio = false; 1080 } else { 1081 mFlushingVideo = false; 1082 notifyComplete = mNotifyCompleteVideo; 1083 mNotifyCompleteVideo = false; 1084 } 1085 } 1086 1087 // If we're currently syncing the queues, i.e. dropping audio while 1088 // aligning the first audio/video buffer times and only one of the 1089 // two queues has data, we may starve that queue by not requesting 1090 // more buffers from the decoder. If the other source then encounters 1091 // a discontinuity that leads to flushing, we'll never find the 1092 // corresponding discontinuity on the other queue. 1093 // Therefore we'll stop syncing the queues if at least one of them 1094 // is flushed. 1095 { 1096 Mutex::Autolock autoLock(mLock); 1097 syncQueuesDone_l(); 1098 setPauseStartedTimeRealUs(-1); 1099 setAnchorTime(-1, -1); 1100 } 1101 1102 ALOGV("flushing %s", audio ? "audio" : "video"); 1103 if (audio) { 1104 { 1105 Mutex::Autolock autoLock(mLock); 1106 flushQueue(&mAudioQueue); 1107 1108 ++mAudioQueueGeneration; 1109 prepareForMediaRenderingStart(); 1110 1111 if (offloadingAudio()) { 1112 setAudioFirstAnchorTime(-1); 1113 } 1114 } 1115 1116 mDrainAudioQueuePending = false; 1117 1118 if (offloadingAudio()) { 1119 mAudioSink->pause(); 1120 mAudioSink->flush(); 1121 mAudioSink->start(); 1122 } 1123 } else { 1124 flushQueue(&mVideoQueue); 1125 1126 mDrainVideoQueuePending = false; 1127 ++mVideoQueueGeneration; 1128 1129 if (mVideoScheduler != NULL) { 1130 mVideoScheduler->restart(); 1131 } 1132 1133 prepareForMediaRenderingStart(); 1134 } 1135 1136 mVideoSampleReceived = false; 1137 1138 if (notifyComplete) { 1139 notifyFlushComplete(audio); 1140 } 1141} 1142 1143void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { 1144 while (!queue->empty()) { 1145 QueueEntry *entry = &*queue->begin(); 1146 1147 if (entry->mBuffer != NULL) { 1148 entry->mNotifyConsumed->post(); 1149 } 1150 1151 queue->erase(queue->begin()); 1152 entry = NULL; 1153 } 1154} 1155 1156void NuPlayer::Renderer::notifyFlushComplete(bool audio) { 1157 sp<AMessage> notify = mNotify->dup(); 1158 notify->setInt32("what", kWhatFlushComplete); 1159 notify->setInt32("audio", static_cast<int32_t>(audio)); 1160 notify->post(); 1161} 1162 1163bool NuPlayer::Renderer::dropBufferWhileFlushing( 1164 bool audio, const sp<AMessage> &msg) { 1165 bool flushing = false; 1166 1167 { 1168 Mutex::Autolock autoLock(mFlushLock); 1169 if (audio) { 1170 flushing = mFlushingAudio; 1171 } else { 1172 flushing = mFlushingVideo; 1173 } 1174 } 1175 1176 if (!flushing) { 1177 return false; 1178 } 1179 1180 sp<AMessage> notifyConsumed; 1181 if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) { 1182 notifyConsumed->post(); 1183 } 1184 1185 return true; 1186} 1187 1188void NuPlayer::Renderer::onAudioSinkChanged() { 1189 if (offloadingAudio()) { 1190 return; 1191 } 1192 CHECK(!mDrainAudioQueuePending); 1193 mNumFramesWritten = 0; 1194 mAnchorNumFramesWritten = -1; 1195 uint32_t written; 1196 if (mAudioSink->getFramesWritten(&written) == OK) { 1197 mNumFramesWritten = written; 1198 } 1199} 1200 1201void NuPlayer::Renderer::onDisableOffloadAudio() { 1202 Mutex::Autolock autoLock(mLock); 1203 mFlags &= ~FLAG_OFFLOAD_AUDIO; 1204 ++mAudioQueueGeneration; 1205} 1206 1207void NuPlayer::Renderer::onEnableOffloadAudio() { 1208 Mutex::Autolock autoLock(mLock); 1209 mFlags |= FLAG_OFFLOAD_AUDIO; 1210 ++mAudioQueueGeneration; 1211} 1212 1213void NuPlayer::Renderer::onPause() { 1214 if (mPaused) { 1215 ALOGW("Renderer::onPause() called while already paused!"); 1216 return; 1217 } 1218 int64_t currentPositionUs; 1219 if (getCurrentPositionFromAnchor( 1220 ¤tPositionUs, ALooper::GetNowUs()) == OK) { 1221 mPausePositionMediaTimeUs = currentPositionUs; 1222 } 1223 { 1224 Mutex::Autolock autoLock(mLock); 1225 ++mAudioQueueGeneration; 1226 ++mVideoQueueGeneration; 1227 prepareForMediaRenderingStart(); 1228 mPaused = true; 1229 setPauseStartedTimeRealUs(ALooper::GetNowUs()); 1230 } 1231 1232 mDrainAudioQueuePending = false; 1233 mDrainVideoQueuePending = false; 1234 1235 if (mHasAudio) { 1236 mAudioSink->pause(); 1237 startAudioOffloadPauseTimeout(); 1238 } 1239 1240 ALOGV("now paused audio queue has %d entries, video has %d entries", 1241 mAudioQueue.size(), mVideoQueue.size()); 1242} 1243 1244void NuPlayer::Renderer::onResume() { 1245 if (!mPaused) { 1246 return; 1247 } 1248 1249 if (mHasAudio) { 1250 cancelAudioOffloadPauseTimeout(); 1251 mAudioSink->start(); 1252 } 1253 1254 Mutex::Autolock autoLock(mLock); 1255 mPaused = false; 1256 if (mPauseStartedTimeRealUs != -1) { 1257 int64_t newAnchorRealUs = 1258 mAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; 1259 setAnchorTime( 1260 mAnchorTimeMediaUs, newAnchorRealUs, mAnchorNumFramesWritten, true /* resume */); 1261 } 1262 1263 if (!mAudioQueue.empty()) { 1264 postDrainAudioQueue_l(); 1265 } 1266 1267 if (!mVideoQueue.empty()) { 1268 postDrainVideoQueue(); 1269 } 1270} 1271 1272void NuPlayer::Renderer::onSetVideoFrameRate(float fps) { 1273 if (mVideoScheduler == NULL) { 1274 mVideoScheduler = new VideoFrameScheduler(); 1275 } 1276 mVideoScheduler->init(fps); 1277} 1278 1279// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs() 1280// as it acquires locks and may query the audio driver. 1281// 1282// Some calls could conceivably retrieve extrapolated data instead of 1283// accessing getTimestamp() or getPosition() every time a data buffer with 1284// a media time is received. 1285// 1286int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) { 1287 uint32_t numFramesPlayed; 1288 int64_t numFramesPlayedAt; 1289 AudioTimestamp ts; 1290 static const int64_t kStaleTimestamp100ms = 100000; 1291 1292 status_t res = mAudioSink->getTimestamp(ts); 1293 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks. 1294 numFramesPlayed = ts.mPosition; 1295 numFramesPlayedAt = 1296 ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000; 1297 const int64_t timestampAge = nowUs - numFramesPlayedAt; 1298 if (timestampAge > kStaleTimestamp100ms) { 1299 // This is an audio FIXME. 1300 // getTimestamp returns a timestamp which may come from audio mixing threads. 1301 // After pausing, the MixerThread may go idle, thus the mTime estimate may 1302 // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms, 1303 // the max latency should be about 25ms with an average around 12ms (to be verified). 1304 // For safety we use 100ms. 1305 ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)", 1306 (long long)nowUs, (long long)numFramesPlayedAt); 1307 numFramesPlayedAt = nowUs - kStaleTimestamp100ms; 1308 } 1309 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt); 1310 } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track 1311 numFramesPlayed = 0; 1312 numFramesPlayedAt = nowUs; 1313 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld", 1314 // numFramesPlayed, (long long)numFramesPlayedAt); 1315 } else { // case 3: transitory at new track or audio fast tracks. 1316 res = mAudioSink->getPosition(&numFramesPlayed); 1317 CHECK_EQ(res, (status_t)OK); 1318 numFramesPlayedAt = nowUs; 1319 numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */ 1320 //ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt); 1321 } 1322 1323 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours. 1324 //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test 1325 int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame()) 1326 + nowUs - numFramesPlayedAt; 1327 if (durationUs < 0) { 1328 // Occurs when numFramesPlayed position is very small and the following: 1329 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and 1330 // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed. 1331 // (2) In case 3, using getPosition and adding mAudioSink->latency() to 1332 // numFramesPlayedAt, by a time amount greater than numFramesPlayed. 1333 // 1334 // Both of these are transitory conditions. 1335 ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs); 1336 durationUs = 0; 1337 } 1338 ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)", 1339 (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt); 1340 return durationUs; 1341} 1342 1343void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) { 1344 if (mAudioOffloadTornDown) { 1345 return; 1346 } 1347 mAudioOffloadTornDown = true; 1348 1349 int64_t currentPositionUs; 1350 if (getCurrentPositionOnLooper(¤tPositionUs) != OK) { 1351 currentPositionUs = 0; 1352 } 1353 1354 mAudioSink->stop(); 1355 mAudioSink->flush(); 1356 1357 sp<AMessage> notify = mNotify->dup(); 1358 notify->setInt32("what", kWhatAudioOffloadTearDown); 1359 notify->setInt64("positionUs", currentPositionUs); 1360 notify->setInt32("reason", reason); 1361 notify->post(); 1362} 1363 1364void NuPlayer::Renderer::startAudioOffloadPauseTimeout() { 1365 if (offloadingAudio()) { 1366 sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id()); 1367 msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration); 1368 msg->post(kOffloadPauseMaxUs); 1369 } 1370} 1371 1372void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { 1373 if (offloadingAudio()) { 1374 ++mAudioOffloadPauseTimeoutGeneration; 1375 } 1376} 1377 1378status_t NuPlayer::Renderer::onOpenAudioSink( 1379 const sp<AMessage> &format, 1380 bool offloadOnly, 1381 bool hasVideo, 1382 uint32_t flags) { 1383 ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)", 1384 offloadOnly, offloadingAudio()); 1385 bool audioSinkChanged = false; 1386 1387 int32_t numChannels; 1388 CHECK(format->findInt32("channel-count", &numChannels)); 1389 1390 int32_t channelMask; 1391 if (!format->findInt32("channel-mask", &channelMask)) { 1392 // signal to the AudioSink to derive the mask from count. 1393 channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; 1394 } 1395 1396 int32_t sampleRate; 1397 CHECK(format->findInt32("sample-rate", &sampleRate)); 1398 1399 if (offloadingAudio()) { 1400 audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; 1401 AString mime; 1402 CHECK(format->findString("mime", &mime)); 1403 status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); 1404 1405 if (err != OK) { 1406 ALOGE("Couldn't map mime \"%s\" to a valid " 1407 "audio_format", mime.c_str()); 1408 onDisableOffloadAudio(); 1409 } else { 1410 ALOGV("Mime \"%s\" mapped to audio_format 0x%x", 1411 mime.c_str(), audioFormat); 1412 1413 int avgBitRate = -1; 1414 format->findInt32("bit-rate", &avgBitRate); 1415 1416 int32_t aacProfile = -1; 1417 if (audioFormat == AUDIO_FORMAT_AAC 1418 && format->findInt32("aac-profile", &aacProfile)) { 1419 // Redefine AAC format as per aac profile 1420 mapAACProfileToAudioFormat( 1421 audioFormat, 1422 aacProfile); 1423 } 1424 1425 audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; 1426 offloadInfo.duration_us = -1; 1427 format->findInt64( 1428 "durationUs", &offloadInfo.duration_us); 1429 offloadInfo.sample_rate = sampleRate; 1430 offloadInfo.channel_mask = channelMask; 1431 offloadInfo.format = audioFormat; 1432 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; 1433 offloadInfo.bit_rate = avgBitRate; 1434 offloadInfo.has_video = hasVideo; 1435 offloadInfo.is_streaming = true; 1436 1437 if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { 1438 ALOGV("openAudioSink: no change in offload mode"); 1439 // no change from previous configuration, everything ok. 1440 return OK; 1441 } 1442 ALOGV("openAudioSink: try to open AudioSink in offload mode"); 1443 uint32_t offloadFlags = flags; 1444 offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; 1445 offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 1446 audioSinkChanged = true; 1447 mAudioSink->close(); 1448 err = mAudioSink->open( 1449 sampleRate, 1450 numChannels, 1451 (audio_channel_mask_t)channelMask, 1452 audioFormat, 1453 8 /* bufferCount */, 1454 &NuPlayer::Renderer::AudioSinkCallback, 1455 this, 1456 (audio_output_flags_t)offloadFlags, 1457 &offloadInfo); 1458 1459 if (err == OK) { 1460 // If the playback is offloaded to h/w, we pass 1461 // the HAL some metadata information. 1462 // We don't want to do this for PCM because it 1463 // will be going through the AudioFlinger mixer 1464 // before reaching the hardware. 1465 // TODO 1466 mCurrentOffloadInfo = offloadInfo; 1467 err = mAudioSink->start(); 1468 ALOGV_IF(err == OK, "openAudioSink: offload succeeded"); 1469 } 1470 if (err != OK) { 1471 // Clean up, fall back to non offload mode. 1472 mAudioSink->close(); 1473 onDisableOffloadAudio(); 1474 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1475 ALOGV("openAudioSink: offload failed"); 1476 } 1477 } 1478 } 1479 if (!offloadOnly && !offloadingAudio()) { 1480 ALOGV("openAudioSink: open AudioSink in NON-offload mode"); 1481 uint32_t pcmFlags = flags; 1482 pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; 1483 audioSinkChanged = true; 1484 mAudioSink->close(); 1485 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1486 status_t err = mAudioSink->open( 1487 sampleRate, 1488 numChannels, 1489 (audio_channel_mask_t)channelMask, 1490 AUDIO_FORMAT_PCM_16_BIT, 1491 8 /* bufferCount */, 1492 NULL, 1493 NULL, 1494 (audio_output_flags_t)pcmFlags); 1495 if (err != OK) { 1496 ALOGW("openAudioSink: non offloaded open failed status: %d", err); 1497 return err; 1498 } 1499 mAudioSink->start(); 1500 } 1501 if (audioSinkChanged) { 1502 onAudioSinkChanged(); 1503 } 1504 if (offloadingAudio()) { 1505 mAudioOffloadTornDown = false; 1506 } 1507 return OK; 1508} 1509 1510void NuPlayer::Renderer::onCloseAudioSink() { 1511 mAudioSink->close(); 1512 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; 1513} 1514 1515} // namespace android 1516 1517