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