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