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