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