NuPlayerRenderer.cpp revision 5095d7091874cb9e9c95ecc4fe762076ed05e624
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/MediaErrors.h>
27#include <media/stagefright/MetaData.h>
28
29#include <inttypes.h>
30
31namespace android {
32
33// static
34const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
35
36NuPlayer::Renderer::Renderer(
37        const sp<MediaPlayerBase::AudioSink> &sink,
38        const sp<AMessage> &notify,
39        uint32_t flags)
40    : mAudioSink(sink),
41      mNotify(notify),
42      mFlags(flags),
43      mNumFramesWritten(0),
44      mDrainAudioQueuePending(false),
45      mDrainVideoQueuePending(false),
46      mAudioQueueGeneration(0),
47      mVideoQueueGeneration(0),
48      mFirstAudioTimeUs(-1),
49      mAnchorTimeMediaUs(-1),
50      mAnchorTimeRealUs(-1),
51      mFlushingAudio(false),
52      mFlushingVideo(false),
53      mHasAudio(false),
54      mHasVideo(false),
55      mSyncQueues(false),
56      mPaused(false),
57      mVideoRenderingStarted(false),
58      mVideoRenderingStartGeneration(0),
59      mAudioRenderingStartGeneration(0),
60      mLastPositionUpdateUs(-1ll),
61      mVideoLateByUs(0ll) {
62}
63
64NuPlayer::Renderer::~Renderer() {
65    if (offloadingAudio()) {
66        mAudioSink->stop();
67        mAudioSink->flush();
68        mAudioSink->close();
69    }
70}
71
72void NuPlayer::Renderer::queueBuffer(
73        bool audio,
74        const sp<ABuffer> &buffer,
75        const sp<AMessage> &notifyConsumed) {
76    sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
77    msg->setInt32("audio", static_cast<int32_t>(audio));
78    msg->setBuffer("buffer", buffer);
79    msg->setMessage("notifyConsumed", notifyConsumed);
80    msg->post();
81}
82
83void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
84    CHECK_NE(finalResult, (status_t)OK);
85
86    sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
87    msg->setInt32("audio", static_cast<int32_t>(audio));
88    msg->setInt32("finalResult", finalResult);
89    msg->post();
90}
91
92void NuPlayer::Renderer::flush(bool audio) {
93    {
94        Mutex::Autolock autoLock(mFlushLock);
95        if (audio) {
96            if (mFlushingAudio) {
97                return;
98            }
99            mFlushingAudio = true;
100        } else {
101            if (mFlushingVideo) {
102                return;
103            }
104            mFlushingVideo = true;
105        }
106    }
107
108    sp<AMessage> msg = new AMessage(kWhatFlush, id());
109    msg->setInt32("audio", static_cast<int32_t>(audio));
110    msg->post();
111}
112
113void NuPlayer::Renderer::signalTimeDiscontinuity() {
114    Mutex::Autolock autoLock(mLock);
115    // CHECK(mAudioQueue.empty());
116    // CHECK(mVideoQueue.empty());
117    mAnchorTimeMediaUs = -1;
118    mAnchorTimeRealUs = -1;
119    mSyncQueues = false;
120}
121
122void NuPlayer::Renderer::signalAudioSinkChanged() {
123    (new AMessage(kWhatAudioSinkChanged, id()))->post();
124}
125
126void NuPlayer::Renderer::signalDisableOffloadAudio() {
127    (new AMessage(kWhatDisableOffloadAudio, id()))->post();
128}
129
130void NuPlayer::Renderer::pause() {
131    (new AMessage(kWhatPause, id()))->post();
132}
133
134void NuPlayer::Renderer::resume() {
135    (new AMessage(kWhatResume, id()))->post();
136}
137
138void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
139    switch (msg->what()) {
140        case kWhatStopAudioSink:
141        {
142            mAudioSink->stop();
143            break;
144        }
145
146        case kWhatDrainAudioQueue:
147        {
148            int32_t generation;
149            CHECK(msg->findInt32("generation", &generation));
150            if (generation != mAudioQueueGeneration) {
151                break;
152            }
153
154            mDrainAudioQueuePending = false;
155
156            if (onDrainAudioQueue()) {
157                uint32_t numFramesPlayed;
158                CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
159                         (status_t)OK);
160
161                uint32_t numFramesPendingPlayout =
162                    mNumFramesWritten - numFramesPlayed;
163
164                // This is how long the audio sink will have data to
165                // play back.
166                int64_t delayUs =
167                    mAudioSink->msecsPerFrame()
168                        * numFramesPendingPlayout * 1000ll;
169
170                // Let's give it more data after about half that time
171                // has elapsed.
172                // kWhatDrainAudioQueue is used for non-offloading mode,
173                // and mLock is used only for offloading mode. Therefore,
174                // no need to acquire mLock here.
175                postDrainAudioQueue_l(delayUs / 2);
176            }
177            break;
178        }
179
180        case kWhatDrainVideoQueue:
181        {
182            int32_t generation;
183            CHECK(msg->findInt32("generation", &generation));
184            if (generation != mVideoQueueGeneration) {
185                break;
186            }
187
188            mDrainVideoQueuePending = false;
189
190            onDrainVideoQueue();
191
192            postDrainVideoQueue();
193            break;
194        }
195
196        case kWhatQueueBuffer:
197        {
198            onQueueBuffer(msg);
199            break;
200        }
201
202        case kWhatQueueEOS:
203        {
204            onQueueEOS(msg);
205            break;
206        }
207
208        case kWhatFlush:
209        {
210            onFlush(msg);
211            break;
212        }
213
214        case kWhatAudioSinkChanged:
215        {
216            onAudioSinkChanged();
217            break;
218        }
219
220        case kWhatDisableOffloadAudio:
221        {
222            onDisableOffloadAudio();
223            break;
224        }
225
226        case kWhatPause:
227        {
228            onPause();
229            break;
230        }
231
232        case kWhatResume:
233        {
234            onResume();
235            break;
236        }
237
238        case kWhatAudioOffloadTearDown:
239        {
240            onAudioOffloadTearDown();
241            break;
242        }
243
244        default:
245            TRESPASS();
246            break;
247    }
248}
249
250void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
251    if (mDrainAudioQueuePending || mSyncQueues || mPaused
252            || offloadingAudio()) {
253        return;
254    }
255
256    if (mAudioQueue.empty()) {
257        return;
258    }
259
260    mDrainAudioQueuePending = true;
261    sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
262    msg->setInt32("generation", mAudioQueueGeneration);
263    msg->post(delayUs);
264}
265
266void NuPlayer::Renderer::prepareForMediaRenderingStart() {
267    mAudioRenderingStartGeneration = mAudioQueueGeneration;
268    mVideoRenderingStartGeneration = mVideoQueueGeneration;
269}
270
271void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
272    if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
273        mAudioRenderingStartGeneration == mAudioQueueGeneration) {
274        mVideoRenderingStartGeneration = -1;
275        mAudioRenderingStartGeneration = -1;
276
277        sp<AMessage> notify = mNotify->dup();
278        notify->setInt32("what", kWhatMediaRenderingStart);
279        notify->post();
280    }
281}
282
283// static
284size_t NuPlayer::Renderer::AudioSinkCallback(
285        MediaPlayerBase::AudioSink * /* audioSink */,
286        void *buffer,
287        size_t size,
288        void *cookie,
289        MediaPlayerBase::AudioSink::cb_event_t event) {
290    NuPlayer::Renderer *me = (NuPlayer::Renderer *)cookie;
291
292    switch (event) {
293        case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
294        {
295            return me->fillAudioBuffer(buffer, size);
296            break;
297        }
298
299        case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
300        {
301            me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
302            break;
303        }
304
305        case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
306        {
307            me->notifyAudioOffloadTearDown();
308            break;
309        }
310    }
311
312    return 0;
313}
314
315size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
316    Mutex::Autolock autoLock(mLock);
317
318    if (!offloadingAudio()) {
319        return 0;
320    }
321
322    bool hasEOS = false;
323
324    size_t sizeCopied = 0;
325    bool firstEntry = true;
326    while (sizeCopied < size && !mAudioQueue.empty()) {
327        QueueEntry *entry = &*mAudioQueue.begin();
328
329        if (entry->mBuffer == NULL) { // EOS
330            hasEOS = true;
331            mAudioQueue.erase(mAudioQueue.begin());
332            entry = NULL;
333            break;
334        }
335
336        if (firstEntry && entry->mOffset == 0) {
337            firstEntry = false;
338            int64_t mediaTimeUs;
339            CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
340            ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
341            if (mFirstAudioTimeUs == -1) {
342                mFirstAudioTimeUs = mediaTimeUs;
343            }
344
345            uint32_t numFramesPlayed;
346            CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
347
348            // TODO: figure out how to calculate initial latency.
349            // Otherwise, the initial time is not correct till the first sample
350            // is played.
351            mAnchorTimeMediaUs = mFirstAudioTimeUs
352                    + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
353            mAnchorTimeRealUs = ALooper::GetNowUs();
354        }
355
356        size_t copy = entry->mBuffer->size() - entry->mOffset;
357        size_t sizeRemaining = size - sizeCopied;
358        if (copy > sizeRemaining) {
359            copy = sizeRemaining;
360        }
361
362        memcpy((char *)buffer + sizeCopied,
363               entry->mBuffer->data() + entry->mOffset,
364               copy);
365
366        entry->mOffset += copy;
367        if (entry->mOffset == entry->mBuffer->size()) {
368            entry->mNotifyConsumed->post();
369            mAudioQueue.erase(mAudioQueue.begin());
370            entry = NULL;
371        }
372        sizeCopied += copy;
373        notifyIfMediaRenderingStarted();
374    }
375
376    if (sizeCopied != 0) {
377        notifyPosition();
378    }
379
380    if (hasEOS) {
381        (new AMessage(kWhatStopAudioSink, id()))->post();
382    }
383
384    return sizeCopied;
385}
386
387bool NuPlayer::Renderer::onDrainAudioQueue() {
388    uint32_t numFramesPlayed;
389    if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
390        return false;
391    }
392
393    ssize_t numFramesAvailableToWrite =
394        mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
395
396#if 0
397    if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
398        ALOGI("audio sink underrun");
399    } else {
400        ALOGV("audio queue has %d frames left to play",
401             mAudioSink->frameCount() - numFramesAvailableToWrite);
402    }
403#endif
404
405    size_t numBytesAvailableToWrite =
406        numFramesAvailableToWrite * mAudioSink->frameSize();
407
408    while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
409        QueueEntry *entry = &*mAudioQueue.begin();
410
411        if (entry->mBuffer == NULL) {
412            // EOS
413            int64_t postEOSDelayUs = 0;
414            if (mAudioSink->needsTrailingPadding()) {
415                postEOSDelayUs = getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency();
416            }
417            notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
418
419            mAudioQueue.erase(mAudioQueue.begin());
420            entry = NULL;
421            return false;
422        }
423
424        if (entry->mOffset == 0) {
425            int64_t mediaTimeUs;
426            CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
427            ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
428            mAnchorTimeMediaUs = mediaTimeUs;
429
430            mAnchorTimeRealUs = ALooper::GetNowUs()
431                    + getAudioPendingPlayoutUs() + 1000 * mAudioSink->latency() / 2;
432        }
433
434        size_t copy = entry->mBuffer->size() - entry->mOffset;
435        if (copy > numBytesAvailableToWrite) {
436            copy = numBytesAvailableToWrite;
437        }
438
439        ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy);
440        if (written < 0) {
441            // An error in AudioSink write is fatal here.
442            LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy);
443        }
444
445        entry->mOffset += written;
446        if (entry->mOffset == entry->mBuffer->size()) {
447            entry->mNotifyConsumed->post();
448            mAudioQueue.erase(mAudioQueue.begin());
449
450            entry = NULL;
451        }
452
453        numBytesAvailableToWrite -= written;
454        size_t copiedFrames = written / mAudioSink->frameSize();
455        mNumFramesWritten += copiedFrames;
456
457        notifyIfMediaRenderingStarted();
458
459        if (written != (ssize_t)copy) {
460            // A short count was received from AudioSink::write()
461            //
462            // AudioSink write should block until exactly the number of bytes are delivered.
463            // But it may return with a short count (without an error) when:
464            //
465            // 1) Size to be copied is not a multiple of the frame size. We consider this fatal.
466            // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
467
468            // (Case 1)
469            // Must be a multiple of the frame size.  If it is not a multiple of a frame size, it
470            // needs to fail, as we should not carry over fractional frames between calls.
471            CHECK_EQ(copy % mAudioSink->frameSize(), 0);
472
473            // (Case 2)
474            // Return early to the caller.
475            // Beware of calling immediately again as this may busy-loop if you are not careful.
476            ALOGW("AudioSink write short frame count %zd < %zu", written, copy);
477            break;
478        }
479    }
480    notifyPosition();
481
482    return !mAudioQueue.empty();
483}
484
485int64_t NuPlayer::Renderer::getAudioPendingPlayoutUs() {
486    uint32_t numFramesPlayed;
487    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
488
489    uint32_t numFramesPendingPlayout = mNumFramesWritten - numFramesPlayed;
490    return numFramesPendingPlayout * mAudioSink->msecsPerFrame() * 1000;
491}
492
493void NuPlayer::Renderer::postDrainVideoQueue() {
494    if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
495        return;
496    }
497
498    if (mVideoQueue.empty()) {
499        return;
500    }
501
502    QueueEntry &entry = *mVideoQueue.begin();
503
504    sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
505    msg->setInt32("generation", mVideoQueueGeneration);
506
507    int64_t delayUs;
508
509    if (entry.mBuffer == NULL) {
510        // EOS doesn't carry a timestamp.
511        delayUs = 0;
512    } else if (mFlags & FLAG_REAL_TIME) {
513        int64_t mediaTimeUs;
514        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
515
516        delayUs = mediaTimeUs - ALooper::GetNowUs();
517    } else {
518        int64_t mediaTimeUs;
519        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
520
521        if (mAnchorTimeMediaUs < 0) {
522            delayUs = 0;
523
524            if (!mHasAudio) {
525                mAnchorTimeMediaUs = mediaTimeUs;
526                mAnchorTimeRealUs = ALooper::GetNowUs();
527            }
528        } else {
529            int64_t realTimeUs =
530                (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
531
532            delayUs = realTimeUs - ALooper::GetNowUs();
533        }
534    }
535
536    ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
537    msg->post(delayUs);
538
539    mDrainVideoQueuePending = true;
540}
541
542void NuPlayer::Renderer::onDrainVideoQueue() {
543    if (mVideoQueue.empty()) {
544        return;
545    }
546
547    QueueEntry *entry = &*mVideoQueue.begin();
548
549    if (entry->mBuffer == NULL) {
550        // EOS
551
552        notifyEOS(false /* audio */, entry->mFinalResult);
553
554        mVideoQueue.erase(mVideoQueue.begin());
555        entry = NULL;
556
557        mVideoLateByUs = 0ll;
558
559        notifyPosition();
560        return;
561    }
562
563    int64_t realTimeUs;
564    if (mFlags & FLAG_REAL_TIME) {
565        CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
566    } else {
567        int64_t mediaTimeUs;
568        CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
569
570        realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
571    }
572
573    mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
574    bool tooLate = (mVideoLateByUs > 40000);
575
576    if (tooLate) {
577        ALOGV("video late by %lld us (%.2f secs)",
578             mVideoLateByUs, mVideoLateByUs / 1E6);
579    } else {
580        ALOGV("rendering video at media time %.2f secs",
581                (mFlags & FLAG_REAL_TIME ? realTimeUs :
582                (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
583    }
584
585    entry->mNotifyConsumed->setInt32("render", !tooLate);
586    entry->mNotifyConsumed->post();
587    mVideoQueue.erase(mVideoQueue.begin());
588    entry = NULL;
589
590    if (!mVideoRenderingStarted) {
591        mVideoRenderingStarted = true;
592        notifyVideoRenderingStart();
593    }
594
595    notifyIfMediaRenderingStarted();
596
597    notifyPosition();
598}
599
600void NuPlayer::Renderer::notifyVideoRenderingStart() {
601    sp<AMessage> notify = mNotify->dup();
602    notify->setInt32("what", kWhatVideoRenderingStart);
603    notify->post();
604}
605
606void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
607    sp<AMessage> notify = mNotify->dup();
608    notify->setInt32("what", kWhatEOS);
609    notify->setInt32("audio", static_cast<int32_t>(audio));
610    notify->setInt32("finalResult", finalResult);
611    notify->post(delayUs);
612}
613
614void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
615    (new AMessage(kWhatAudioOffloadTearDown, id()))->post();
616}
617
618void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
619    int32_t audio;
620    CHECK(msg->findInt32("audio", &audio));
621
622    if (audio) {
623        mHasAudio = true;
624    } else {
625        mHasVideo = true;
626    }
627
628    if (dropBufferWhileFlushing(audio, msg)) {
629        return;
630    }
631
632    sp<ABuffer> buffer;
633    CHECK(msg->findBuffer("buffer", &buffer));
634
635    sp<AMessage> notifyConsumed;
636    CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
637
638    QueueEntry entry;
639    entry.mBuffer = buffer;
640    entry.mNotifyConsumed = notifyConsumed;
641    entry.mOffset = 0;
642    entry.mFinalResult = OK;
643
644    if (audio) {
645        Mutex::Autolock autoLock(mLock);
646        mAudioQueue.push_back(entry);
647        postDrainAudioQueue_l();
648    } else {
649        mVideoQueue.push_back(entry);
650        postDrainVideoQueue();
651    }
652
653    Mutex::Autolock autoLock(mLock);
654    if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
655        return;
656    }
657
658    sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
659    sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
660
661    if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
662        // EOS signalled on either queue.
663        syncQueuesDone_l();
664        return;
665    }
666
667    int64_t firstAudioTimeUs;
668    int64_t firstVideoTimeUs;
669    CHECK(firstAudioBuffer->meta()
670            ->findInt64("timeUs", &firstAudioTimeUs));
671    CHECK(firstVideoBuffer->meta()
672            ->findInt64("timeUs", &firstVideoTimeUs));
673
674    int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
675
676    ALOGV("queueDiff = %.2f secs", diff / 1E6);
677
678    if (diff > 100000ll) {
679        // Audio data starts More than 0.1 secs before video.
680        // Drop some audio.
681
682        (*mAudioQueue.begin()).mNotifyConsumed->post();
683        mAudioQueue.erase(mAudioQueue.begin());
684        return;
685    }
686
687    syncQueuesDone_l();
688}
689
690void NuPlayer::Renderer::syncQueuesDone_l() {
691    if (!mSyncQueues) {
692        return;
693    }
694
695    mSyncQueues = false;
696
697    if (!mAudioQueue.empty()) {
698        postDrainAudioQueue_l();
699    }
700
701    if (!mVideoQueue.empty()) {
702        postDrainVideoQueue();
703    }
704}
705
706void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
707    int32_t audio;
708    CHECK(msg->findInt32("audio", &audio));
709
710    if (dropBufferWhileFlushing(audio, msg)) {
711        return;
712    }
713
714    int32_t finalResult;
715    CHECK(msg->findInt32("finalResult", &finalResult));
716
717    QueueEntry entry;
718    entry.mOffset = 0;
719    entry.mFinalResult = finalResult;
720
721    if (audio) {
722        Mutex::Autolock autoLock(mLock);
723        if (mAudioQueue.empty() && mSyncQueues) {
724            syncQueuesDone_l();
725        }
726        mAudioQueue.push_back(entry);
727        postDrainAudioQueue_l();
728    } else {
729        if (mVideoQueue.empty() && mSyncQueues) {
730            Mutex::Autolock autoLock(mLock);
731            syncQueuesDone_l();
732        }
733        mVideoQueue.push_back(entry);
734        postDrainVideoQueue();
735    }
736}
737
738void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
739    int32_t audio;
740    CHECK(msg->findInt32("audio", &audio));
741
742    {
743        Mutex::Autolock autoLock(mFlushLock);
744        if (audio) {
745            mFlushingAudio = false;
746        } else {
747            mFlushingVideo = false;
748        }
749    }
750
751    // If we're currently syncing the queues, i.e. dropping audio while
752    // aligning the first audio/video buffer times and only one of the
753    // two queues has data, we may starve that queue by not requesting
754    // more buffers from the decoder. If the other source then encounters
755    // a discontinuity that leads to flushing, we'll never find the
756    // corresponding discontinuity on the other queue.
757    // Therefore we'll stop syncing the queues if at least one of them
758    // is flushed.
759    {
760         Mutex::Autolock autoLock(mLock);
761         syncQueuesDone_l();
762    }
763
764    ALOGV("flushing %s", audio ? "audio" : "video");
765    if (audio) {
766        {
767            Mutex::Autolock autoLock(mLock);
768            flushQueue(&mAudioQueue);
769
770            ++mAudioQueueGeneration;
771            prepareForMediaRenderingStart();
772
773            if (offloadingAudio()) {
774                mFirstAudioTimeUs = -1;
775            }
776        }
777
778        mDrainAudioQueuePending = false;
779
780        if (offloadingAudio()) {
781            mAudioSink->pause();
782            mAudioSink->flush();
783            mAudioSink->start();
784        }
785    } else {
786        flushQueue(&mVideoQueue);
787
788        mDrainVideoQueuePending = false;
789        ++mVideoQueueGeneration;
790
791        prepareForMediaRenderingStart();
792    }
793
794    notifyFlushComplete(audio);
795}
796
797void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
798    while (!queue->empty()) {
799        QueueEntry *entry = &*queue->begin();
800
801        if (entry->mBuffer != NULL) {
802            entry->mNotifyConsumed->post();
803        }
804
805        queue->erase(queue->begin());
806        entry = NULL;
807    }
808}
809
810void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
811    sp<AMessage> notify = mNotify->dup();
812    notify->setInt32("what", kWhatFlushComplete);
813    notify->setInt32("audio", static_cast<int32_t>(audio));
814    notify->post();
815}
816
817bool NuPlayer::Renderer::dropBufferWhileFlushing(
818        bool audio, const sp<AMessage> &msg) {
819    bool flushing = false;
820
821    {
822        Mutex::Autolock autoLock(mFlushLock);
823        if (audio) {
824            flushing = mFlushingAudio;
825        } else {
826            flushing = mFlushingVideo;
827        }
828    }
829
830    if (!flushing) {
831        return false;
832    }
833
834    sp<AMessage> notifyConsumed;
835    if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
836        notifyConsumed->post();
837    }
838
839    return true;
840}
841
842void NuPlayer::Renderer::onAudioSinkChanged() {
843    if (offloadingAudio()) {
844        return;
845    }
846    CHECK(!mDrainAudioQueuePending);
847    mNumFramesWritten = 0;
848    uint32_t written;
849    if (mAudioSink->getFramesWritten(&written) == OK) {
850        mNumFramesWritten = written;
851    }
852}
853
854void NuPlayer::Renderer::onDisableOffloadAudio() {
855    Mutex::Autolock autoLock(mLock);
856    mFlags &= ~FLAG_OFFLOAD_AUDIO;
857    ++mAudioQueueGeneration;
858}
859
860void NuPlayer::Renderer::notifyPosition() {
861    if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
862        return;
863    }
864
865    int64_t nowUs = ALooper::GetNowUs();
866
867    if (mLastPositionUpdateUs >= 0
868            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
869        return;
870    }
871    mLastPositionUpdateUs = nowUs;
872
873    int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
874
875    sp<AMessage> notify = mNotify->dup();
876    notify->setInt32("what", kWhatPosition);
877    notify->setInt64("positionUs", positionUs);
878    notify->setInt64("videoLateByUs", mVideoLateByUs);
879    notify->post();
880}
881
882void NuPlayer::Renderer::onPause() {
883    CHECK(!mPaused);
884
885    {
886        Mutex::Autolock autoLock(mLock);
887        ++mAudioQueueGeneration;
888        ++mVideoQueueGeneration;
889        prepareForMediaRenderingStart();
890    }
891
892    mDrainAudioQueuePending = false;
893    mDrainVideoQueuePending = false;
894
895    if (mHasAudio) {
896        mAudioSink->pause();
897    }
898
899    ALOGV("now paused audio queue has %d entries, video has %d entries",
900          mAudioQueue.size(), mVideoQueue.size());
901
902    mPaused = true;
903}
904
905void NuPlayer::Renderer::onResume() {
906    if (!mPaused) {
907        return;
908    }
909
910    if (mHasAudio) {
911        mAudioSink->start();
912    }
913
914    mPaused = false;
915
916    Mutex::Autolock autoLock(mLock);
917    if (!mAudioQueue.empty()) {
918        postDrainAudioQueue_l();
919    }
920
921    if (!mVideoQueue.empty()) {
922        postDrainVideoQueue();
923    }
924}
925
926void NuPlayer::Renderer::onAudioOffloadTearDown() {
927    uint32_t numFramesPlayed;
928    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
929
930    int64_t firstAudioTimeUs;
931    {
932        Mutex::Autolock autoLock(mLock);
933        firstAudioTimeUs = mFirstAudioTimeUs;
934    }
935    int64_t currentPositionUs = firstAudioTimeUs
936            + (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
937
938    mAudioSink->stop();
939    mAudioSink->flush();
940
941    sp<AMessage> notify = mNotify->dup();
942    notify->setInt32("what", kWhatAudioOffloadTearDown);
943    notify->setInt64("positionUs", currentPositionUs);
944    notify->post();
945}
946
947}  // namespace android
948
949