xref: /aosp_15_r20/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_AUDIO
19*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NuPlayerRenderer"
20*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
21*ec779b8eSAndroid Build Coastguard Worker 
22*ec779b8eSAndroid Build Coastguard Worker #include "AWakeLock.h"
23*ec779b8eSAndroid Build Coastguard Worker #include "NuPlayerRenderer.h"
24*ec779b8eSAndroid Build Coastguard Worker #include <algorithm>
25*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ADebug.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/AMessage.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/AUtils.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaClock.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaCodecConstants.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaDefs.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaErrors.h>
33*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MetaData.h>
34*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/Utils.h>
35*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/VideoFrameScheduler.h>
36*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaCodecBuffer.h>
37*ec779b8eSAndroid Build Coastguard Worker #include <utils/SystemClock.h>
38*ec779b8eSAndroid Build Coastguard Worker 
39*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
40*ec779b8eSAndroid Build Coastguard Worker 
41*ec779b8eSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
42*ec779b8eSAndroid Build Coastguard Worker using ::android::base::StringPrintf;
43*ec779b8eSAndroid Build Coastguard Worker 
44*ec779b8eSAndroid Build Coastguard Worker namespace android {
45*ec779b8eSAndroid Build Coastguard Worker 
46*ec779b8eSAndroid Build Coastguard Worker /*
47*ec779b8eSAndroid Build Coastguard Worker  * Example of common configuration settings in shell script form
48*ec779b8eSAndroid Build Coastguard Worker 
49*ec779b8eSAndroid Build Coastguard Worker    #Turn offload audio off (use PCM for Play Music) -- AudioPolicyManager
50*ec779b8eSAndroid Build Coastguard Worker    adb shell setprop audio.offload.disable 1
51*ec779b8eSAndroid Build Coastguard Worker 
52*ec779b8eSAndroid Build Coastguard Worker    #Allow offload audio with video (requires offloading to be enabled) -- AudioPolicyManager
53*ec779b8eSAndroid Build Coastguard Worker    adb shell setprop audio.offload.video 1
54*ec779b8eSAndroid Build Coastguard Worker 
55*ec779b8eSAndroid Build Coastguard Worker    #Use audio callbacks for PCM data
56*ec779b8eSAndroid Build Coastguard Worker    adb shell setprop media.stagefright.audio.cbk 1
57*ec779b8eSAndroid Build Coastguard Worker 
58*ec779b8eSAndroid Build Coastguard Worker    #Use deep buffer for PCM data with video (it is generally enabled for audio-only)
59*ec779b8eSAndroid Build Coastguard Worker    adb shell setprop media.stagefright.audio.deep 1
60*ec779b8eSAndroid Build Coastguard Worker 
61*ec779b8eSAndroid Build Coastguard Worker    #Set size of buffers for pcm audio sink in msec (example: 1000 msec)
62*ec779b8eSAndroid Build Coastguard Worker    adb shell setprop media.stagefright.audio.sink 1000
63*ec779b8eSAndroid Build Coastguard Worker 
64*ec779b8eSAndroid Build Coastguard Worker  * These configurations take effect for the next track played (not the current track).
65*ec779b8eSAndroid Build Coastguard Worker  */
66*ec779b8eSAndroid Build Coastguard Worker 
getUseAudioCallbackSetting()67*ec779b8eSAndroid Build Coastguard Worker static inline bool getUseAudioCallbackSetting() {
68*ec779b8eSAndroid Build Coastguard Worker     return property_get_bool("media.stagefright.audio.cbk", false /* default_value */);
69*ec779b8eSAndroid Build Coastguard Worker }
70*ec779b8eSAndroid Build Coastguard Worker 
getAudioSinkPcmMsSetting()71*ec779b8eSAndroid Build Coastguard Worker static inline int32_t getAudioSinkPcmMsSetting() {
72*ec779b8eSAndroid Build Coastguard Worker     return property_get_int32(
73*ec779b8eSAndroid Build Coastguard Worker             "media.stagefright.audio.sink", 500 /* default_value */);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker 
76*ec779b8eSAndroid Build Coastguard Worker // Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
77*ec779b8eSAndroid Build Coastguard Worker // is closed to allow the audio DSP to power down.
78*ec779b8eSAndroid Build Coastguard Worker static const int64_t kOffloadPauseMaxUs = 10000000LL;
79*ec779b8eSAndroid Build Coastguard Worker 
80*ec779b8eSAndroid Build Coastguard Worker // Additional delay after teardown before releasing the wake lock to allow time for the audio path
81*ec779b8eSAndroid Build Coastguard Worker // to be completely released
82*ec779b8eSAndroid Build Coastguard Worker static const int64_t kWakelockReleaseDelayUs = 2000000LL;
83*ec779b8eSAndroid Build Coastguard Worker 
84*ec779b8eSAndroid Build Coastguard Worker // Maximum allowed delay from AudioSink, 1.5 seconds.
85*ec779b8eSAndroid Build Coastguard Worker static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000LL;
86*ec779b8eSAndroid Build Coastguard Worker 
87*ec779b8eSAndroid Build Coastguard Worker static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
88*ec779b8eSAndroid Build Coastguard Worker 
89*ec779b8eSAndroid Build Coastguard Worker // Default video frame display duration when only video exists.
90*ec779b8eSAndroid Build Coastguard Worker // Used to set max media time in MediaClock.
91*ec779b8eSAndroid Build Coastguard Worker static const int64_t kDefaultVideoFrameIntervalUs = 100000LL;
92*ec779b8eSAndroid Build Coastguard Worker 
93*ec779b8eSAndroid Build Coastguard Worker // static
94*ec779b8eSAndroid Build Coastguard Worker const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {
95*ec779b8eSAndroid Build Coastguard Worker         AUDIO_CHANNEL_NONE,
96*ec779b8eSAndroid Build Coastguard Worker         AUDIO_OUTPUT_FLAG_NONE,
97*ec779b8eSAndroid Build Coastguard Worker         AUDIO_FORMAT_INVALID,
98*ec779b8eSAndroid Build Coastguard Worker         0, // mNumChannels
99*ec779b8eSAndroid Build Coastguard Worker         0 // mSampleRate
100*ec779b8eSAndroid Build Coastguard Worker };
101*ec779b8eSAndroid Build Coastguard Worker 
102*ec779b8eSAndroid Build Coastguard Worker // static
103*ec779b8eSAndroid Build Coastguard Worker const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
104*ec779b8eSAndroid Build Coastguard Worker 
Renderer(const sp<MediaPlayerBase::AudioSink> & sink,const sp<MediaClock> & mediaClock,const sp<AMessage> & notify,uint32_t flags)105*ec779b8eSAndroid Build Coastguard Worker NuPlayer::Renderer::Renderer(
106*ec779b8eSAndroid Build Coastguard Worker         const sp<MediaPlayerBase::AudioSink> &sink,
107*ec779b8eSAndroid Build Coastguard Worker         const sp<MediaClock> &mediaClock,
108*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &notify,
109*ec779b8eSAndroid Build Coastguard Worker         uint32_t flags)
110*ec779b8eSAndroid Build Coastguard Worker     : mAudioSink(sink),
111*ec779b8eSAndroid Build Coastguard Worker       mUseVirtualAudioSink(false),
112*ec779b8eSAndroid Build Coastguard Worker       mNotify(notify),
113*ec779b8eSAndroid Build Coastguard Worker       mFlags(flags),
114*ec779b8eSAndroid Build Coastguard Worker       mNumFramesWritten(0),
115*ec779b8eSAndroid Build Coastguard Worker       mDrainAudioQueuePending(false),
116*ec779b8eSAndroid Build Coastguard Worker       mDrainVideoQueuePending(false),
117*ec779b8eSAndroid Build Coastguard Worker       mAudioQueueGeneration(0),
118*ec779b8eSAndroid Build Coastguard Worker       mVideoQueueGeneration(0),
119*ec779b8eSAndroid Build Coastguard Worker       mAudioDrainGeneration(0),
120*ec779b8eSAndroid Build Coastguard Worker       mVideoDrainGeneration(0),
121*ec779b8eSAndroid Build Coastguard Worker       mAudioEOSGeneration(0),
122*ec779b8eSAndroid Build Coastguard Worker       mMediaClock(mediaClock),
123*ec779b8eSAndroid Build Coastguard Worker       mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
124*ec779b8eSAndroid Build Coastguard Worker       mAudioFirstAnchorTimeMediaUs(-1),
125*ec779b8eSAndroid Build Coastguard Worker       mAudioAnchorTimeMediaUs(-1),
126*ec779b8eSAndroid Build Coastguard Worker       mAnchorTimeMediaUs(-1),
127*ec779b8eSAndroid Build Coastguard Worker       mAnchorNumFramesWritten(-1),
128*ec779b8eSAndroid Build Coastguard Worker       mVideoLateByUs(0LL),
129*ec779b8eSAndroid Build Coastguard Worker       mNextVideoTimeMediaUs(-1),
130*ec779b8eSAndroid Build Coastguard Worker       mHasAudio(false),
131*ec779b8eSAndroid Build Coastguard Worker       mHasVideo(false),
132*ec779b8eSAndroid Build Coastguard Worker       mNotifyCompleteAudio(false),
133*ec779b8eSAndroid Build Coastguard Worker       mNotifyCompleteVideo(false),
134*ec779b8eSAndroid Build Coastguard Worker       mSyncQueues(false),
135*ec779b8eSAndroid Build Coastguard Worker       mPaused(false),
136*ec779b8eSAndroid Build Coastguard Worker       mPauseDrainAudioAllowedUs(0),
137*ec779b8eSAndroid Build Coastguard Worker       mVideoSampleReceived(false),
138*ec779b8eSAndroid Build Coastguard Worker       mVideoRenderingStarted(false),
139*ec779b8eSAndroid Build Coastguard Worker       mVideoRenderingStartGeneration(0),
140*ec779b8eSAndroid Build Coastguard Worker       mAudioRenderingStartGeneration(0),
141*ec779b8eSAndroid Build Coastguard Worker       mRenderingDataDelivered(false),
142*ec779b8eSAndroid Build Coastguard Worker       mNextAudioClockUpdateTimeUs(-1),
143*ec779b8eSAndroid Build Coastguard Worker       mLastAudioMediaTimeUs(-1),
144*ec779b8eSAndroid Build Coastguard Worker       mAudioOffloadPauseTimeoutGeneration(0),
145*ec779b8eSAndroid Build Coastguard Worker       mAudioTornDown(false),
146*ec779b8eSAndroid Build Coastguard Worker       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
147*ec779b8eSAndroid Build Coastguard Worker       mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
148*ec779b8eSAndroid Build Coastguard Worker       mTotalBuffersQueued(0),
149*ec779b8eSAndroid Build Coastguard Worker       mLastAudioBufferDrained(0),
150*ec779b8eSAndroid Build Coastguard Worker       mUseAudioCallback(false),
151*ec779b8eSAndroid Build Coastguard Worker       mWakeLock(new AWakeLock()),
152*ec779b8eSAndroid Build Coastguard Worker       mNeedVideoClearAnchor(false) {
153*ec779b8eSAndroid Build Coastguard Worker     CHECK(mediaClock != NULL);
154*ec779b8eSAndroid Build Coastguard Worker     mPlaybackRate = mPlaybackSettings.mSpeed;
155*ec779b8eSAndroid Build Coastguard Worker     mMediaClock->setPlaybackRate(mPlaybackRate);
156*ec779b8eSAndroid Build Coastguard Worker     (void)mSyncFlag.test_and_set();
157*ec779b8eSAndroid Build Coastguard Worker }
158*ec779b8eSAndroid Build Coastguard Worker 
~Renderer()159*ec779b8eSAndroid Build Coastguard Worker NuPlayer::Renderer::~Renderer() {
160*ec779b8eSAndroid Build Coastguard Worker     if (offloadingAudio()) {
161*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->stop();
162*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->flush();
163*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->close();
164*ec779b8eSAndroid Build Coastguard Worker     }
165*ec779b8eSAndroid Build Coastguard Worker 
166*ec779b8eSAndroid Build Coastguard Worker     // Try to avoid racing condition in case callback is still on.
167*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
168*ec779b8eSAndroid Build Coastguard Worker     if (mUseAudioCallback) {
169*ec779b8eSAndroid Build Coastguard Worker         flushQueue(&mAudioQueue);
170*ec779b8eSAndroid Build Coastguard Worker         flushQueue(&mVideoQueue);
171*ec779b8eSAndroid Build Coastguard Worker     }
172*ec779b8eSAndroid Build Coastguard Worker     mWakeLock.clear();
173*ec779b8eSAndroid Build Coastguard Worker     mVideoScheduler.clear();
174*ec779b8eSAndroid Build Coastguard Worker     mNotify.clear();
175*ec779b8eSAndroid Build Coastguard Worker     mAudioSink.clear();
176*ec779b8eSAndroid Build Coastguard Worker }
177*ec779b8eSAndroid Build Coastguard Worker 
queueBuffer(bool audio,const sp<MediaCodecBuffer> & buffer,const sp<AMessage> & notifyConsumed)178*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::queueBuffer(
179*ec779b8eSAndroid Build Coastguard Worker         bool audio,
180*ec779b8eSAndroid Build Coastguard Worker         const sp<MediaCodecBuffer> &buffer,
181*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &notifyConsumed) {
182*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
183*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("queueGeneration", getQueueGeneration(audio));
184*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("audio", static_cast<int32_t>(audio));
185*ec779b8eSAndroid Build Coastguard Worker     msg->setObject("buffer", buffer);
186*ec779b8eSAndroid Build Coastguard Worker     msg->setMessage("notifyConsumed", notifyConsumed);
187*ec779b8eSAndroid Build Coastguard Worker     msg->post();
188*ec779b8eSAndroid Build Coastguard Worker }
189*ec779b8eSAndroid Build Coastguard Worker 
queueEOS(bool audio,status_t finalResult)190*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
191*ec779b8eSAndroid Build Coastguard Worker     CHECK_NE(finalResult, (status_t)OK);
192*ec779b8eSAndroid Build Coastguard Worker 
193*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatQueueEOS, this);
194*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("queueGeneration", getQueueGeneration(audio));
195*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("audio", static_cast<int32_t>(audio));
196*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("finalResult", finalResult);
197*ec779b8eSAndroid Build Coastguard Worker     msg->post();
198*ec779b8eSAndroid Build Coastguard Worker }
199*ec779b8eSAndroid Build Coastguard Worker 
setPlaybackSettings(const AudioPlaybackRate & rate)200*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) {
201*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
202*ec779b8eSAndroid Build Coastguard Worker     writeToAMessage(msg, rate);
203*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
204*ec779b8eSAndroid Build Coastguard Worker     status_t err = msg->postAndAwaitResponse(&response);
205*ec779b8eSAndroid Build Coastguard Worker     if (err == OK && response != NULL) {
206*ec779b8eSAndroid Build Coastguard Worker         CHECK(response->findInt32("err", &err));
207*ec779b8eSAndroid Build Coastguard Worker     }
208*ec779b8eSAndroid Build Coastguard Worker     return err;
209*ec779b8eSAndroid Build Coastguard Worker }
210*ec779b8eSAndroid Build Coastguard Worker 
onConfigPlayback(const AudioPlaybackRate & rate)211*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
212*ec779b8eSAndroid Build Coastguard Worker     if (rate.mSpeed == 0.f) {
213*ec779b8eSAndroid Build Coastguard Worker         onPause();
214*ec779b8eSAndroid Build Coastguard Worker         // don't call audiosink's setPlaybackRate if pausing, as pitch does not
215*ec779b8eSAndroid Build Coastguard Worker         // have to correspond to the any non-0 speed (e.g old speed). Keep
216*ec779b8eSAndroid Build Coastguard Worker         // settings nonetheless, using the old speed, in case audiosink changes.
217*ec779b8eSAndroid Build Coastguard Worker         AudioPlaybackRate newRate = rate;
218*ec779b8eSAndroid Build Coastguard Worker         newRate.mSpeed = mPlaybackSettings.mSpeed;
219*ec779b8eSAndroid Build Coastguard Worker         mPlaybackSettings = newRate;
220*ec779b8eSAndroid Build Coastguard Worker         return OK;
221*ec779b8eSAndroid Build Coastguard Worker     }
222*ec779b8eSAndroid Build Coastguard Worker 
223*ec779b8eSAndroid Build Coastguard Worker     if (mAudioSink != NULL && mAudioSink->ready()) {
224*ec779b8eSAndroid Build Coastguard Worker         status_t err = mAudioSink->setPlaybackRate(rate);
225*ec779b8eSAndroid Build Coastguard Worker         if (err != OK) {
226*ec779b8eSAndroid Build Coastguard Worker             return err;
227*ec779b8eSAndroid Build Coastguard Worker         }
228*ec779b8eSAndroid Build Coastguard Worker     }
229*ec779b8eSAndroid Build Coastguard Worker 
230*ec779b8eSAndroid Build Coastguard Worker     if (!mHasAudio && mHasVideo) {
231*ec779b8eSAndroid Build Coastguard Worker         mNeedVideoClearAnchor = true;
232*ec779b8eSAndroid Build Coastguard Worker     }
233*ec779b8eSAndroid Build Coastguard Worker     mPlaybackSettings = rate;
234*ec779b8eSAndroid Build Coastguard Worker     mPlaybackRate = rate.mSpeed;
235*ec779b8eSAndroid Build Coastguard Worker     mMediaClock->setPlaybackRate(mPlaybackRate);
236*ec779b8eSAndroid Build Coastguard Worker     return OK;
237*ec779b8eSAndroid Build Coastguard Worker }
238*ec779b8eSAndroid Build Coastguard Worker 
getPlaybackSettings(AudioPlaybackRate * rate)239*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
240*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
241*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
242*ec779b8eSAndroid Build Coastguard Worker     status_t err = msg->postAndAwaitResponse(&response);
243*ec779b8eSAndroid Build Coastguard Worker     if (err == OK && response != NULL) {
244*ec779b8eSAndroid Build Coastguard Worker         CHECK(response->findInt32("err", &err));
245*ec779b8eSAndroid Build Coastguard Worker         if (err == OK) {
246*ec779b8eSAndroid Build Coastguard Worker             readFromAMessage(response, rate);
247*ec779b8eSAndroid Build Coastguard Worker         }
248*ec779b8eSAndroid Build Coastguard Worker     }
249*ec779b8eSAndroid Build Coastguard Worker     return err;
250*ec779b8eSAndroid Build Coastguard Worker }
251*ec779b8eSAndroid Build Coastguard Worker 
onGetPlaybackSettings(AudioPlaybackRate * rate)252*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
253*ec779b8eSAndroid Build Coastguard Worker     if (mAudioSink != NULL && mAudioSink->ready()) {
254*ec779b8eSAndroid Build Coastguard Worker         status_t err = mAudioSink->getPlaybackRate(rate);
255*ec779b8eSAndroid Build Coastguard Worker         if (err == OK) {
256*ec779b8eSAndroid Build Coastguard Worker             if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) {
257*ec779b8eSAndroid Build Coastguard Worker                 ALOGW("correcting mismatch in internal/external playback rate");
258*ec779b8eSAndroid Build Coastguard Worker             }
259*ec779b8eSAndroid Build Coastguard Worker             // get playback settings used by audiosink, as it may be
260*ec779b8eSAndroid Build Coastguard Worker             // slightly off due to audiosink not taking small changes.
261*ec779b8eSAndroid Build Coastguard Worker             mPlaybackSettings = *rate;
262*ec779b8eSAndroid Build Coastguard Worker             if (mPaused) {
263*ec779b8eSAndroid Build Coastguard Worker                 rate->mSpeed = 0.f;
264*ec779b8eSAndroid Build Coastguard Worker             }
265*ec779b8eSAndroid Build Coastguard Worker         }
266*ec779b8eSAndroid Build Coastguard Worker         return err;
267*ec779b8eSAndroid Build Coastguard Worker     }
268*ec779b8eSAndroid Build Coastguard Worker     *rate = mPlaybackSettings;
269*ec779b8eSAndroid Build Coastguard Worker     return OK;
270*ec779b8eSAndroid Build Coastguard Worker }
271*ec779b8eSAndroid Build Coastguard Worker 
setSyncSettings(const AVSyncSettings & sync,float videoFpsHint)272*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
273*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
274*ec779b8eSAndroid Build Coastguard Worker     writeToAMessage(msg, sync, videoFpsHint);
275*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
276*ec779b8eSAndroid Build Coastguard Worker     status_t err = msg->postAndAwaitResponse(&response);
277*ec779b8eSAndroid Build Coastguard Worker     if (err == OK && response != NULL) {
278*ec779b8eSAndroid Build Coastguard Worker         CHECK(response->findInt32("err", &err));
279*ec779b8eSAndroid Build Coastguard Worker     }
280*ec779b8eSAndroid Build Coastguard Worker     return err;
281*ec779b8eSAndroid Build Coastguard Worker }
282*ec779b8eSAndroid Build Coastguard Worker 
onConfigSync(const AVSyncSettings & sync,float videoFpsHint __unused)283*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) {
284*ec779b8eSAndroid Build Coastguard Worker     if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
285*ec779b8eSAndroid Build Coastguard Worker         return BAD_VALUE;
286*ec779b8eSAndroid Build Coastguard Worker     }
287*ec779b8eSAndroid Build Coastguard Worker     // TODO: support sync sources
288*ec779b8eSAndroid Build Coastguard Worker     return INVALID_OPERATION;
289*ec779b8eSAndroid Build Coastguard Worker }
290*ec779b8eSAndroid Build Coastguard Worker 
getSyncSettings(AVSyncSettings * sync,float * videoFps)291*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
292*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
293*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
294*ec779b8eSAndroid Build Coastguard Worker     status_t err = msg->postAndAwaitResponse(&response);
295*ec779b8eSAndroid Build Coastguard Worker     if (err == OK && response != NULL) {
296*ec779b8eSAndroid Build Coastguard Worker         CHECK(response->findInt32("err", &err));
297*ec779b8eSAndroid Build Coastguard Worker         if (err == OK) {
298*ec779b8eSAndroid Build Coastguard Worker             readFromAMessage(response, sync, videoFps);
299*ec779b8eSAndroid Build Coastguard Worker         }
300*ec779b8eSAndroid Build Coastguard Worker     }
301*ec779b8eSAndroid Build Coastguard Worker     return err;
302*ec779b8eSAndroid Build Coastguard Worker }
303*ec779b8eSAndroid Build Coastguard Worker 
onGetSyncSettings(AVSyncSettings * sync,float * videoFps)304*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::onGetSyncSettings(
305*ec779b8eSAndroid Build Coastguard Worker         AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
306*ec779b8eSAndroid Build Coastguard Worker     *sync = mSyncSettings;
307*ec779b8eSAndroid Build Coastguard Worker     *videoFps = -1.f;
308*ec779b8eSAndroid Build Coastguard Worker     return OK;
309*ec779b8eSAndroid Build Coastguard Worker }
310*ec779b8eSAndroid Build Coastguard Worker 
flush(bool audio,bool notifyComplete)311*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) {
312*ec779b8eSAndroid Build Coastguard Worker     {
313*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
314*ec779b8eSAndroid Build Coastguard Worker         if (audio) {
315*ec779b8eSAndroid Build Coastguard Worker             mNotifyCompleteAudio |= notifyComplete;
316*ec779b8eSAndroid Build Coastguard Worker             clearAudioFirstAnchorTime_l();
317*ec779b8eSAndroid Build Coastguard Worker             ++mAudioQueueGeneration;
318*ec779b8eSAndroid Build Coastguard Worker             ++mAudioDrainGeneration;
319*ec779b8eSAndroid Build Coastguard Worker         } else {
320*ec779b8eSAndroid Build Coastguard Worker             mNotifyCompleteVideo |= notifyComplete;
321*ec779b8eSAndroid Build Coastguard Worker             ++mVideoQueueGeneration;
322*ec779b8eSAndroid Build Coastguard Worker             ++mVideoDrainGeneration;
323*ec779b8eSAndroid Build Coastguard Worker             mNextVideoTimeMediaUs = -1;
324*ec779b8eSAndroid Build Coastguard Worker         }
325*ec779b8eSAndroid Build Coastguard Worker 
326*ec779b8eSAndroid Build Coastguard Worker         mVideoLateByUs = 0;
327*ec779b8eSAndroid Build Coastguard Worker         mSyncQueues = false;
328*ec779b8eSAndroid Build Coastguard Worker     }
329*ec779b8eSAndroid Build Coastguard Worker 
330*ec779b8eSAndroid Build Coastguard Worker     // Wait until the current job in the message queue is done, to make sure
331*ec779b8eSAndroid Build Coastguard Worker     // buffer processing from the old generation is finished. After the current
332*ec779b8eSAndroid Build Coastguard Worker     // job is finished, access to buffers are protected by generation.
333*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock syncLock(mSyncLock);
334*ec779b8eSAndroid Build Coastguard Worker     int64_t syncCount = mSyncCount;
335*ec779b8eSAndroid Build Coastguard Worker     mSyncFlag.clear();
336*ec779b8eSAndroid Build Coastguard Worker 
337*ec779b8eSAndroid Build Coastguard Worker     // Make sure message queue is not empty after mSyncFlag is cleared.
338*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatFlush, this);
339*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("audio", static_cast<int32_t>(audio));
340*ec779b8eSAndroid Build Coastguard Worker     msg->post();
341*ec779b8eSAndroid Build Coastguard Worker 
342*ec779b8eSAndroid Build Coastguard Worker     int64_t uptimeMs = uptimeMillis();
343*ec779b8eSAndroid Build Coastguard Worker     while (mSyncCount == syncCount) {
344*ec779b8eSAndroid Build Coastguard Worker         (void)mSyncCondition.waitRelative(mSyncLock, ms2ns(1000));
345*ec779b8eSAndroid Build Coastguard Worker         if (uptimeMillis() - uptimeMs > 1000) {
346*ec779b8eSAndroid Build Coastguard Worker             ALOGW("flush(): no wake-up from sync point for 1s; stop waiting to "
347*ec779b8eSAndroid Build Coastguard Worker                   "prevent being stuck indefinitely.");
348*ec779b8eSAndroid Build Coastguard Worker             break;
349*ec779b8eSAndroid Build Coastguard Worker         }
350*ec779b8eSAndroid Build Coastguard Worker     }
351*ec779b8eSAndroid Build Coastguard Worker }
352*ec779b8eSAndroid Build Coastguard Worker 
signalTimeDiscontinuity()353*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::signalTimeDiscontinuity() {
354*ec779b8eSAndroid Build Coastguard Worker }
355*ec779b8eSAndroid Build Coastguard Worker 
signalDisableOffloadAudio()356*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::signalDisableOffloadAudio() {
357*ec779b8eSAndroid Build Coastguard Worker     (new AMessage(kWhatDisableOffloadAudio, this))->post();
358*ec779b8eSAndroid Build Coastguard Worker }
359*ec779b8eSAndroid Build Coastguard Worker 
signalEnableOffloadAudio()360*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::signalEnableOffloadAudio() {
361*ec779b8eSAndroid Build Coastguard Worker     (new AMessage(kWhatEnableOffloadAudio, this))->post();
362*ec779b8eSAndroid Build Coastguard Worker }
363*ec779b8eSAndroid Build Coastguard Worker 
pause()364*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::pause() {
365*ec779b8eSAndroid Build Coastguard Worker     (new AMessage(kWhatPause, this))->post();
366*ec779b8eSAndroid Build Coastguard Worker }
367*ec779b8eSAndroid Build Coastguard Worker 
resume()368*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::resume() {
369*ec779b8eSAndroid Build Coastguard Worker     (new AMessage(kWhatResume, this))->post();
370*ec779b8eSAndroid Build Coastguard Worker }
371*ec779b8eSAndroid Build Coastguard Worker 
setVideoFrameRate(float fps)372*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::setVideoFrameRate(float fps) {
373*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, this);
374*ec779b8eSAndroid Build Coastguard Worker     msg->setFloat("frame-rate", fps);
375*ec779b8eSAndroid Build Coastguard Worker     msg->post();
376*ec779b8eSAndroid Build Coastguard Worker }
377*ec779b8eSAndroid Build Coastguard Worker 
378*ec779b8eSAndroid Build Coastguard Worker // Called on any threads without mLock acquired.
getCurrentPosition(int64_t * mediaUs)379*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
380*ec779b8eSAndroid Build Coastguard Worker     status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
381*ec779b8eSAndroid Build Coastguard Worker     if (result == OK) {
382*ec779b8eSAndroid Build Coastguard Worker         return result;
383*ec779b8eSAndroid Build Coastguard Worker     }
384*ec779b8eSAndroid Build Coastguard Worker 
385*ec779b8eSAndroid Build Coastguard Worker     // MediaClock has not started yet. Try to start it if possible.
386*ec779b8eSAndroid Build Coastguard Worker     {
387*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
388*ec779b8eSAndroid Build Coastguard Worker         if (mAudioFirstAnchorTimeMediaUs == -1) {
389*ec779b8eSAndroid Build Coastguard Worker             return result;
390*ec779b8eSAndroid Build Coastguard Worker         }
391*ec779b8eSAndroid Build Coastguard Worker 
392*ec779b8eSAndroid Build Coastguard Worker         AudioTimestamp ts;
393*ec779b8eSAndroid Build Coastguard Worker         status_t res = mAudioSink->getTimestamp(ts);
394*ec779b8eSAndroid Build Coastguard Worker         if (res != OK) {
395*ec779b8eSAndroid Build Coastguard Worker             return result;
396*ec779b8eSAndroid Build Coastguard Worker         }
397*ec779b8eSAndroid Build Coastguard Worker 
398*ec779b8eSAndroid Build Coastguard Worker         // AudioSink has rendered some frames.
399*ec779b8eSAndroid Build Coastguard Worker         int64_t nowUs = ALooper::GetNowUs();
400*ec779b8eSAndroid Build Coastguard Worker         int64_t playedOutDurationUs = mAudioSink->getPlayedOutDurationUs(nowUs);
401*ec779b8eSAndroid Build Coastguard Worker         if (playedOutDurationUs == 0) {
402*ec779b8eSAndroid Build Coastguard Worker             *mediaUs = mAudioFirstAnchorTimeMediaUs;
403*ec779b8eSAndroid Build Coastguard Worker             return OK;
404*ec779b8eSAndroid Build Coastguard Worker         }
405*ec779b8eSAndroid Build Coastguard Worker         int64_t nowMediaUs = playedOutDurationUs + mAudioFirstAnchorTimeMediaUs;
406*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
407*ec779b8eSAndroid Build Coastguard Worker     }
408*ec779b8eSAndroid Build Coastguard Worker 
409*ec779b8eSAndroid Build Coastguard Worker     return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
410*ec779b8eSAndroid Build Coastguard Worker }
411*ec779b8eSAndroid Build Coastguard Worker 
clearAudioFirstAnchorTime_l()412*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::clearAudioFirstAnchorTime_l() {
413*ec779b8eSAndroid Build Coastguard Worker     mAudioFirstAnchorTimeMediaUs = -1;
414*ec779b8eSAndroid Build Coastguard Worker     mMediaClock->setStartingTimeMedia(-1);
415*ec779b8eSAndroid Build Coastguard Worker }
416*ec779b8eSAndroid Build Coastguard Worker 
setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs)417*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs) {
418*ec779b8eSAndroid Build Coastguard Worker     if (mAudioFirstAnchorTimeMediaUs == -1) {
419*ec779b8eSAndroid Build Coastguard Worker         mAudioFirstAnchorTimeMediaUs = mediaUs;
420*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->setStartingTimeMedia(mediaUs);
421*ec779b8eSAndroid Build Coastguard Worker     }
422*ec779b8eSAndroid Build Coastguard Worker }
423*ec779b8eSAndroid Build Coastguard Worker 
424*ec779b8eSAndroid Build Coastguard Worker // Called on renderer looper.
clearAnchorTime()425*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::clearAnchorTime() {
426*ec779b8eSAndroid Build Coastguard Worker     mMediaClock->clearAnchor();
427*ec779b8eSAndroid Build Coastguard Worker     mAudioAnchorTimeMediaUs = -1;
428*ec779b8eSAndroid Build Coastguard Worker     mAnchorTimeMediaUs = -1;
429*ec779b8eSAndroid Build Coastguard Worker     mAnchorNumFramesWritten = -1;
430*ec779b8eSAndroid Build Coastguard Worker }
431*ec779b8eSAndroid Build Coastguard Worker 
setVideoLateByUs(int64_t lateUs)432*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) {
433*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
434*ec779b8eSAndroid Build Coastguard Worker     mVideoLateByUs = lateUs;
435*ec779b8eSAndroid Build Coastguard Worker }
436*ec779b8eSAndroid Build Coastguard Worker 
getVideoLateByUs()437*ec779b8eSAndroid Build Coastguard Worker int64_t NuPlayer::Renderer::getVideoLateByUs() {
438*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
439*ec779b8eSAndroid Build Coastguard Worker     return mVideoLateByUs;
440*ec779b8eSAndroid Build Coastguard Worker }
441*ec779b8eSAndroid Build Coastguard Worker 
openAudioSink(const sp<AMessage> & format,bool offloadOnly,bool hasVideo,uint32_t flags,bool * isOffloaded,bool isStreaming)442*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::openAudioSink(
443*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &format,
444*ec779b8eSAndroid Build Coastguard Worker         bool offloadOnly,
445*ec779b8eSAndroid Build Coastguard Worker         bool hasVideo,
446*ec779b8eSAndroid Build Coastguard Worker         uint32_t flags,
447*ec779b8eSAndroid Build Coastguard Worker         bool *isOffloaded,
448*ec779b8eSAndroid Build Coastguard Worker         bool isStreaming) {
449*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
450*ec779b8eSAndroid Build Coastguard Worker     msg->setMessage("format", format);
451*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("offload-only", offloadOnly);
452*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("has-video", hasVideo);
453*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("flags", flags);
454*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("isStreaming", isStreaming);
455*ec779b8eSAndroid Build Coastguard Worker 
456*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
457*ec779b8eSAndroid Build Coastguard Worker     status_t postStatus = msg->postAndAwaitResponse(&response);
458*ec779b8eSAndroid Build Coastguard Worker 
459*ec779b8eSAndroid Build Coastguard Worker     int32_t err;
460*ec779b8eSAndroid Build Coastguard Worker     if (postStatus != OK || response.get() == nullptr || !response->findInt32("err", &err)) {
461*ec779b8eSAndroid Build Coastguard Worker         err = INVALID_OPERATION;
462*ec779b8eSAndroid Build Coastguard Worker     } else if (err == OK && isOffloaded != NULL) {
463*ec779b8eSAndroid Build Coastguard Worker         int32_t offload;
464*ec779b8eSAndroid Build Coastguard Worker         CHECK(response->findInt32("offload", &offload));
465*ec779b8eSAndroid Build Coastguard Worker         *isOffloaded = (offload != 0);
466*ec779b8eSAndroid Build Coastguard Worker     }
467*ec779b8eSAndroid Build Coastguard Worker     return err;
468*ec779b8eSAndroid Build Coastguard Worker }
469*ec779b8eSAndroid Build Coastguard Worker 
closeAudioSink()470*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::closeAudioSink() {
471*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, this);
472*ec779b8eSAndroid Build Coastguard Worker 
473*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> response;
474*ec779b8eSAndroid Build Coastguard Worker     msg->postAndAwaitResponse(&response);
475*ec779b8eSAndroid Build Coastguard Worker }
476*ec779b8eSAndroid Build Coastguard Worker 
dump(AString & logString)477*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::dump(AString& logString) {
478*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
479*ec779b8eSAndroid Build Coastguard Worker     logString.append("paused(");
480*ec779b8eSAndroid Build Coastguard Worker     logString.append(mPaused);
481*ec779b8eSAndroid Build Coastguard Worker     logString.append("), offloading(");
482*ec779b8eSAndroid Build Coastguard Worker     logString.append(offloadingAudio());
483*ec779b8eSAndroid Build Coastguard Worker     logString.append("), wakelock(acquired=");
484*ec779b8eSAndroid Build Coastguard Worker     mWakelockAcquireEvent.dump(logString);
485*ec779b8eSAndroid Build Coastguard Worker     logString.append(", timeout=");
486*ec779b8eSAndroid Build Coastguard Worker     mWakelockTimeoutEvent.dump(logString);
487*ec779b8eSAndroid Build Coastguard Worker     logString.append(", release=");
488*ec779b8eSAndroid Build Coastguard Worker     mWakelockReleaseEvent.dump(logString);
489*ec779b8eSAndroid Build Coastguard Worker     logString.append(", cancel=");
490*ec779b8eSAndroid Build Coastguard Worker     mWakelockCancelEvent.dump(logString);
491*ec779b8eSAndroid Build Coastguard Worker     logString.append(")");
492*ec779b8eSAndroid Build Coastguard Worker }
493*ec779b8eSAndroid Build Coastguard Worker 
changeAudioFormat(const sp<AMessage> & format,bool offloadOnly,bool hasVideo,uint32_t flags,bool isStreaming,const sp<AMessage> & notify)494*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::changeAudioFormat(
495*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &format,
496*ec779b8eSAndroid Build Coastguard Worker         bool offloadOnly,
497*ec779b8eSAndroid Build Coastguard Worker         bool hasVideo,
498*ec779b8eSAndroid Build Coastguard Worker         uint32_t flags,
499*ec779b8eSAndroid Build Coastguard Worker         bool isStreaming,
500*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &notify) {
501*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> meta = new AMessage;
502*ec779b8eSAndroid Build Coastguard Worker     meta->setMessage("format", format);
503*ec779b8eSAndroid Build Coastguard Worker     meta->setInt32("offload-only", offloadOnly);
504*ec779b8eSAndroid Build Coastguard Worker     meta->setInt32("has-video", hasVideo);
505*ec779b8eSAndroid Build Coastguard Worker     meta->setInt32("flags", flags);
506*ec779b8eSAndroid Build Coastguard Worker     meta->setInt32("isStreaming", isStreaming);
507*ec779b8eSAndroid Build Coastguard Worker 
508*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatChangeAudioFormat, this);
509*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("queueGeneration", getQueueGeneration(true /* audio */));
510*ec779b8eSAndroid Build Coastguard Worker     msg->setMessage("notify", notify);
511*ec779b8eSAndroid Build Coastguard Worker     msg->setMessage("meta", meta);
512*ec779b8eSAndroid Build Coastguard Worker     msg->post();
513*ec779b8eSAndroid Build Coastguard Worker }
514*ec779b8eSAndroid Build Coastguard Worker 
onMessageReceived(const sp<AMessage> & msg)515*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
516*ec779b8eSAndroid Build Coastguard Worker     switch (msg->what()) {
517*ec779b8eSAndroid Build Coastguard Worker         case kWhatOpenAudioSink:
518*ec779b8eSAndroid Build Coastguard Worker         {
519*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> format;
520*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findMessage("format", &format));
521*ec779b8eSAndroid Build Coastguard Worker 
522*ec779b8eSAndroid Build Coastguard Worker             int32_t offloadOnly;
523*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("offload-only", &offloadOnly));
524*ec779b8eSAndroid Build Coastguard Worker 
525*ec779b8eSAndroid Build Coastguard Worker             int32_t hasVideo;
526*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("has-video", &hasVideo));
527*ec779b8eSAndroid Build Coastguard Worker 
528*ec779b8eSAndroid Build Coastguard Worker             uint32_t flags;
529*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("flags", (int32_t *)&flags));
530*ec779b8eSAndroid Build Coastguard Worker 
531*ec779b8eSAndroid Build Coastguard Worker             uint32_t isStreaming;
532*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("isStreaming", (int32_t *)&isStreaming));
533*ec779b8eSAndroid Build Coastguard Worker 
534*ec779b8eSAndroid Build Coastguard Worker             status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
535*ec779b8eSAndroid Build Coastguard Worker 
536*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
537*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("err", err);
538*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("offload", offloadingAudio());
539*ec779b8eSAndroid Build Coastguard Worker 
540*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
541*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
542*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
543*ec779b8eSAndroid Build Coastguard Worker 
544*ec779b8eSAndroid Build Coastguard Worker             break;
545*ec779b8eSAndroid Build Coastguard Worker         }
546*ec779b8eSAndroid Build Coastguard Worker 
547*ec779b8eSAndroid Build Coastguard Worker         case kWhatCloseAudioSink:
548*ec779b8eSAndroid Build Coastguard Worker         {
549*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
550*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
551*ec779b8eSAndroid Build Coastguard Worker 
552*ec779b8eSAndroid Build Coastguard Worker             onCloseAudioSink();
553*ec779b8eSAndroid Build Coastguard Worker 
554*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
555*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
556*ec779b8eSAndroid Build Coastguard Worker             break;
557*ec779b8eSAndroid Build Coastguard Worker         }
558*ec779b8eSAndroid Build Coastguard Worker 
559*ec779b8eSAndroid Build Coastguard Worker         case kWhatStopAudioSink:
560*ec779b8eSAndroid Build Coastguard Worker         {
561*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->stop();
562*ec779b8eSAndroid Build Coastguard Worker             break;
563*ec779b8eSAndroid Build Coastguard Worker         }
564*ec779b8eSAndroid Build Coastguard Worker 
565*ec779b8eSAndroid Build Coastguard Worker         case kWhatChangeAudioFormat:
566*ec779b8eSAndroid Build Coastguard Worker         {
567*ec779b8eSAndroid Build Coastguard Worker             int32_t queueGeneration;
568*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("queueGeneration", &queueGeneration));
569*ec779b8eSAndroid Build Coastguard Worker 
570*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> notify;
571*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findMessage("notify", &notify));
572*ec779b8eSAndroid Build Coastguard Worker 
573*ec779b8eSAndroid Build Coastguard Worker             if (offloadingAudio()) {
574*ec779b8eSAndroid Build Coastguard Worker                 ALOGW("changeAudioFormat should NOT be called in offload mode");
575*ec779b8eSAndroid Build Coastguard Worker                 notify->setInt32("err", INVALID_OPERATION);
576*ec779b8eSAndroid Build Coastguard Worker                 notify->post();
577*ec779b8eSAndroid Build Coastguard Worker                 break;
578*ec779b8eSAndroid Build Coastguard Worker             }
579*ec779b8eSAndroid Build Coastguard Worker 
580*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> meta;
581*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findMessage("meta", &meta));
582*ec779b8eSAndroid Build Coastguard Worker 
583*ec779b8eSAndroid Build Coastguard Worker             if (queueGeneration != getQueueGeneration(true /* audio */)
584*ec779b8eSAndroid Build Coastguard Worker                     || mAudioQueue.empty()) {
585*ec779b8eSAndroid Build Coastguard Worker                 onChangeAudioFormat(meta, notify);
586*ec779b8eSAndroid Build Coastguard Worker                 break;
587*ec779b8eSAndroid Build Coastguard Worker             }
588*ec779b8eSAndroid Build Coastguard Worker 
589*ec779b8eSAndroid Build Coastguard Worker             QueueEntry entry;
590*ec779b8eSAndroid Build Coastguard Worker             entry.mNotifyConsumed = notify;
591*ec779b8eSAndroid Build Coastguard Worker             entry.mMeta = meta;
592*ec779b8eSAndroid Build Coastguard Worker 
593*ec779b8eSAndroid Build Coastguard Worker             Mutex::Autolock autoLock(mLock);
594*ec779b8eSAndroid Build Coastguard Worker             mAudioQueue.push_back(entry);
595*ec779b8eSAndroid Build Coastguard Worker             postDrainAudioQueue_l();
596*ec779b8eSAndroid Build Coastguard Worker 
597*ec779b8eSAndroid Build Coastguard Worker             break;
598*ec779b8eSAndroid Build Coastguard Worker         }
599*ec779b8eSAndroid Build Coastguard Worker 
600*ec779b8eSAndroid Build Coastguard Worker         case kWhatDrainAudioQueue:
601*ec779b8eSAndroid Build Coastguard Worker         {
602*ec779b8eSAndroid Build Coastguard Worker             mDrainAudioQueuePending = false;
603*ec779b8eSAndroid Build Coastguard Worker 
604*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
605*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("drainGeneration", &generation));
606*ec779b8eSAndroid Build Coastguard Worker             if (generation != getDrainGeneration(true /* audio */)) {
607*ec779b8eSAndroid Build Coastguard Worker                 break;
608*ec779b8eSAndroid Build Coastguard Worker             }
609*ec779b8eSAndroid Build Coastguard Worker 
610*ec779b8eSAndroid Build Coastguard Worker             if (onDrainAudioQueue()) {
611*ec779b8eSAndroid Build Coastguard Worker                 uint32_t numFramesPlayed;
612*ec779b8eSAndroid Build Coastguard Worker                 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
613*ec779b8eSAndroid Build Coastguard Worker                          (status_t)OK);
614*ec779b8eSAndroid Build Coastguard Worker 
615*ec779b8eSAndroid Build Coastguard Worker                 // Handle AudioTrack race when start is immediately called after flush.
616*ec779b8eSAndroid Build Coastguard Worker                 uint32_t numFramesPendingPlayout =
617*ec779b8eSAndroid Build Coastguard Worker                     (mNumFramesWritten > numFramesPlayed ?
618*ec779b8eSAndroid Build Coastguard Worker                         mNumFramesWritten - numFramesPlayed : 0);
619*ec779b8eSAndroid Build Coastguard Worker 
620*ec779b8eSAndroid Build Coastguard Worker                 // This is how long the audio sink will have data to
621*ec779b8eSAndroid Build Coastguard Worker                 // play back.
622*ec779b8eSAndroid Build Coastguard Worker                 int64_t delayUs =
623*ec779b8eSAndroid Build Coastguard Worker                     mAudioSink->msecsPerFrame()
624*ec779b8eSAndroid Build Coastguard Worker                         * numFramesPendingPlayout * 1000LL;
625*ec779b8eSAndroid Build Coastguard Worker                 if (mPlaybackRate > 1.0f) {
626*ec779b8eSAndroid Build Coastguard Worker                     delayUs /= mPlaybackRate;
627*ec779b8eSAndroid Build Coastguard Worker                 }
628*ec779b8eSAndroid Build Coastguard Worker 
629*ec779b8eSAndroid Build Coastguard Worker                 // Let's give it more data after about half that time
630*ec779b8eSAndroid Build Coastguard Worker                 // has elapsed.
631*ec779b8eSAndroid Build Coastguard Worker                 delayUs /= 2;
632*ec779b8eSAndroid Build Coastguard Worker                 // check the buffer size to estimate maximum delay permitted.
633*ec779b8eSAndroid Build Coastguard Worker                 const int64_t maxDrainDelayUs = std::max(
634*ec779b8eSAndroid Build Coastguard Worker                         mAudioSink->getBufferDurationInUs(), (int64_t)500000 /* half second */);
635*ec779b8eSAndroid Build Coastguard Worker                 ALOGD_IF(delayUs > maxDrainDelayUs, "postDrainAudioQueue long delay: %lld > %lld",
636*ec779b8eSAndroid Build Coastguard Worker                         (long long)delayUs, (long long)maxDrainDelayUs);
637*ec779b8eSAndroid Build Coastguard Worker                 Mutex::Autolock autoLock(mLock);
638*ec779b8eSAndroid Build Coastguard Worker                 postDrainAudioQueue_l(delayUs);
639*ec779b8eSAndroid Build Coastguard Worker             }
640*ec779b8eSAndroid Build Coastguard Worker             break;
641*ec779b8eSAndroid Build Coastguard Worker         }
642*ec779b8eSAndroid Build Coastguard Worker 
643*ec779b8eSAndroid Build Coastguard Worker         case kWhatDrainVideoQueue:
644*ec779b8eSAndroid Build Coastguard Worker         {
645*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
646*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("drainGeneration", &generation));
647*ec779b8eSAndroid Build Coastguard Worker             if (generation != getDrainGeneration(false /* audio */)) {
648*ec779b8eSAndroid Build Coastguard Worker                 break;
649*ec779b8eSAndroid Build Coastguard Worker             }
650*ec779b8eSAndroid Build Coastguard Worker 
651*ec779b8eSAndroid Build Coastguard Worker             mDrainVideoQueuePending = false;
652*ec779b8eSAndroid Build Coastguard Worker 
653*ec779b8eSAndroid Build Coastguard Worker             onDrainVideoQueue();
654*ec779b8eSAndroid Build Coastguard Worker 
655*ec779b8eSAndroid Build Coastguard Worker             postDrainVideoQueue();
656*ec779b8eSAndroid Build Coastguard Worker             break;
657*ec779b8eSAndroid Build Coastguard Worker         }
658*ec779b8eSAndroid Build Coastguard Worker 
659*ec779b8eSAndroid Build Coastguard Worker         case kWhatPostDrainVideoQueue:
660*ec779b8eSAndroid Build Coastguard Worker         {
661*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
662*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("drainGeneration", &generation));
663*ec779b8eSAndroid Build Coastguard Worker             if (generation != getDrainGeneration(false /* audio */)) {
664*ec779b8eSAndroid Build Coastguard Worker                 break;
665*ec779b8eSAndroid Build Coastguard Worker             }
666*ec779b8eSAndroid Build Coastguard Worker 
667*ec779b8eSAndroid Build Coastguard Worker             mDrainVideoQueuePending = false;
668*ec779b8eSAndroid Build Coastguard Worker             postDrainVideoQueue();
669*ec779b8eSAndroid Build Coastguard Worker             break;
670*ec779b8eSAndroid Build Coastguard Worker         }
671*ec779b8eSAndroid Build Coastguard Worker 
672*ec779b8eSAndroid Build Coastguard Worker         case kWhatQueueBuffer:
673*ec779b8eSAndroid Build Coastguard Worker         {
674*ec779b8eSAndroid Build Coastguard Worker             onQueueBuffer(msg);
675*ec779b8eSAndroid Build Coastguard Worker             break;
676*ec779b8eSAndroid Build Coastguard Worker         }
677*ec779b8eSAndroid Build Coastguard Worker 
678*ec779b8eSAndroid Build Coastguard Worker         case kWhatQueueEOS:
679*ec779b8eSAndroid Build Coastguard Worker         {
680*ec779b8eSAndroid Build Coastguard Worker             onQueueEOS(msg);
681*ec779b8eSAndroid Build Coastguard Worker             break;
682*ec779b8eSAndroid Build Coastguard Worker         }
683*ec779b8eSAndroid Build Coastguard Worker 
684*ec779b8eSAndroid Build Coastguard Worker         case kWhatEOS:
685*ec779b8eSAndroid Build Coastguard Worker         {
686*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
687*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("audioEOSGeneration", &generation));
688*ec779b8eSAndroid Build Coastguard Worker             if (generation != mAudioEOSGeneration) {
689*ec779b8eSAndroid Build Coastguard Worker                 break;
690*ec779b8eSAndroid Build Coastguard Worker             }
691*ec779b8eSAndroid Build Coastguard Worker             status_t finalResult;
692*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("finalResult", &finalResult));
693*ec779b8eSAndroid Build Coastguard Worker             notifyEOS(true /* audio */, finalResult);
694*ec779b8eSAndroid Build Coastguard Worker             break;
695*ec779b8eSAndroid Build Coastguard Worker         }
696*ec779b8eSAndroid Build Coastguard Worker 
697*ec779b8eSAndroid Build Coastguard Worker         case kWhatConfigPlayback:
698*ec779b8eSAndroid Build Coastguard Worker         {
699*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
700*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
701*ec779b8eSAndroid Build Coastguard Worker             AudioPlaybackRate rate;
702*ec779b8eSAndroid Build Coastguard Worker             readFromAMessage(msg, &rate);
703*ec779b8eSAndroid Build Coastguard Worker             status_t err = onConfigPlayback(rate);
704*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
705*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("err", err);
706*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
707*ec779b8eSAndroid Build Coastguard Worker             break;
708*ec779b8eSAndroid Build Coastguard Worker         }
709*ec779b8eSAndroid Build Coastguard Worker 
710*ec779b8eSAndroid Build Coastguard Worker         case kWhatGetPlaybackSettings:
711*ec779b8eSAndroid Build Coastguard Worker         {
712*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
713*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
714*ec779b8eSAndroid Build Coastguard Worker             AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
715*ec779b8eSAndroid Build Coastguard Worker             status_t err = onGetPlaybackSettings(&rate);
716*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
717*ec779b8eSAndroid Build Coastguard Worker             if (err == OK) {
718*ec779b8eSAndroid Build Coastguard Worker                 writeToAMessage(response, rate);
719*ec779b8eSAndroid Build Coastguard Worker             }
720*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("err", err);
721*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
722*ec779b8eSAndroid Build Coastguard Worker             break;
723*ec779b8eSAndroid Build Coastguard Worker         }
724*ec779b8eSAndroid Build Coastguard Worker 
725*ec779b8eSAndroid Build Coastguard Worker         case kWhatConfigSync:
726*ec779b8eSAndroid Build Coastguard Worker         {
727*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
728*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
729*ec779b8eSAndroid Build Coastguard Worker             AVSyncSettings sync;
730*ec779b8eSAndroid Build Coastguard Worker             float videoFpsHint;
731*ec779b8eSAndroid Build Coastguard Worker             readFromAMessage(msg, &sync, &videoFpsHint);
732*ec779b8eSAndroid Build Coastguard Worker             status_t err = onConfigSync(sync, videoFpsHint);
733*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
734*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("err", err);
735*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
736*ec779b8eSAndroid Build Coastguard Worker             break;
737*ec779b8eSAndroid Build Coastguard Worker         }
738*ec779b8eSAndroid Build Coastguard Worker 
739*ec779b8eSAndroid Build Coastguard Worker         case kWhatGetSyncSettings:
740*ec779b8eSAndroid Build Coastguard Worker         {
741*ec779b8eSAndroid Build Coastguard Worker             sp<AReplyToken> replyID;
742*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->senderAwaitsResponse(&replyID));
743*ec779b8eSAndroid Build Coastguard Worker 
744*ec779b8eSAndroid Build Coastguard Worker             ALOGV("kWhatGetSyncSettings");
745*ec779b8eSAndroid Build Coastguard Worker             AVSyncSettings sync;
746*ec779b8eSAndroid Build Coastguard Worker             float videoFps = -1.f;
747*ec779b8eSAndroid Build Coastguard Worker             status_t err = onGetSyncSettings(&sync, &videoFps);
748*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> response = new AMessage;
749*ec779b8eSAndroid Build Coastguard Worker             if (err == OK) {
750*ec779b8eSAndroid Build Coastguard Worker                 writeToAMessage(response, sync, videoFps);
751*ec779b8eSAndroid Build Coastguard Worker             }
752*ec779b8eSAndroid Build Coastguard Worker             response->setInt32("err", err);
753*ec779b8eSAndroid Build Coastguard Worker             response->postReply(replyID);
754*ec779b8eSAndroid Build Coastguard Worker             break;
755*ec779b8eSAndroid Build Coastguard Worker         }
756*ec779b8eSAndroid Build Coastguard Worker 
757*ec779b8eSAndroid Build Coastguard Worker         case kWhatFlush:
758*ec779b8eSAndroid Build Coastguard Worker         {
759*ec779b8eSAndroid Build Coastguard Worker             onFlush(msg);
760*ec779b8eSAndroid Build Coastguard Worker             break;
761*ec779b8eSAndroid Build Coastguard Worker         }
762*ec779b8eSAndroid Build Coastguard Worker 
763*ec779b8eSAndroid Build Coastguard Worker         case kWhatDisableOffloadAudio:
764*ec779b8eSAndroid Build Coastguard Worker         {
765*ec779b8eSAndroid Build Coastguard Worker             onDisableOffloadAudio();
766*ec779b8eSAndroid Build Coastguard Worker             break;
767*ec779b8eSAndroid Build Coastguard Worker         }
768*ec779b8eSAndroid Build Coastguard Worker 
769*ec779b8eSAndroid Build Coastguard Worker         case kWhatEnableOffloadAudio:
770*ec779b8eSAndroid Build Coastguard Worker         {
771*ec779b8eSAndroid Build Coastguard Worker             onEnableOffloadAudio();
772*ec779b8eSAndroid Build Coastguard Worker             break;
773*ec779b8eSAndroid Build Coastguard Worker         }
774*ec779b8eSAndroid Build Coastguard Worker 
775*ec779b8eSAndroid Build Coastguard Worker         case kWhatPause:
776*ec779b8eSAndroid Build Coastguard Worker         {
777*ec779b8eSAndroid Build Coastguard Worker             onPause();
778*ec779b8eSAndroid Build Coastguard Worker             break;
779*ec779b8eSAndroid Build Coastguard Worker         }
780*ec779b8eSAndroid Build Coastguard Worker 
781*ec779b8eSAndroid Build Coastguard Worker         case kWhatResume:
782*ec779b8eSAndroid Build Coastguard Worker         {
783*ec779b8eSAndroid Build Coastguard Worker             onResume();
784*ec779b8eSAndroid Build Coastguard Worker             break;
785*ec779b8eSAndroid Build Coastguard Worker         }
786*ec779b8eSAndroid Build Coastguard Worker 
787*ec779b8eSAndroid Build Coastguard Worker         case kWhatSetVideoFrameRate:
788*ec779b8eSAndroid Build Coastguard Worker         {
789*ec779b8eSAndroid Build Coastguard Worker             float fps;
790*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findFloat("frame-rate", &fps));
791*ec779b8eSAndroid Build Coastguard Worker             onSetVideoFrameRate(fps);
792*ec779b8eSAndroid Build Coastguard Worker             break;
793*ec779b8eSAndroid Build Coastguard Worker         }
794*ec779b8eSAndroid Build Coastguard Worker 
795*ec779b8eSAndroid Build Coastguard Worker         case kWhatAudioTearDown:
796*ec779b8eSAndroid Build Coastguard Worker         {
797*ec779b8eSAndroid Build Coastguard Worker             int32_t reason;
798*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("reason", &reason));
799*ec779b8eSAndroid Build Coastguard Worker 
800*ec779b8eSAndroid Build Coastguard Worker             onAudioTearDown((AudioTearDownReason)reason);
801*ec779b8eSAndroid Build Coastguard Worker             break;
802*ec779b8eSAndroid Build Coastguard Worker         }
803*ec779b8eSAndroid Build Coastguard Worker 
804*ec779b8eSAndroid Build Coastguard Worker         case kWhatAudioOffloadPauseTimeout:
805*ec779b8eSAndroid Build Coastguard Worker         {
806*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
807*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("drainGeneration", &generation));
808*ec779b8eSAndroid Build Coastguard Worker             mWakelockTimeoutEvent.updateValues(
809*ec779b8eSAndroid Build Coastguard Worker                     uptimeMillis(),
810*ec779b8eSAndroid Build Coastguard Worker                     generation,
811*ec779b8eSAndroid Build Coastguard Worker                     mAudioOffloadPauseTimeoutGeneration);
812*ec779b8eSAndroid Build Coastguard Worker             if (generation != mAudioOffloadPauseTimeoutGeneration) {
813*ec779b8eSAndroid Build Coastguard Worker                 break;
814*ec779b8eSAndroid Build Coastguard Worker             }
815*ec779b8eSAndroid Build Coastguard Worker             ALOGV("Audio Offload tear down due to pause timeout.");
816*ec779b8eSAndroid Build Coastguard Worker             onAudioTearDown(kDueToTimeout);
817*ec779b8eSAndroid Build Coastguard Worker             sp<AMessage> newMsg = new AMessage(kWhatReleaseWakeLock, this);
818*ec779b8eSAndroid Build Coastguard Worker             newMsg->setInt32("drainGeneration", generation);
819*ec779b8eSAndroid Build Coastguard Worker             newMsg->post(kWakelockReleaseDelayUs);
820*ec779b8eSAndroid Build Coastguard Worker             break;
821*ec779b8eSAndroid Build Coastguard Worker         }
822*ec779b8eSAndroid Build Coastguard Worker 
823*ec779b8eSAndroid Build Coastguard Worker         case kWhatReleaseWakeLock:
824*ec779b8eSAndroid Build Coastguard Worker         {
825*ec779b8eSAndroid Build Coastguard Worker             int32_t generation;
826*ec779b8eSAndroid Build Coastguard Worker             CHECK(msg->findInt32("drainGeneration", &generation));
827*ec779b8eSAndroid Build Coastguard Worker             mWakelockReleaseEvent.updateValues(
828*ec779b8eSAndroid Build Coastguard Worker                 uptimeMillis(),
829*ec779b8eSAndroid Build Coastguard Worker                 generation,
830*ec779b8eSAndroid Build Coastguard Worker                 mAudioOffloadPauseTimeoutGeneration);
831*ec779b8eSAndroid Build Coastguard Worker             if (generation != mAudioOffloadPauseTimeoutGeneration) {
832*ec779b8eSAndroid Build Coastguard Worker                 break;
833*ec779b8eSAndroid Build Coastguard Worker             }
834*ec779b8eSAndroid Build Coastguard Worker             ALOGV("releasing audio offload pause wakelock.");
835*ec779b8eSAndroid Build Coastguard Worker             mWakeLock->release();
836*ec779b8eSAndroid Build Coastguard Worker             break;
837*ec779b8eSAndroid Build Coastguard Worker         }
838*ec779b8eSAndroid Build Coastguard Worker 
839*ec779b8eSAndroid Build Coastguard Worker         default:
840*ec779b8eSAndroid Build Coastguard Worker             TRESPASS();
841*ec779b8eSAndroid Build Coastguard Worker             break;
842*ec779b8eSAndroid Build Coastguard Worker     }
843*ec779b8eSAndroid Build Coastguard Worker     if (!mSyncFlag.test_and_set()) {
844*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock syncLock(mSyncLock);
845*ec779b8eSAndroid Build Coastguard Worker         ++mSyncCount;
846*ec779b8eSAndroid Build Coastguard Worker         mSyncCondition.broadcast();
847*ec779b8eSAndroid Build Coastguard Worker     }
848*ec779b8eSAndroid Build Coastguard Worker }
849*ec779b8eSAndroid Build Coastguard Worker 
postDrainAudioQueue_l(int64_t delayUs)850*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
851*ec779b8eSAndroid Build Coastguard Worker     if (mDrainAudioQueuePending || mSyncQueues || mUseAudioCallback) {
852*ec779b8eSAndroid Build Coastguard Worker         return;
853*ec779b8eSAndroid Build Coastguard Worker     }
854*ec779b8eSAndroid Build Coastguard Worker 
855*ec779b8eSAndroid Build Coastguard Worker     if (mAudioQueue.empty()) {
856*ec779b8eSAndroid Build Coastguard Worker         return;
857*ec779b8eSAndroid Build Coastguard Worker     }
858*ec779b8eSAndroid Build Coastguard Worker 
859*ec779b8eSAndroid Build Coastguard Worker     // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data.
860*ec779b8eSAndroid Build Coastguard Worker     if (mPaused) {
861*ec779b8eSAndroid Build Coastguard Worker         const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs();
862*ec779b8eSAndroid Build Coastguard Worker         if (diffUs > delayUs) {
863*ec779b8eSAndroid Build Coastguard Worker             delayUs = diffUs;
864*ec779b8eSAndroid Build Coastguard Worker         }
865*ec779b8eSAndroid Build Coastguard Worker     }
866*ec779b8eSAndroid Build Coastguard Worker 
867*ec779b8eSAndroid Build Coastguard Worker     mDrainAudioQueuePending = true;
868*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
869*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("drainGeneration", mAudioDrainGeneration);
870*ec779b8eSAndroid Build Coastguard Worker     msg->post(delayUs);
871*ec779b8eSAndroid Build Coastguard Worker }
872*ec779b8eSAndroid Build Coastguard Worker 
prepareForMediaRenderingStart_l()873*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::prepareForMediaRenderingStart_l() {
874*ec779b8eSAndroid Build Coastguard Worker     mAudioRenderingStartGeneration = mAudioDrainGeneration;
875*ec779b8eSAndroid Build Coastguard Worker     mVideoRenderingStartGeneration = mVideoDrainGeneration;
876*ec779b8eSAndroid Build Coastguard Worker     mRenderingDataDelivered = false;
877*ec779b8eSAndroid Build Coastguard Worker }
878*ec779b8eSAndroid Build Coastguard Worker 
notifyIfMediaRenderingStarted_l()879*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyIfMediaRenderingStarted_l() {
880*ec779b8eSAndroid Build Coastguard Worker     if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
881*ec779b8eSAndroid Build Coastguard Worker         mAudioRenderingStartGeneration == mAudioDrainGeneration) {
882*ec779b8eSAndroid Build Coastguard Worker         mRenderingDataDelivered = true;
883*ec779b8eSAndroid Build Coastguard Worker         if (mPaused) {
884*ec779b8eSAndroid Build Coastguard Worker             return;
885*ec779b8eSAndroid Build Coastguard Worker         }
886*ec779b8eSAndroid Build Coastguard Worker         mVideoRenderingStartGeneration = -1;
887*ec779b8eSAndroid Build Coastguard Worker         mAudioRenderingStartGeneration = -1;
888*ec779b8eSAndroid Build Coastguard Worker 
889*ec779b8eSAndroid Build Coastguard Worker         sp<AMessage> notify = mNotify->dup();
890*ec779b8eSAndroid Build Coastguard Worker         notify->setInt32("what", kWhatMediaRenderingStart);
891*ec779b8eSAndroid Build Coastguard Worker         notify->post();
892*ec779b8eSAndroid Build Coastguard Worker     }
893*ec779b8eSAndroid Build Coastguard Worker }
894*ec779b8eSAndroid Build Coastguard Worker 
895*ec779b8eSAndroid Build Coastguard Worker // static
AudioSinkCallback(const sp<MediaPlayerBase::AudioSink> &,void * buffer,size_t size,const wp<RefBase> & cookie,MediaPlayerBase::AudioSink::cb_event_t event)896*ec779b8eSAndroid Build Coastguard Worker size_t NuPlayer::Renderer::AudioSinkCallback(
897*ec779b8eSAndroid Build Coastguard Worker         const sp<MediaPlayerBase::AudioSink>& /* audioSink */,
898*ec779b8eSAndroid Build Coastguard Worker         void *buffer,
899*ec779b8eSAndroid Build Coastguard Worker         size_t size,
900*ec779b8eSAndroid Build Coastguard Worker         const wp<RefBase>& cookie,
901*ec779b8eSAndroid Build Coastguard Worker         MediaPlayerBase::AudioSink::cb_event_t event) {
902*ec779b8eSAndroid Build Coastguard Worker     if (cookie == nullptr) return 0;
903*ec779b8eSAndroid Build Coastguard Worker     const auto ref = cookie.promote();
904*ec779b8eSAndroid Build Coastguard Worker     if (!ref) return 0;
905*ec779b8eSAndroid Build Coastguard Worker     const auto me = static_cast<NuPlayer::Renderer*>(ref.get()); // we already hold a sp.
906*ec779b8eSAndroid Build Coastguard Worker 
907*ec779b8eSAndroid Build Coastguard Worker     switch (event) {
908*ec779b8eSAndroid Build Coastguard Worker         case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
909*ec779b8eSAndroid Build Coastguard Worker         {
910*ec779b8eSAndroid Build Coastguard Worker             return me->fillAudioBuffer(buffer, size);
911*ec779b8eSAndroid Build Coastguard Worker             break;
912*ec779b8eSAndroid Build Coastguard Worker         }
913*ec779b8eSAndroid Build Coastguard Worker 
914*ec779b8eSAndroid Build Coastguard Worker         case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
915*ec779b8eSAndroid Build Coastguard Worker         {
916*ec779b8eSAndroid Build Coastguard Worker             ALOGV("AudioSink::CB_EVENT_STREAM_END");
917*ec779b8eSAndroid Build Coastguard Worker             me->notifyEOSCallback();
918*ec779b8eSAndroid Build Coastguard Worker             break;
919*ec779b8eSAndroid Build Coastguard Worker         }
920*ec779b8eSAndroid Build Coastguard Worker 
921*ec779b8eSAndroid Build Coastguard Worker         case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
922*ec779b8eSAndroid Build Coastguard Worker         {
923*ec779b8eSAndroid Build Coastguard Worker             ALOGV("AudioSink::CB_EVENT_TEAR_DOWN");
924*ec779b8eSAndroid Build Coastguard Worker             me->notifyAudioTearDown(kDueToError);
925*ec779b8eSAndroid Build Coastguard Worker             break;
926*ec779b8eSAndroid Build Coastguard Worker         }
927*ec779b8eSAndroid Build Coastguard Worker     }
928*ec779b8eSAndroid Build Coastguard Worker 
929*ec779b8eSAndroid Build Coastguard Worker     return 0;
930*ec779b8eSAndroid Build Coastguard Worker }
931*ec779b8eSAndroid Build Coastguard Worker 
notifyEOSCallback()932*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyEOSCallback() {
933*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
934*ec779b8eSAndroid Build Coastguard Worker 
935*ec779b8eSAndroid Build Coastguard Worker     if (!mUseAudioCallback) {
936*ec779b8eSAndroid Build Coastguard Worker         return;
937*ec779b8eSAndroid Build Coastguard Worker     }
938*ec779b8eSAndroid Build Coastguard Worker 
939*ec779b8eSAndroid Build Coastguard Worker     notifyEOS_l(true /* audio */, ERROR_END_OF_STREAM);
940*ec779b8eSAndroid Build Coastguard Worker }
941*ec779b8eSAndroid Build Coastguard Worker 
fillAudioBuffer(void * buffer,size_t size)942*ec779b8eSAndroid Build Coastguard Worker size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
943*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
944*ec779b8eSAndroid Build Coastguard Worker 
945*ec779b8eSAndroid Build Coastguard Worker     if (!mUseAudioCallback) {
946*ec779b8eSAndroid Build Coastguard Worker         return 0;
947*ec779b8eSAndroid Build Coastguard Worker     }
948*ec779b8eSAndroid Build Coastguard Worker 
949*ec779b8eSAndroid Build Coastguard Worker     bool hasEOS = false;
950*ec779b8eSAndroid Build Coastguard Worker 
951*ec779b8eSAndroid Build Coastguard Worker     size_t sizeCopied = 0;
952*ec779b8eSAndroid Build Coastguard Worker     bool firstEntry = true;
953*ec779b8eSAndroid Build Coastguard Worker     QueueEntry *entry;  // will be valid after while loop if hasEOS is set.
954*ec779b8eSAndroid Build Coastguard Worker     while (sizeCopied < size && !mAudioQueue.empty()) {
955*ec779b8eSAndroid Build Coastguard Worker         entry = &*mAudioQueue.begin();
956*ec779b8eSAndroid Build Coastguard Worker 
957*ec779b8eSAndroid Build Coastguard Worker         if (entry->mBuffer == NULL) { // EOS
958*ec779b8eSAndroid Build Coastguard Worker             hasEOS = true;
959*ec779b8eSAndroid Build Coastguard Worker             mAudioQueue.erase(mAudioQueue.begin());
960*ec779b8eSAndroid Build Coastguard Worker             break;
961*ec779b8eSAndroid Build Coastguard Worker         }
962*ec779b8eSAndroid Build Coastguard Worker 
963*ec779b8eSAndroid Build Coastguard Worker         if (firstEntry && entry->mOffset == 0) {
964*ec779b8eSAndroid Build Coastguard Worker             firstEntry = false;
965*ec779b8eSAndroid Build Coastguard Worker             int64_t mediaTimeUs;
966*ec779b8eSAndroid Build Coastguard Worker             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
967*ec779b8eSAndroid Build Coastguard Worker             if (mediaTimeUs < 0) {
968*ec779b8eSAndroid Build Coastguard Worker                 ALOGD("fillAudioBuffer: reset negative media time %.2f secs to zero",
969*ec779b8eSAndroid Build Coastguard Worker                        mediaTimeUs / 1E6);
970*ec779b8eSAndroid Build Coastguard Worker                 mediaTimeUs = 0;
971*ec779b8eSAndroid Build Coastguard Worker             }
972*ec779b8eSAndroid Build Coastguard Worker             ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
973*ec779b8eSAndroid Build Coastguard Worker             setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
974*ec779b8eSAndroid Build Coastguard Worker         }
975*ec779b8eSAndroid Build Coastguard Worker 
976*ec779b8eSAndroid Build Coastguard Worker         size_t copy = entry->mBuffer->size() - entry->mOffset;
977*ec779b8eSAndroid Build Coastguard Worker         size_t sizeRemaining = size - sizeCopied;
978*ec779b8eSAndroid Build Coastguard Worker         if (copy > sizeRemaining) {
979*ec779b8eSAndroid Build Coastguard Worker             copy = sizeRemaining;
980*ec779b8eSAndroid Build Coastguard Worker         }
981*ec779b8eSAndroid Build Coastguard Worker 
982*ec779b8eSAndroid Build Coastguard Worker         memcpy((char *)buffer + sizeCopied,
983*ec779b8eSAndroid Build Coastguard Worker                entry->mBuffer->data() + entry->mOffset,
984*ec779b8eSAndroid Build Coastguard Worker                copy);
985*ec779b8eSAndroid Build Coastguard Worker 
986*ec779b8eSAndroid Build Coastguard Worker         entry->mOffset += copy;
987*ec779b8eSAndroid Build Coastguard Worker         if (entry->mOffset == entry->mBuffer->size()) {
988*ec779b8eSAndroid Build Coastguard Worker             entry->mNotifyConsumed->post();
989*ec779b8eSAndroid Build Coastguard Worker             mAudioQueue.erase(mAudioQueue.begin());
990*ec779b8eSAndroid Build Coastguard Worker             entry = NULL;
991*ec779b8eSAndroid Build Coastguard Worker         }
992*ec779b8eSAndroid Build Coastguard Worker         sizeCopied += copy;
993*ec779b8eSAndroid Build Coastguard Worker 
994*ec779b8eSAndroid Build Coastguard Worker         notifyIfMediaRenderingStarted_l();
995*ec779b8eSAndroid Build Coastguard Worker     }
996*ec779b8eSAndroid Build Coastguard Worker 
997*ec779b8eSAndroid Build Coastguard Worker     if (mAudioFirstAnchorTimeMediaUs >= 0) {
998*ec779b8eSAndroid Build Coastguard Worker         int64_t nowUs = ALooper::GetNowUs();
999*ec779b8eSAndroid Build Coastguard Worker         int64_t nowMediaUs =
1000*ec779b8eSAndroid Build Coastguard Worker             mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
1001*ec779b8eSAndroid Build Coastguard Worker         // we don't know how much data we are queueing for offloaded tracks.
1002*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
1003*ec779b8eSAndroid Build Coastguard Worker     }
1004*ec779b8eSAndroid Build Coastguard Worker 
1005*ec779b8eSAndroid Build Coastguard Worker     // for non-offloaded audio, we need to compute the frames written because
1006*ec779b8eSAndroid Build Coastguard Worker     // there is no EVENT_STREAM_END notification. The frames written gives
1007*ec779b8eSAndroid Build Coastguard Worker     // an estimate on the pending played out duration.
1008*ec779b8eSAndroid Build Coastguard Worker     if (!offloadingAudio()) {
1009*ec779b8eSAndroid Build Coastguard Worker         mNumFramesWritten += sizeCopied / mAudioSink->frameSize();
1010*ec779b8eSAndroid Build Coastguard Worker     }
1011*ec779b8eSAndroid Build Coastguard Worker 
1012*ec779b8eSAndroid Build Coastguard Worker     if (hasEOS) {
1013*ec779b8eSAndroid Build Coastguard Worker         (new AMessage(kWhatStopAudioSink, this))->post();
1014*ec779b8eSAndroid Build Coastguard Worker         // As there is currently no EVENT_STREAM_END callback notification for
1015*ec779b8eSAndroid Build Coastguard Worker         // non-offloaded audio tracks, we need to post the EOS ourselves.
1016*ec779b8eSAndroid Build Coastguard Worker         if (!offloadingAudio()) {
1017*ec779b8eSAndroid Build Coastguard Worker             int64_t postEOSDelayUs = 0;
1018*ec779b8eSAndroid Build Coastguard Worker             if (mAudioSink->needsTrailingPadding()) {
1019*ec779b8eSAndroid Build Coastguard Worker                 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
1020*ec779b8eSAndroid Build Coastguard Worker             }
1021*ec779b8eSAndroid Build Coastguard Worker             ALOGV("fillAudioBuffer: notifyEOS_l "
1022*ec779b8eSAndroid Build Coastguard Worker                     "mNumFramesWritten:%u  finalResult:%d  postEOSDelay:%lld",
1023*ec779b8eSAndroid Build Coastguard Worker                     mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs);
1024*ec779b8eSAndroid Build Coastguard Worker             notifyEOS_l(true /* audio */, entry->mFinalResult, postEOSDelayUs);
1025*ec779b8eSAndroid Build Coastguard Worker         }
1026*ec779b8eSAndroid Build Coastguard Worker     }
1027*ec779b8eSAndroid Build Coastguard Worker     return sizeCopied;
1028*ec779b8eSAndroid Build Coastguard Worker }
1029*ec779b8eSAndroid Build Coastguard Worker 
drainAudioQueueUntilLastEOS()1030*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::drainAudioQueueUntilLastEOS() {
1031*ec779b8eSAndroid Build Coastguard Worker     List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
1032*ec779b8eSAndroid Build Coastguard Worker     bool foundEOS = false;
1033*ec779b8eSAndroid Build Coastguard Worker     while (it != mAudioQueue.end()) {
1034*ec779b8eSAndroid Build Coastguard Worker         int32_t eos;
1035*ec779b8eSAndroid Build Coastguard Worker         QueueEntry *entry = &*it++;
1036*ec779b8eSAndroid Build Coastguard Worker         if ((entry->mBuffer == nullptr && entry->mNotifyConsumed == nullptr)
1037*ec779b8eSAndroid Build Coastguard Worker                 || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
1038*ec779b8eSAndroid Build Coastguard Worker             itEOS = it;
1039*ec779b8eSAndroid Build Coastguard Worker             foundEOS = true;
1040*ec779b8eSAndroid Build Coastguard Worker         }
1041*ec779b8eSAndroid Build Coastguard Worker     }
1042*ec779b8eSAndroid Build Coastguard Worker 
1043*ec779b8eSAndroid Build Coastguard Worker     if (foundEOS) {
1044*ec779b8eSAndroid Build Coastguard Worker         // post all replies before EOS and drop the samples
1045*ec779b8eSAndroid Build Coastguard Worker         for (it = mAudioQueue.begin(); it != itEOS; it++) {
1046*ec779b8eSAndroid Build Coastguard Worker             if (it->mBuffer == nullptr) {
1047*ec779b8eSAndroid Build Coastguard Worker                 if (it->mNotifyConsumed == nullptr) {
1048*ec779b8eSAndroid Build Coastguard Worker                     // delay doesn't matter as we don't even have an AudioTrack
1049*ec779b8eSAndroid Build Coastguard Worker                     notifyEOS(true /* audio */, it->mFinalResult);
1050*ec779b8eSAndroid Build Coastguard Worker                 } else {
1051*ec779b8eSAndroid Build Coastguard Worker                     // TAG for re-opening audio sink.
1052*ec779b8eSAndroid Build Coastguard Worker                     onChangeAudioFormat(it->mMeta, it->mNotifyConsumed);
1053*ec779b8eSAndroid Build Coastguard Worker                 }
1054*ec779b8eSAndroid Build Coastguard Worker             } else {
1055*ec779b8eSAndroid Build Coastguard Worker                 it->mNotifyConsumed->post();
1056*ec779b8eSAndroid Build Coastguard Worker             }
1057*ec779b8eSAndroid Build Coastguard Worker         }
1058*ec779b8eSAndroid Build Coastguard Worker         mAudioQueue.erase(mAudioQueue.begin(), itEOS);
1059*ec779b8eSAndroid Build Coastguard Worker     }
1060*ec779b8eSAndroid Build Coastguard Worker }
1061*ec779b8eSAndroid Build Coastguard Worker 
onDrainAudioQueue()1062*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::Renderer::onDrainAudioQueue() {
1063*ec779b8eSAndroid Build Coastguard Worker     // do not drain audio during teardown as queued buffers may be invalid.
1064*ec779b8eSAndroid Build Coastguard Worker     if (mAudioTornDown) {
1065*ec779b8eSAndroid Build Coastguard Worker         return false;
1066*ec779b8eSAndroid Build Coastguard Worker     }
1067*ec779b8eSAndroid Build Coastguard Worker     // TODO: This call to getPosition checks if AudioTrack has been created
1068*ec779b8eSAndroid Build Coastguard Worker     // in AudioSink before draining audio. If AudioTrack doesn't exist, then
1069*ec779b8eSAndroid Build Coastguard Worker     // CHECKs on getPosition will fail.
1070*ec779b8eSAndroid Build Coastguard Worker     // We still need to figure out why AudioTrack is not created when
1071*ec779b8eSAndroid Build Coastguard Worker     // this function is called. One possible reason could be leftover
1072*ec779b8eSAndroid Build Coastguard Worker     // audio. Another possible place is to check whether decoder
1073*ec779b8eSAndroid Build Coastguard Worker     // has received INFO_FORMAT_CHANGED as the first buffer since
1074*ec779b8eSAndroid Build Coastguard Worker     // AudioSink is opened there, and possible interactions with flush
1075*ec779b8eSAndroid Build Coastguard Worker     // immediately after start. Investigate error message
1076*ec779b8eSAndroid Build Coastguard Worker     // "vorbis_dsp_synthesis returned -135", along with RTSP.
1077*ec779b8eSAndroid Build Coastguard Worker     uint32_t numFramesPlayed;
1078*ec779b8eSAndroid Build Coastguard Worker     if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
1079*ec779b8eSAndroid Build Coastguard Worker         // When getPosition fails, renderer will not reschedule the draining
1080*ec779b8eSAndroid Build Coastguard Worker         // unless new samples are queued.
1081*ec779b8eSAndroid Build Coastguard Worker         // If we have pending EOS (or "eos" marker for discontinuities), we need
1082*ec779b8eSAndroid Build Coastguard Worker         // to post these now as NuPlayerDecoder might be waiting for it.
1083*ec779b8eSAndroid Build Coastguard Worker         drainAudioQueueUntilLastEOS();
1084*ec779b8eSAndroid Build Coastguard Worker 
1085*ec779b8eSAndroid Build Coastguard Worker         ALOGW("onDrainAudioQueue(): audio sink is not ready");
1086*ec779b8eSAndroid Build Coastguard Worker         return false;
1087*ec779b8eSAndroid Build Coastguard Worker     }
1088*ec779b8eSAndroid Build Coastguard Worker 
1089*ec779b8eSAndroid Build Coastguard Worker #if 0
1090*ec779b8eSAndroid Build Coastguard Worker     ssize_t numFramesAvailableToWrite =
1091*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
1092*ec779b8eSAndroid Build Coastguard Worker 
1093*ec779b8eSAndroid Build Coastguard Worker     if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
1094*ec779b8eSAndroid Build Coastguard Worker         ALOGI("audio sink underrun");
1095*ec779b8eSAndroid Build Coastguard Worker     } else {
1096*ec779b8eSAndroid Build Coastguard Worker         ALOGV("audio queue has %d frames left to play",
1097*ec779b8eSAndroid Build Coastguard Worker              mAudioSink->frameCount() - numFramesAvailableToWrite);
1098*ec779b8eSAndroid Build Coastguard Worker     }
1099*ec779b8eSAndroid Build Coastguard Worker #endif
1100*ec779b8eSAndroid Build Coastguard Worker 
1101*ec779b8eSAndroid Build Coastguard Worker     uint32_t prevFramesWritten = mNumFramesWritten;
1102*ec779b8eSAndroid Build Coastguard Worker     while (!mAudioQueue.empty()) {
1103*ec779b8eSAndroid Build Coastguard Worker         QueueEntry *entry = &*mAudioQueue.begin();
1104*ec779b8eSAndroid Build Coastguard Worker 
1105*ec779b8eSAndroid Build Coastguard Worker         if (entry->mBuffer == NULL) {
1106*ec779b8eSAndroid Build Coastguard Worker             if (entry->mNotifyConsumed != nullptr) {
1107*ec779b8eSAndroid Build Coastguard Worker                 // TAG for re-open audio sink.
1108*ec779b8eSAndroid Build Coastguard Worker                 onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
1109*ec779b8eSAndroid Build Coastguard Worker                 mAudioQueue.erase(mAudioQueue.begin());
1110*ec779b8eSAndroid Build Coastguard Worker                 continue;
1111*ec779b8eSAndroid Build Coastguard Worker             }
1112*ec779b8eSAndroid Build Coastguard Worker 
1113*ec779b8eSAndroid Build Coastguard Worker             // EOS
1114*ec779b8eSAndroid Build Coastguard Worker             if (mPaused) {
1115*ec779b8eSAndroid Build Coastguard Worker                 // Do not notify EOS when paused.
1116*ec779b8eSAndroid Build Coastguard Worker                 // This is needed to avoid switch to next clip while in pause.
1117*ec779b8eSAndroid Build Coastguard Worker                 ALOGV("onDrainAudioQueue(): Do not notify EOS when paused");
1118*ec779b8eSAndroid Build Coastguard Worker                 return false;
1119*ec779b8eSAndroid Build Coastguard Worker             }
1120*ec779b8eSAndroid Build Coastguard Worker 
1121*ec779b8eSAndroid Build Coastguard Worker             int64_t postEOSDelayUs = 0;
1122*ec779b8eSAndroid Build Coastguard Worker             if (mAudioSink->needsTrailingPadding()) {
1123*ec779b8eSAndroid Build Coastguard Worker                 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
1124*ec779b8eSAndroid Build Coastguard Worker             }
1125*ec779b8eSAndroid Build Coastguard Worker             notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
1126*ec779b8eSAndroid Build Coastguard Worker             mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
1127*ec779b8eSAndroid Build Coastguard Worker 
1128*ec779b8eSAndroid Build Coastguard Worker             mAudioQueue.erase(mAudioQueue.begin());
1129*ec779b8eSAndroid Build Coastguard Worker             entry = NULL;
1130*ec779b8eSAndroid Build Coastguard Worker             if (mAudioSink->needsTrailingPadding()) {
1131*ec779b8eSAndroid Build Coastguard Worker                 // If we're not in gapless playback (i.e. through setNextPlayer), we
1132*ec779b8eSAndroid Build Coastguard Worker                 // need to stop the track here, because that will play out the last
1133*ec779b8eSAndroid Build Coastguard Worker                 // little bit at the end of the file. Otherwise short files won't play.
1134*ec779b8eSAndroid Build Coastguard Worker                 mAudioSink->stop();
1135*ec779b8eSAndroid Build Coastguard Worker                 mNumFramesWritten = 0;
1136*ec779b8eSAndroid Build Coastguard Worker             }
1137*ec779b8eSAndroid Build Coastguard Worker             return false;
1138*ec779b8eSAndroid Build Coastguard Worker         }
1139*ec779b8eSAndroid Build Coastguard Worker 
1140*ec779b8eSAndroid Build Coastguard Worker         mLastAudioBufferDrained = entry->mBufferOrdinal;
1141*ec779b8eSAndroid Build Coastguard Worker 
1142*ec779b8eSAndroid Build Coastguard Worker         // ignore 0-sized buffer which could be EOS marker with no data
1143*ec779b8eSAndroid Build Coastguard Worker         if (entry->mOffset == 0 && entry->mBuffer->size() > 0) {
1144*ec779b8eSAndroid Build Coastguard Worker             int64_t mediaTimeUs;
1145*ec779b8eSAndroid Build Coastguard Worker             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
1146*ec779b8eSAndroid Build Coastguard Worker             ALOGV("onDrainAudioQueue: rendering audio at media time %.2f secs",
1147*ec779b8eSAndroid Build Coastguard Worker                     mediaTimeUs / 1E6);
1148*ec779b8eSAndroid Build Coastguard Worker             onNewAudioMediaTime(mediaTimeUs);
1149*ec779b8eSAndroid Build Coastguard Worker         }
1150*ec779b8eSAndroid Build Coastguard Worker 
1151*ec779b8eSAndroid Build Coastguard Worker         size_t copy = entry->mBuffer->size() - entry->mOffset;
1152*ec779b8eSAndroid Build Coastguard Worker 
1153*ec779b8eSAndroid Build Coastguard Worker         ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
1154*ec779b8eSAndroid Build Coastguard Worker                                             copy, false /* blocking */);
1155*ec779b8eSAndroid Build Coastguard Worker         if (written < 0) {
1156*ec779b8eSAndroid Build Coastguard Worker             // An error in AudioSink write. Perhaps the AudioSink was not properly opened.
1157*ec779b8eSAndroid Build Coastguard Worker             if (written == WOULD_BLOCK) {
1158*ec779b8eSAndroid Build Coastguard Worker                 ALOGV("AudioSink write would block when writing %zu bytes", copy);
1159*ec779b8eSAndroid Build Coastguard Worker             } else {
1160*ec779b8eSAndroid Build Coastguard Worker                 ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
1161*ec779b8eSAndroid Build Coastguard Worker                 // This can only happen when AudioSink was opened with doNotReconnect flag set to
1162*ec779b8eSAndroid Build Coastguard Worker                 // true, in which case the NuPlayer will handle the reconnect.
1163*ec779b8eSAndroid Build Coastguard Worker                 notifyAudioTearDown(kDueToError);
1164*ec779b8eSAndroid Build Coastguard Worker             }
1165*ec779b8eSAndroid Build Coastguard Worker             break;
1166*ec779b8eSAndroid Build Coastguard Worker         }
1167*ec779b8eSAndroid Build Coastguard Worker 
1168*ec779b8eSAndroid Build Coastguard Worker         entry->mOffset += written;
1169*ec779b8eSAndroid Build Coastguard Worker         size_t remainder = entry->mBuffer->size() - entry->mOffset;
1170*ec779b8eSAndroid Build Coastguard Worker         if ((ssize_t)remainder < mAudioSink->frameSize()) {
1171*ec779b8eSAndroid Build Coastguard Worker             if (remainder > 0) {
1172*ec779b8eSAndroid Build Coastguard Worker                 ALOGW("Corrupted audio buffer has fractional frames, discarding %zu bytes.",
1173*ec779b8eSAndroid Build Coastguard Worker                         remainder);
1174*ec779b8eSAndroid Build Coastguard Worker                 entry->mOffset += remainder;
1175*ec779b8eSAndroid Build Coastguard Worker                 copy -= remainder;
1176*ec779b8eSAndroid Build Coastguard Worker             }
1177*ec779b8eSAndroid Build Coastguard Worker 
1178*ec779b8eSAndroid Build Coastguard Worker             entry->mNotifyConsumed->post();
1179*ec779b8eSAndroid Build Coastguard Worker             mAudioQueue.erase(mAudioQueue.begin());
1180*ec779b8eSAndroid Build Coastguard Worker 
1181*ec779b8eSAndroid Build Coastguard Worker             entry = NULL;
1182*ec779b8eSAndroid Build Coastguard Worker         }
1183*ec779b8eSAndroid Build Coastguard Worker 
1184*ec779b8eSAndroid Build Coastguard Worker         size_t copiedFrames = written / mAudioSink->frameSize();
1185*ec779b8eSAndroid Build Coastguard Worker         mNumFramesWritten += copiedFrames;
1186*ec779b8eSAndroid Build Coastguard Worker 
1187*ec779b8eSAndroid Build Coastguard Worker         {
1188*ec779b8eSAndroid Build Coastguard Worker             Mutex::Autolock autoLock(mLock);
1189*ec779b8eSAndroid Build Coastguard Worker             int64_t maxTimeMedia;
1190*ec779b8eSAndroid Build Coastguard Worker             maxTimeMedia =
1191*ec779b8eSAndroid Build Coastguard Worker                 mAnchorTimeMediaUs +
1192*ec779b8eSAndroid Build Coastguard Worker                         (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
1193*ec779b8eSAndroid Build Coastguard Worker                                 * 1000LL * mAudioSink->msecsPerFrame());
1194*ec779b8eSAndroid Build Coastguard Worker             mMediaClock->updateMaxTimeMedia(maxTimeMedia);
1195*ec779b8eSAndroid Build Coastguard Worker 
1196*ec779b8eSAndroid Build Coastguard Worker             notifyIfMediaRenderingStarted_l();
1197*ec779b8eSAndroid Build Coastguard Worker         }
1198*ec779b8eSAndroid Build Coastguard Worker 
1199*ec779b8eSAndroid Build Coastguard Worker         if (written != (ssize_t)copy) {
1200*ec779b8eSAndroid Build Coastguard Worker             // A short count was received from AudioSink::write()
1201*ec779b8eSAndroid Build Coastguard Worker             //
1202*ec779b8eSAndroid Build Coastguard Worker             // AudioSink write is called in non-blocking mode.
1203*ec779b8eSAndroid Build Coastguard Worker             // It may return with a short count when:
1204*ec779b8eSAndroid Build Coastguard Worker             //
1205*ec779b8eSAndroid Build Coastguard Worker             // 1) Size to be copied is not a multiple of the frame size. Fractional frames are
1206*ec779b8eSAndroid Build Coastguard Worker             //    discarded.
1207*ec779b8eSAndroid Build Coastguard Worker             // 2) The data to be copied exceeds the available buffer in AudioSink.
1208*ec779b8eSAndroid Build Coastguard Worker             // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
1209*ec779b8eSAndroid Build Coastguard Worker             // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
1210*ec779b8eSAndroid Build Coastguard Worker 
1211*ec779b8eSAndroid Build Coastguard Worker             // (Case 1)
1212*ec779b8eSAndroid Build Coastguard Worker             // Must be a multiple of the frame size.  If it is not a multiple of a frame size, it
1213*ec779b8eSAndroid Build Coastguard Worker             // needs to fail, as we should not carry over fractional frames between calls.
1214*ec779b8eSAndroid Build Coastguard Worker             CHECK_EQ(copy % mAudioSink->frameSize(), 0u);
1215*ec779b8eSAndroid Build Coastguard Worker 
1216*ec779b8eSAndroid Build Coastguard Worker             // (Case 2, 3, 4)
1217*ec779b8eSAndroid Build Coastguard Worker             // Return early to the caller.
1218*ec779b8eSAndroid Build Coastguard Worker             // Beware of calling immediately again as this may busy-loop if you are not careful.
1219*ec779b8eSAndroid Build Coastguard Worker             ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
1220*ec779b8eSAndroid Build Coastguard Worker             break;
1221*ec779b8eSAndroid Build Coastguard Worker         }
1222*ec779b8eSAndroid Build Coastguard Worker     }
1223*ec779b8eSAndroid Build Coastguard Worker 
1224*ec779b8eSAndroid Build Coastguard Worker     // calculate whether we need to reschedule another write.
1225*ec779b8eSAndroid Build Coastguard Worker     bool reschedule = !mAudioQueue.empty()
1226*ec779b8eSAndroid Build Coastguard Worker             && (!mPaused
1227*ec779b8eSAndroid Build Coastguard Worker                 || prevFramesWritten != mNumFramesWritten); // permit pause to fill buffers
1228*ec779b8eSAndroid Build Coastguard Worker     //ALOGD("reschedule:%d  empty:%d  mPaused:%d  prevFramesWritten:%u  mNumFramesWritten:%u",
1229*ec779b8eSAndroid Build Coastguard Worker     //        reschedule, mAudioQueue.empty(), mPaused, prevFramesWritten, mNumFramesWritten);
1230*ec779b8eSAndroid Build Coastguard Worker     return reschedule;
1231*ec779b8eSAndroid Build Coastguard Worker }
1232*ec779b8eSAndroid Build Coastguard Worker 
getDurationUsIfPlayedAtSampleRate(uint32_t numFrames)1233*ec779b8eSAndroid Build Coastguard Worker int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
1234*ec779b8eSAndroid Build Coastguard Worker     int32_t sampleRate = offloadingAudio() ?
1235*ec779b8eSAndroid Build Coastguard Worker             mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
1236*ec779b8eSAndroid Build Coastguard Worker     if (sampleRate == 0) {
1237*ec779b8eSAndroid Build Coastguard Worker         ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
1238*ec779b8eSAndroid Build Coastguard Worker         return 0;
1239*ec779b8eSAndroid Build Coastguard Worker     }
1240*ec779b8eSAndroid Build Coastguard Worker 
1241*ec779b8eSAndroid Build Coastguard Worker     return (int64_t)(numFrames * 1000000LL / sampleRate);
1242*ec779b8eSAndroid Build Coastguard Worker }
1243*ec779b8eSAndroid Build Coastguard Worker 
1244*ec779b8eSAndroid Build Coastguard Worker // Calculate duration of pending samples if played at normal rate (i.e., 1.0).
getPendingAudioPlayoutDurationUs(int64_t nowUs)1245*ec779b8eSAndroid Build Coastguard Worker int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
1246*ec779b8eSAndroid Build Coastguard Worker     int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
1247*ec779b8eSAndroid Build Coastguard Worker     if (mUseVirtualAudioSink) {
1248*ec779b8eSAndroid Build Coastguard Worker         int64_t nowUs = ALooper::GetNowUs();
1249*ec779b8eSAndroid Build Coastguard Worker         int64_t mediaUs;
1250*ec779b8eSAndroid Build Coastguard Worker         if (mMediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
1251*ec779b8eSAndroid Build Coastguard Worker             return 0LL;
1252*ec779b8eSAndroid Build Coastguard Worker         } else {
1253*ec779b8eSAndroid Build Coastguard Worker             return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
1254*ec779b8eSAndroid Build Coastguard Worker         }
1255*ec779b8eSAndroid Build Coastguard Worker     }
1256*ec779b8eSAndroid Build Coastguard Worker 
1257*ec779b8eSAndroid Build Coastguard Worker     const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
1258*ec779b8eSAndroid Build Coastguard Worker     int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
1259*ec779b8eSAndroid Build Coastguard Worker     if (pendingUs < 0) {
1260*ec779b8eSAndroid Build Coastguard Worker         // This shouldn't happen unless the timestamp is stale.
1261*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
1262*ec779b8eSAndroid Build Coastguard Worker                 "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
1263*ec779b8eSAndroid Build Coastguard Worker                 __func__, (long long)pendingUs,
1264*ec779b8eSAndroid Build Coastguard Worker                 (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
1265*ec779b8eSAndroid Build Coastguard Worker         pendingUs = 0;
1266*ec779b8eSAndroid Build Coastguard Worker     }
1267*ec779b8eSAndroid Build Coastguard Worker     return pendingUs;
1268*ec779b8eSAndroid Build Coastguard Worker }
1269*ec779b8eSAndroid Build Coastguard Worker 
getRealTimeUs(int64_t mediaTimeUs,int64_t nowUs)1270*ec779b8eSAndroid Build Coastguard Worker int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
1271*ec779b8eSAndroid Build Coastguard Worker     int64_t realUs;
1272*ec779b8eSAndroid Build Coastguard Worker     if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
1273*ec779b8eSAndroid Build Coastguard Worker         // If failed to get current position, e.g. due to audio clock is
1274*ec779b8eSAndroid Build Coastguard Worker         // not ready, then just play out video immediately without delay.
1275*ec779b8eSAndroid Build Coastguard Worker         return nowUs;
1276*ec779b8eSAndroid Build Coastguard Worker     }
1277*ec779b8eSAndroid Build Coastguard Worker     return realUs;
1278*ec779b8eSAndroid Build Coastguard Worker }
1279*ec779b8eSAndroid Build Coastguard Worker 
onNewAudioMediaTime(int64_t mediaTimeUs)1280*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
1281*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1282*ec779b8eSAndroid Build Coastguard Worker     // TRICKY: vorbis decoder generates multiple frames with the same
1283*ec779b8eSAndroid Build Coastguard Worker     // timestamp, so only update on the first frame with a given timestamp
1284*ec779b8eSAndroid Build Coastguard Worker     if (mediaTimeUs == mAudioAnchorTimeMediaUs) {
1285*ec779b8eSAndroid Build Coastguard Worker         return;
1286*ec779b8eSAndroid Build Coastguard Worker     }
1287*ec779b8eSAndroid Build Coastguard Worker     setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
1288*ec779b8eSAndroid Build Coastguard Worker 
1289*ec779b8eSAndroid Build Coastguard Worker     // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
1290*ec779b8eSAndroid Build Coastguard Worker     if (mNextAudioClockUpdateTimeUs == -1) {
1291*ec779b8eSAndroid Build Coastguard Worker         AudioTimestamp ts;
1292*ec779b8eSAndroid Build Coastguard Worker         if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
1293*ec779b8eSAndroid Build Coastguard Worker             mNextAudioClockUpdateTimeUs = 0; // start our clock updates
1294*ec779b8eSAndroid Build Coastguard Worker         }
1295*ec779b8eSAndroid Build Coastguard Worker     }
1296*ec779b8eSAndroid Build Coastguard Worker     int64_t nowUs = ALooper::GetNowUs();
1297*ec779b8eSAndroid Build Coastguard Worker     if (mNextAudioClockUpdateTimeUs >= 0) {
1298*ec779b8eSAndroid Build Coastguard Worker         if (nowUs >= mNextAudioClockUpdateTimeUs) {
1299*ec779b8eSAndroid Build Coastguard Worker             int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
1300*ec779b8eSAndroid Build Coastguard Worker             mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
1301*ec779b8eSAndroid Build Coastguard Worker             mUseVirtualAudioSink = false;
1302*ec779b8eSAndroid Build Coastguard Worker             mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
1303*ec779b8eSAndroid Build Coastguard Worker         }
1304*ec779b8eSAndroid Build Coastguard Worker     } else {
1305*ec779b8eSAndroid Build Coastguard Worker         int64_t unused;
1306*ec779b8eSAndroid Build Coastguard Worker         if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
1307*ec779b8eSAndroid Build Coastguard Worker                 && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
1308*ec779b8eSAndroid Build Coastguard Worker                         > kMaxAllowedAudioSinkDelayUs)) {
1309*ec779b8eSAndroid Build Coastguard Worker             // Enough data has been sent to AudioSink, but AudioSink has not rendered
1310*ec779b8eSAndroid Build Coastguard Worker             // any data yet. Something is wrong with AudioSink, e.g., the device is not
1311*ec779b8eSAndroid Build Coastguard Worker             // connected to audio out.
1312*ec779b8eSAndroid Build Coastguard Worker             // Switch to system clock. This essentially creates a virtual AudioSink with
1313*ec779b8eSAndroid Build Coastguard Worker             // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
1314*ec779b8eSAndroid Build Coastguard Worker             // This virtual AudioSink renders audio data starting from the very first sample
1315*ec779b8eSAndroid Build Coastguard Worker             // and it's paced by system clock.
1316*ec779b8eSAndroid Build Coastguard Worker             ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
1317*ec779b8eSAndroid Build Coastguard Worker             mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
1318*ec779b8eSAndroid Build Coastguard Worker             mUseVirtualAudioSink = true;
1319*ec779b8eSAndroid Build Coastguard Worker         }
1320*ec779b8eSAndroid Build Coastguard Worker     }
1321*ec779b8eSAndroid Build Coastguard Worker     mAnchorNumFramesWritten = mNumFramesWritten;
1322*ec779b8eSAndroid Build Coastguard Worker     mAudioAnchorTimeMediaUs = mediaTimeUs;
1323*ec779b8eSAndroid Build Coastguard Worker     mAnchorTimeMediaUs = mediaTimeUs;
1324*ec779b8eSAndroid Build Coastguard Worker }
1325*ec779b8eSAndroid Build Coastguard Worker 
1326*ec779b8eSAndroid Build Coastguard Worker // Called without mLock acquired.
postDrainVideoQueue()1327*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::postDrainVideoQueue() {
1328*ec779b8eSAndroid Build Coastguard Worker     if (mDrainVideoQueuePending
1329*ec779b8eSAndroid Build Coastguard Worker             || getSyncQueues()
1330*ec779b8eSAndroid Build Coastguard Worker             || (mPaused && mVideoSampleReceived)) {
1331*ec779b8eSAndroid Build Coastguard Worker         return;
1332*ec779b8eSAndroid Build Coastguard Worker     }
1333*ec779b8eSAndroid Build Coastguard Worker 
1334*ec779b8eSAndroid Build Coastguard Worker     if (mVideoQueue.empty()) {
1335*ec779b8eSAndroid Build Coastguard Worker         return;
1336*ec779b8eSAndroid Build Coastguard Worker     }
1337*ec779b8eSAndroid Build Coastguard Worker 
1338*ec779b8eSAndroid Build Coastguard Worker     QueueEntry &entry = *mVideoQueue.begin();
1339*ec779b8eSAndroid Build Coastguard Worker 
1340*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this);
1341*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("drainGeneration", getDrainGeneration(false /* audio */));
1342*ec779b8eSAndroid Build Coastguard Worker 
1343*ec779b8eSAndroid Build Coastguard Worker     if (entry.mBuffer == NULL) {
1344*ec779b8eSAndroid Build Coastguard Worker         // EOS doesn't carry a timestamp.
1345*ec779b8eSAndroid Build Coastguard Worker         msg->post();
1346*ec779b8eSAndroid Build Coastguard Worker         mDrainVideoQueuePending = true;
1347*ec779b8eSAndroid Build Coastguard Worker         return;
1348*ec779b8eSAndroid Build Coastguard Worker     }
1349*ec779b8eSAndroid Build Coastguard Worker 
1350*ec779b8eSAndroid Build Coastguard Worker     int64_t nowUs = ALooper::GetNowUs();
1351*ec779b8eSAndroid Build Coastguard Worker     if (mFlags & FLAG_REAL_TIME) {
1352*ec779b8eSAndroid Build Coastguard Worker         int64_t realTimeUs;
1353*ec779b8eSAndroid Build Coastguard Worker         CHECK(entry.mBuffer->meta()->findInt64("timeUs", &realTimeUs));
1354*ec779b8eSAndroid Build Coastguard Worker 
1355*ec779b8eSAndroid Build Coastguard Worker         realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
1356*ec779b8eSAndroid Build Coastguard Worker 
1357*ec779b8eSAndroid Build Coastguard Worker         int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
1358*ec779b8eSAndroid Build Coastguard Worker 
1359*ec779b8eSAndroid Build Coastguard Worker         int64_t delayUs = realTimeUs - nowUs;
1360*ec779b8eSAndroid Build Coastguard Worker 
1361*ec779b8eSAndroid Build Coastguard Worker         ALOGW_IF(delayUs > 500000, "unusually high delayUs: %lld", (long long)delayUs);
1362*ec779b8eSAndroid Build Coastguard Worker         // post 2 display refreshes before rendering is due
1363*ec779b8eSAndroid Build Coastguard Worker         msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
1364*ec779b8eSAndroid Build Coastguard Worker 
1365*ec779b8eSAndroid Build Coastguard Worker         mDrainVideoQueuePending = true;
1366*ec779b8eSAndroid Build Coastguard Worker         return;
1367*ec779b8eSAndroid Build Coastguard Worker     }
1368*ec779b8eSAndroid Build Coastguard Worker 
1369*ec779b8eSAndroid Build Coastguard Worker     int64_t mediaTimeUs;
1370*ec779b8eSAndroid Build Coastguard Worker     CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
1371*ec779b8eSAndroid Build Coastguard Worker 
1372*ec779b8eSAndroid Build Coastguard Worker     {
1373*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1374*ec779b8eSAndroid Build Coastguard Worker         if (mNeedVideoClearAnchor && !mHasAudio) {
1375*ec779b8eSAndroid Build Coastguard Worker             mNeedVideoClearAnchor = false;
1376*ec779b8eSAndroid Build Coastguard Worker             clearAnchorTime();
1377*ec779b8eSAndroid Build Coastguard Worker         }
1378*ec779b8eSAndroid Build Coastguard Worker         if (mAnchorTimeMediaUs < 0) {
1379*ec779b8eSAndroid Build Coastguard Worker             mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
1380*ec779b8eSAndroid Build Coastguard Worker             mAnchorTimeMediaUs = mediaTimeUs;
1381*ec779b8eSAndroid Build Coastguard Worker         }
1382*ec779b8eSAndroid Build Coastguard Worker     }
1383*ec779b8eSAndroid Build Coastguard Worker     mNextVideoTimeMediaUs = mediaTimeUs;
1384*ec779b8eSAndroid Build Coastguard Worker     if (!mHasAudio) {
1385*ec779b8eSAndroid Build Coastguard Worker         // smooth out videos >= 10fps
1386*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
1387*ec779b8eSAndroid Build Coastguard Worker     }
1388*ec779b8eSAndroid Build Coastguard Worker 
1389*ec779b8eSAndroid Build Coastguard Worker     if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
1390*ec779b8eSAndroid Build Coastguard Worker         msg->post();
1391*ec779b8eSAndroid Build Coastguard Worker     } else {
1392*ec779b8eSAndroid Build Coastguard Worker         int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
1393*ec779b8eSAndroid Build Coastguard Worker 
1394*ec779b8eSAndroid Build Coastguard Worker         // post 2 display refreshes before rendering is due
1395*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->addTimer(msg, mediaTimeUs, -twoVsyncsUs);
1396*ec779b8eSAndroid Build Coastguard Worker     }
1397*ec779b8eSAndroid Build Coastguard Worker 
1398*ec779b8eSAndroid Build Coastguard Worker     mDrainVideoQueuePending = true;
1399*ec779b8eSAndroid Build Coastguard Worker }
1400*ec779b8eSAndroid Build Coastguard Worker 
onDrainVideoQueue()1401*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onDrainVideoQueue() {
1402*ec779b8eSAndroid Build Coastguard Worker     if (mVideoQueue.empty()) {
1403*ec779b8eSAndroid Build Coastguard Worker         return;
1404*ec779b8eSAndroid Build Coastguard Worker     }
1405*ec779b8eSAndroid Build Coastguard Worker 
1406*ec779b8eSAndroid Build Coastguard Worker     QueueEntry *entry = &*mVideoQueue.begin();
1407*ec779b8eSAndroid Build Coastguard Worker 
1408*ec779b8eSAndroid Build Coastguard Worker     if (entry->mBuffer == NULL) {
1409*ec779b8eSAndroid Build Coastguard Worker         // EOS
1410*ec779b8eSAndroid Build Coastguard Worker 
1411*ec779b8eSAndroid Build Coastguard Worker         notifyEOS(false /* audio */, entry->mFinalResult);
1412*ec779b8eSAndroid Build Coastguard Worker 
1413*ec779b8eSAndroid Build Coastguard Worker         mVideoQueue.erase(mVideoQueue.begin());
1414*ec779b8eSAndroid Build Coastguard Worker         entry = NULL;
1415*ec779b8eSAndroid Build Coastguard Worker 
1416*ec779b8eSAndroid Build Coastguard Worker         setVideoLateByUs(0);
1417*ec779b8eSAndroid Build Coastguard Worker         return;
1418*ec779b8eSAndroid Build Coastguard Worker     }
1419*ec779b8eSAndroid Build Coastguard Worker 
1420*ec779b8eSAndroid Build Coastguard Worker     int64_t nowUs = ALooper::GetNowUs();
1421*ec779b8eSAndroid Build Coastguard Worker     int64_t realTimeUs;
1422*ec779b8eSAndroid Build Coastguard Worker     int64_t mediaTimeUs = -1;
1423*ec779b8eSAndroid Build Coastguard Worker     if (mFlags & FLAG_REAL_TIME) {
1424*ec779b8eSAndroid Build Coastguard Worker         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
1425*ec779b8eSAndroid Build Coastguard Worker     } else {
1426*ec779b8eSAndroid Build Coastguard Worker         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
1427*ec779b8eSAndroid Build Coastguard Worker 
1428*ec779b8eSAndroid Build Coastguard Worker         realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
1429*ec779b8eSAndroid Build Coastguard Worker     }
1430*ec779b8eSAndroid Build Coastguard Worker     realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
1431*ec779b8eSAndroid Build Coastguard Worker 
1432*ec779b8eSAndroid Build Coastguard Worker     bool tooLate = false;
1433*ec779b8eSAndroid Build Coastguard Worker 
1434*ec779b8eSAndroid Build Coastguard Worker     if (!mPaused) {
1435*ec779b8eSAndroid Build Coastguard Worker         setVideoLateByUs(nowUs - realTimeUs);
1436*ec779b8eSAndroid Build Coastguard Worker         tooLate = (mVideoLateByUs > 40000);
1437*ec779b8eSAndroid Build Coastguard Worker 
1438*ec779b8eSAndroid Build Coastguard Worker         if (tooLate) {
1439*ec779b8eSAndroid Build Coastguard Worker             ALOGV("video late by %lld us (%.2f secs)",
1440*ec779b8eSAndroid Build Coastguard Worker                  (long long)mVideoLateByUs, mVideoLateByUs / 1E6);
1441*ec779b8eSAndroid Build Coastguard Worker         } else {
1442*ec779b8eSAndroid Build Coastguard Worker             int64_t mediaUs = 0;
1443*ec779b8eSAndroid Build Coastguard Worker             mMediaClock->getMediaTime(realTimeUs, &mediaUs);
1444*ec779b8eSAndroid Build Coastguard Worker             ALOGV("rendering video at media time %.2f secs",
1445*ec779b8eSAndroid Build Coastguard Worker                     (mFlags & FLAG_REAL_TIME ? realTimeUs :
1446*ec779b8eSAndroid Build Coastguard Worker                     mediaUs) / 1E6);
1447*ec779b8eSAndroid Build Coastguard Worker 
1448*ec779b8eSAndroid Build Coastguard Worker             if (!(mFlags & FLAG_REAL_TIME)
1449*ec779b8eSAndroid Build Coastguard Worker                     && mLastAudioMediaTimeUs != -1
1450*ec779b8eSAndroid Build Coastguard Worker                     && mediaTimeUs > mLastAudioMediaTimeUs) {
1451*ec779b8eSAndroid Build Coastguard Worker                 // If audio ends before video, video continues to drive media clock.
1452*ec779b8eSAndroid Build Coastguard Worker                 // Also smooth out videos >= 10fps.
1453*ec779b8eSAndroid Build Coastguard Worker                 mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
1454*ec779b8eSAndroid Build Coastguard Worker             }
1455*ec779b8eSAndroid Build Coastguard Worker         }
1456*ec779b8eSAndroid Build Coastguard Worker     } else {
1457*ec779b8eSAndroid Build Coastguard Worker         setVideoLateByUs(0);
1458*ec779b8eSAndroid Build Coastguard Worker         if (!mVideoSampleReceived && !mHasAudio) {
1459*ec779b8eSAndroid Build Coastguard Worker             // This will ensure that the first frame after a flush won't be used as anchor
1460*ec779b8eSAndroid Build Coastguard Worker             // when renderer is in paused state, because resume can happen any time after seek.
1461*ec779b8eSAndroid Build Coastguard Worker             clearAnchorTime();
1462*ec779b8eSAndroid Build Coastguard Worker         }
1463*ec779b8eSAndroid Build Coastguard Worker     }
1464*ec779b8eSAndroid Build Coastguard Worker 
1465*ec779b8eSAndroid Build Coastguard Worker     // Always render the first video frame while keeping stats on A/V sync.
1466*ec779b8eSAndroid Build Coastguard Worker     if (!mVideoSampleReceived) {
1467*ec779b8eSAndroid Build Coastguard Worker         realTimeUs = nowUs;
1468*ec779b8eSAndroid Build Coastguard Worker         tooLate = false;
1469*ec779b8eSAndroid Build Coastguard Worker     }
1470*ec779b8eSAndroid Build Coastguard Worker 
1471*ec779b8eSAndroid Build Coastguard Worker     entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000LL);
1472*ec779b8eSAndroid Build Coastguard Worker     entry->mNotifyConsumed->setInt32("render", !tooLate);
1473*ec779b8eSAndroid Build Coastguard Worker     entry->mNotifyConsumed->post();
1474*ec779b8eSAndroid Build Coastguard Worker     mVideoQueue.erase(mVideoQueue.begin());
1475*ec779b8eSAndroid Build Coastguard Worker     entry = NULL;
1476*ec779b8eSAndroid Build Coastguard Worker 
1477*ec779b8eSAndroid Build Coastguard Worker     mVideoSampleReceived = true;
1478*ec779b8eSAndroid Build Coastguard Worker 
1479*ec779b8eSAndroid Build Coastguard Worker     if (!mPaused) {
1480*ec779b8eSAndroid Build Coastguard Worker         if (!mVideoRenderingStarted) {
1481*ec779b8eSAndroid Build Coastguard Worker             mVideoRenderingStarted = true;
1482*ec779b8eSAndroid Build Coastguard Worker             notifyVideoRenderingStart();
1483*ec779b8eSAndroid Build Coastguard Worker         }
1484*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1485*ec779b8eSAndroid Build Coastguard Worker         notifyIfMediaRenderingStarted_l();
1486*ec779b8eSAndroid Build Coastguard Worker     }
1487*ec779b8eSAndroid Build Coastguard Worker }
1488*ec779b8eSAndroid Build Coastguard Worker 
notifyVideoRenderingStart()1489*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyVideoRenderingStart() {
1490*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notify = mNotify->dup();
1491*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("what", kWhatVideoRenderingStart);
1492*ec779b8eSAndroid Build Coastguard Worker     notify->post();
1493*ec779b8eSAndroid Build Coastguard Worker }
1494*ec779b8eSAndroid Build Coastguard Worker 
notifyEOS(bool audio,status_t finalResult,int64_t delayUs)1495*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
1496*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1497*ec779b8eSAndroid Build Coastguard Worker     notifyEOS_l(audio, finalResult, delayUs);
1498*ec779b8eSAndroid Build Coastguard Worker }
1499*ec779b8eSAndroid Build Coastguard Worker 
notifyEOS_l(bool audio,status_t finalResult,int64_t delayUs)1500*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs) {
1501*ec779b8eSAndroid Build Coastguard Worker     if (audio && delayUs > 0) {
1502*ec779b8eSAndroid Build Coastguard Worker         sp<AMessage> msg = new AMessage(kWhatEOS, this);
1503*ec779b8eSAndroid Build Coastguard Worker         msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
1504*ec779b8eSAndroid Build Coastguard Worker         msg->setInt32("finalResult", finalResult);
1505*ec779b8eSAndroid Build Coastguard Worker         msg->post(delayUs);
1506*ec779b8eSAndroid Build Coastguard Worker         return;
1507*ec779b8eSAndroid Build Coastguard Worker     }
1508*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notify = mNotify->dup();
1509*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("what", kWhatEOS);
1510*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("audio", static_cast<int32_t>(audio));
1511*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("finalResult", finalResult);
1512*ec779b8eSAndroid Build Coastguard Worker     notify->post(delayUs);
1513*ec779b8eSAndroid Build Coastguard Worker 
1514*ec779b8eSAndroid Build Coastguard Worker     if (audio) {
1515*ec779b8eSAndroid Build Coastguard Worker         // Video might outlive audio. Clear anchor to enable video only case.
1516*ec779b8eSAndroid Build Coastguard Worker         mAnchorTimeMediaUs = -1;
1517*ec779b8eSAndroid Build Coastguard Worker         mHasAudio = false;
1518*ec779b8eSAndroid Build Coastguard Worker         if (mNextVideoTimeMediaUs >= 0) {
1519*ec779b8eSAndroid Build Coastguard Worker             int64_t mediaUs = 0;
1520*ec779b8eSAndroid Build Coastguard Worker             int64_t nowUs = ALooper::GetNowUs();
1521*ec779b8eSAndroid Build Coastguard Worker             status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
1522*ec779b8eSAndroid Build Coastguard Worker             if (result == OK) {
1523*ec779b8eSAndroid Build Coastguard Worker                 if (mNextVideoTimeMediaUs > mediaUs) {
1524*ec779b8eSAndroid Build Coastguard Worker                     mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
1525*ec779b8eSAndroid Build Coastguard Worker                 }
1526*ec779b8eSAndroid Build Coastguard Worker             } else {
1527*ec779b8eSAndroid Build Coastguard Worker                 mMediaClock->updateAnchor(
1528*ec779b8eSAndroid Build Coastguard Worker                         mNextVideoTimeMediaUs, nowUs,
1529*ec779b8eSAndroid Build Coastguard Worker                         mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
1530*ec779b8eSAndroid Build Coastguard Worker             }
1531*ec779b8eSAndroid Build Coastguard Worker         }
1532*ec779b8eSAndroid Build Coastguard Worker     } else {
1533*ec779b8eSAndroid Build Coastguard Worker         mHasVideo = false;
1534*ec779b8eSAndroid Build Coastguard Worker     }
1535*ec779b8eSAndroid Build Coastguard Worker }
1536*ec779b8eSAndroid Build Coastguard Worker 
notifyAudioTearDown(AudioTearDownReason reason)1537*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyAudioTearDown(AudioTearDownReason reason) {
1538*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> msg = new AMessage(kWhatAudioTearDown, this);
1539*ec779b8eSAndroid Build Coastguard Worker     msg->setInt32("reason", reason);
1540*ec779b8eSAndroid Build Coastguard Worker     msg->post();
1541*ec779b8eSAndroid Build Coastguard Worker }
1542*ec779b8eSAndroid Build Coastguard Worker 
onQueueBuffer(const sp<AMessage> & msg)1543*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
1544*ec779b8eSAndroid Build Coastguard Worker     int32_t audio;
1545*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findInt32("audio", &audio));
1546*ec779b8eSAndroid Build Coastguard Worker 
1547*ec779b8eSAndroid Build Coastguard Worker     if (dropBufferIfStale(audio, msg)) {
1548*ec779b8eSAndroid Build Coastguard Worker         return;
1549*ec779b8eSAndroid Build Coastguard Worker     }
1550*ec779b8eSAndroid Build Coastguard Worker 
1551*ec779b8eSAndroid Build Coastguard Worker     if (audio) {
1552*ec779b8eSAndroid Build Coastguard Worker         mHasAudio = true;
1553*ec779b8eSAndroid Build Coastguard Worker     } else {
1554*ec779b8eSAndroid Build Coastguard Worker         mHasVideo = true;
1555*ec779b8eSAndroid Build Coastguard Worker     }
1556*ec779b8eSAndroid Build Coastguard Worker 
1557*ec779b8eSAndroid Build Coastguard Worker     if (mHasVideo) {
1558*ec779b8eSAndroid Build Coastguard Worker         if (mVideoScheduler == NULL) {
1559*ec779b8eSAndroid Build Coastguard Worker             mVideoScheduler = new VideoFrameScheduler();
1560*ec779b8eSAndroid Build Coastguard Worker             mVideoScheduler->init();
1561*ec779b8eSAndroid Build Coastguard Worker         }
1562*ec779b8eSAndroid Build Coastguard Worker     }
1563*ec779b8eSAndroid Build Coastguard Worker 
1564*ec779b8eSAndroid Build Coastguard Worker     sp<RefBase> obj;
1565*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findObject("buffer", &obj));
1566*ec779b8eSAndroid Build Coastguard Worker     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
1567*ec779b8eSAndroid Build Coastguard Worker 
1568*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notifyConsumed;
1569*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
1570*ec779b8eSAndroid Build Coastguard Worker 
1571*ec779b8eSAndroid Build Coastguard Worker     QueueEntry entry;
1572*ec779b8eSAndroid Build Coastguard Worker     entry.mBuffer = buffer;
1573*ec779b8eSAndroid Build Coastguard Worker     entry.mNotifyConsumed = notifyConsumed;
1574*ec779b8eSAndroid Build Coastguard Worker     entry.mOffset = 0;
1575*ec779b8eSAndroid Build Coastguard Worker     entry.mFinalResult = OK;
1576*ec779b8eSAndroid Build Coastguard Worker     entry.mBufferOrdinal = ++mTotalBuffersQueued;
1577*ec779b8eSAndroid Build Coastguard Worker 
1578*ec779b8eSAndroid Build Coastguard Worker     if (audio) {
1579*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1580*ec779b8eSAndroid Build Coastguard Worker         mAudioQueue.push_back(entry);
1581*ec779b8eSAndroid Build Coastguard Worker         postDrainAudioQueue_l();
1582*ec779b8eSAndroid Build Coastguard Worker     } else {
1583*ec779b8eSAndroid Build Coastguard Worker         mVideoQueue.push_back(entry);
1584*ec779b8eSAndroid Build Coastguard Worker         postDrainVideoQueue();
1585*ec779b8eSAndroid Build Coastguard Worker     }
1586*ec779b8eSAndroid Build Coastguard Worker 
1587*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1588*ec779b8eSAndroid Build Coastguard Worker     if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
1589*ec779b8eSAndroid Build Coastguard Worker         return;
1590*ec779b8eSAndroid Build Coastguard Worker     }
1591*ec779b8eSAndroid Build Coastguard Worker 
1592*ec779b8eSAndroid Build Coastguard Worker     sp<MediaCodecBuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
1593*ec779b8eSAndroid Build Coastguard Worker     sp<MediaCodecBuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
1594*ec779b8eSAndroid Build Coastguard Worker 
1595*ec779b8eSAndroid Build Coastguard Worker     if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
1596*ec779b8eSAndroid Build Coastguard Worker         // EOS signalled on either queue.
1597*ec779b8eSAndroid Build Coastguard Worker         syncQueuesDone_l();
1598*ec779b8eSAndroid Build Coastguard Worker         return;
1599*ec779b8eSAndroid Build Coastguard Worker     }
1600*ec779b8eSAndroid Build Coastguard Worker 
1601*ec779b8eSAndroid Build Coastguard Worker     int64_t firstAudioTimeUs;
1602*ec779b8eSAndroid Build Coastguard Worker     int64_t firstVideoTimeUs;
1603*ec779b8eSAndroid Build Coastguard Worker     CHECK(firstAudioBuffer->meta()
1604*ec779b8eSAndroid Build Coastguard Worker             ->findInt64("timeUs", &firstAudioTimeUs));
1605*ec779b8eSAndroid Build Coastguard Worker     CHECK(firstVideoBuffer->meta()
1606*ec779b8eSAndroid Build Coastguard Worker             ->findInt64("timeUs", &firstVideoTimeUs));
1607*ec779b8eSAndroid Build Coastguard Worker 
1608*ec779b8eSAndroid Build Coastguard Worker     int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
1609*ec779b8eSAndroid Build Coastguard Worker 
1610*ec779b8eSAndroid Build Coastguard Worker     ALOGV("queueDiff = %.2f secs", diff / 1E6);
1611*ec779b8eSAndroid Build Coastguard Worker 
1612*ec779b8eSAndroid Build Coastguard Worker     if (diff > 100000LL) {
1613*ec779b8eSAndroid Build Coastguard Worker         // Audio data starts More than 0.1 secs before video.
1614*ec779b8eSAndroid Build Coastguard Worker         // Drop some audio.
1615*ec779b8eSAndroid Build Coastguard Worker 
1616*ec779b8eSAndroid Build Coastguard Worker         (*mAudioQueue.begin()).mNotifyConsumed->post();
1617*ec779b8eSAndroid Build Coastguard Worker         mAudioQueue.erase(mAudioQueue.begin());
1618*ec779b8eSAndroid Build Coastguard Worker         return;
1619*ec779b8eSAndroid Build Coastguard Worker     }
1620*ec779b8eSAndroid Build Coastguard Worker 
1621*ec779b8eSAndroid Build Coastguard Worker     syncQueuesDone_l();
1622*ec779b8eSAndroid Build Coastguard Worker }
1623*ec779b8eSAndroid Build Coastguard Worker 
syncQueuesDone_l()1624*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::syncQueuesDone_l() {
1625*ec779b8eSAndroid Build Coastguard Worker     if (!mSyncQueues) {
1626*ec779b8eSAndroid Build Coastguard Worker         return;
1627*ec779b8eSAndroid Build Coastguard Worker     }
1628*ec779b8eSAndroid Build Coastguard Worker 
1629*ec779b8eSAndroid Build Coastguard Worker     mSyncQueues = false;
1630*ec779b8eSAndroid Build Coastguard Worker 
1631*ec779b8eSAndroid Build Coastguard Worker     if (!mAudioQueue.empty()) {
1632*ec779b8eSAndroid Build Coastguard Worker         postDrainAudioQueue_l();
1633*ec779b8eSAndroid Build Coastguard Worker     }
1634*ec779b8eSAndroid Build Coastguard Worker 
1635*ec779b8eSAndroid Build Coastguard Worker     if (!mVideoQueue.empty()) {
1636*ec779b8eSAndroid Build Coastguard Worker         mLock.unlock();
1637*ec779b8eSAndroid Build Coastguard Worker         postDrainVideoQueue();
1638*ec779b8eSAndroid Build Coastguard Worker         mLock.lock();
1639*ec779b8eSAndroid Build Coastguard Worker     }
1640*ec779b8eSAndroid Build Coastguard Worker }
1641*ec779b8eSAndroid Build Coastguard Worker 
onQueueEOS(const sp<AMessage> & msg)1642*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
1643*ec779b8eSAndroid Build Coastguard Worker     int32_t audio;
1644*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findInt32("audio", &audio));
1645*ec779b8eSAndroid Build Coastguard Worker 
1646*ec779b8eSAndroid Build Coastguard Worker     if (dropBufferIfStale(audio, msg)) {
1647*ec779b8eSAndroid Build Coastguard Worker         return;
1648*ec779b8eSAndroid Build Coastguard Worker     }
1649*ec779b8eSAndroid Build Coastguard Worker 
1650*ec779b8eSAndroid Build Coastguard Worker     int32_t finalResult;
1651*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findInt32("finalResult", &finalResult));
1652*ec779b8eSAndroid Build Coastguard Worker 
1653*ec779b8eSAndroid Build Coastguard Worker     QueueEntry entry;
1654*ec779b8eSAndroid Build Coastguard Worker     entry.mOffset = 0;
1655*ec779b8eSAndroid Build Coastguard Worker     entry.mFinalResult = finalResult;
1656*ec779b8eSAndroid Build Coastguard Worker 
1657*ec779b8eSAndroid Build Coastguard Worker     if (audio) {
1658*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1659*ec779b8eSAndroid Build Coastguard Worker         if (mAudioQueue.empty() && mSyncQueues) {
1660*ec779b8eSAndroid Build Coastguard Worker             syncQueuesDone_l();
1661*ec779b8eSAndroid Build Coastguard Worker         }
1662*ec779b8eSAndroid Build Coastguard Worker         mAudioQueue.push_back(entry);
1663*ec779b8eSAndroid Build Coastguard Worker         postDrainAudioQueue_l();
1664*ec779b8eSAndroid Build Coastguard Worker     } else {
1665*ec779b8eSAndroid Build Coastguard Worker         if (mVideoQueue.empty() && getSyncQueues()) {
1666*ec779b8eSAndroid Build Coastguard Worker             Mutex::Autolock autoLock(mLock);
1667*ec779b8eSAndroid Build Coastguard Worker             syncQueuesDone_l();
1668*ec779b8eSAndroid Build Coastguard Worker         }
1669*ec779b8eSAndroid Build Coastguard Worker         mVideoQueue.push_back(entry);
1670*ec779b8eSAndroid Build Coastguard Worker         postDrainVideoQueue();
1671*ec779b8eSAndroid Build Coastguard Worker     }
1672*ec779b8eSAndroid Build Coastguard Worker }
1673*ec779b8eSAndroid Build Coastguard Worker 
onFlush(const sp<AMessage> & msg)1674*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
1675*ec779b8eSAndroid Build Coastguard Worker     int32_t audio, notifyComplete;
1676*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findInt32("audio", &audio));
1677*ec779b8eSAndroid Build Coastguard Worker 
1678*ec779b8eSAndroid Build Coastguard Worker     {
1679*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1680*ec779b8eSAndroid Build Coastguard Worker         if (audio) {
1681*ec779b8eSAndroid Build Coastguard Worker             notifyComplete = mNotifyCompleteAudio;
1682*ec779b8eSAndroid Build Coastguard Worker             mNotifyCompleteAudio = false;
1683*ec779b8eSAndroid Build Coastguard Worker             mLastAudioMediaTimeUs = -1;
1684*ec779b8eSAndroid Build Coastguard Worker 
1685*ec779b8eSAndroid Build Coastguard Worker             mHasAudio = false;
1686*ec779b8eSAndroid Build Coastguard Worker             if (mNextVideoTimeMediaUs >= 0) {
1687*ec779b8eSAndroid Build Coastguard Worker                 int64_t nowUs = ALooper::GetNowUs();
1688*ec779b8eSAndroid Build Coastguard Worker                 mMediaClock->updateAnchor(
1689*ec779b8eSAndroid Build Coastguard Worker                         mNextVideoTimeMediaUs, nowUs,
1690*ec779b8eSAndroid Build Coastguard Worker                         mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
1691*ec779b8eSAndroid Build Coastguard Worker             }
1692*ec779b8eSAndroid Build Coastguard Worker         } else {
1693*ec779b8eSAndroid Build Coastguard Worker             notifyComplete = mNotifyCompleteVideo;
1694*ec779b8eSAndroid Build Coastguard Worker             mNotifyCompleteVideo = false;
1695*ec779b8eSAndroid Build Coastguard Worker             mHasVideo = false;
1696*ec779b8eSAndroid Build Coastguard Worker         }
1697*ec779b8eSAndroid Build Coastguard Worker 
1698*ec779b8eSAndroid Build Coastguard Worker         // If we're currently syncing the queues, i.e. dropping audio while
1699*ec779b8eSAndroid Build Coastguard Worker         // aligning the first audio/video buffer times and only one of the
1700*ec779b8eSAndroid Build Coastguard Worker         // two queues has data, we may starve that queue by not requesting
1701*ec779b8eSAndroid Build Coastguard Worker         // more buffers from the decoder. If the other source then encounters
1702*ec779b8eSAndroid Build Coastguard Worker         // a discontinuity that leads to flushing, we'll never find the
1703*ec779b8eSAndroid Build Coastguard Worker         // corresponding discontinuity on the other queue.
1704*ec779b8eSAndroid Build Coastguard Worker         // Therefore we'll stop syncing the queues if at least one of them
1705*ec779b8eSAndroid Build Coastguard Worker         // is flushed.
1706*ec779b8eSAndroid Build Coastguard Worker         syncQueuesDone_l();
1707*ec779b8eSAndroid Build Coastguard Worker     }
1708*ec779b8eSAndroid Build Coastguard Worker 
1709*ec779b8eSAndroid Build Coastguard Worker     if (audio && mDrainVideoQueuePending) {
1710*ec779b8eSAndroid Build Coastguard Worker         // Audio should not clear anchor(MediaClock) directly, because video
1711*ec779b8eSAndroid Build Coastguard Worker         // postDrainVideoQueue sets msg kWhatDrainVideoQueue into MediaClock
1712*ec779b8eSAndroid Build Coastguard Worker         // timer, clear anchor without update immediately may block msg posting.
1713*ec779b8eSAndroid Build Coastguard Worker         // So, postpone clear action to video to ensure anchor can be updated
1714*ec779b8eSAndroid Build Coastguard Worker         // immediately after clear
1715*ec779b8eSAndroid Build Coastguard Worker         mNeedVideoClearAnchor = true;
1716*ec779b8eSAndroid Build Coastguard Worker     } else {
1717*ec779b8eSAndroid Build Coastguard Worker         clearAnchorTime();
1718*ec779b8eSAndroid Build Coastguard Worker     }
1719*ec779b8eSAndroid Build Coastguard Worker 
1720*ec779b8eSAndroid Build Coastguard Worker     ALOGV("flushing %s", audio ? "audio" : "video");
1721*ec779b8eSAndroid Build Coastguard Worker     if (audio) {
1722*ec779b8eSAndroid Build Coastguard Worker         {
1723*ec779b8eSAndroid Build Coastguard Worker             Mutex::Autolock autoLock(mLock);
1724*ec779b8eSAndroid Build Coastguard Worker             flushQueue(&mAudioQueue);
1725*ec779b8eSAndroid Build Coastguard Worker 
1726*ec779b8eSAndroid Build Coastguard Worker             ++mAudioDrainGeneration;
1727*ec779b8eSAndroid Build Coastguard Worker             ++mAudioEOSGeneration;
1728*ec779b8eSAndroid Build Coastguard Worker             prepareForMediaRenderingStart_l();
1729*ec779b8eSAndroid Build Coastguard Worker 
1730*ec779b8eSAndroid Build Coastguard Worker             // the frame count will be reset after flush.
1731*ec779b8eSAndroid Build Coastguard Worker             clearAudioFirstAnchorTime_l();
1732*ec779b8eSAndroid Build Coastguard Worker         }
1733*ec779b8eSAndroid Build Coastguard Worker 
1734*ec779b8eSAndroid Build Coastguard Worker         mDrainAudioQueuePending = false;
1735*ec779b8eSAndroid Build Coastguard Worker 
1736*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->pause();
1737*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->flush();
1738*ec779b8eSAndroid Build Coastguard Worker         if (!offloadingAudio()) {
1739*ec779b8eSAndroid Build Coastguard Worker             // Call stop() to signal to the AudioSink to completely fill the
1740*ec779b8eSAndroid Build Coastguard Worker             // internal buffer before resuming playback.
1741*ec779b8eSAndroid Build Coastguard Worker             // FIXME: this is ignored after flush().
1742*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->stop();
1743*ec779b8eSAndroid Build Coastguard Worker             mNumFramesWritten = 0;
1744*ec779b8eSAndroid Build Coastguard Worker         }
1745*ec779b8eSAndroid Build Coastguard Worker         if (!mPaused) {
1746*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->start();
1747*ec779b8eSAndroid Build Coastguard Worker         }
1748*ec779b8eSAndroid Build Coastguard Worker         mNextAudioClockUpdateTimeUs = -1;
1749*ec779b8eSAndroid Build Coastguard Worker     } else {
1750*ec779b8eSAndroid Build Coastguard Worker         flushQueue(&mVideoQueue);
1751*ec779b8eSAndroid Build Coastguard Worker 
1752*ec779b8eSAndroid Build Coastguard Worker         mDrainVideoQueuePending = false;
1753*ec779b8eSAndroid Build Coastguard Worker 
1754*ec779b8eSAndroid Build Coastguard Worker         if (mVideoScheduler != NULL) {
1755*ec779b8eSAndroid Build Coastguard Worker             mVideoScheduler->restart();
1756*ec779b8eSAndroid Build Coastguard Worker         }
1757*ec779b8eSAndroid Build Coastguard Worker 
1758*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1759*ec779b8eSAndroid Build Coastguard Worker         ++mVideoDrainGeneration;
1760*ec779b8eSAndroid Build Coastguard Worker         prepareForMediaRenderingStart_l();
1761*ec779b8eSAndroid Build Coastguard Worker     }
1762*ec779b8eSAndroid Build Coastguard Worker 
1763*ec779b8eSAndroid Build Coastguard Worker     mVideoSampleReceived = false;
1764*ec779b8eSAndroid Build Coastguard Worker 
1765*ec779b8eSAndroid Build Coastguard Worker     if (notifyComplete) {
1766*ec779b8eSAndroid Build Coastguard Worker         notifyFlushComplete(audio);
1767*ec779b8eSAndroid Build Coastguard Worker     }
1768*ec779b8eSAndroid Build Coastguard Worker }
1769*ec779b8eSAndroid Build Coastguard Worker 
flushQueue(List<QueueEntry> * queue)1770*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
1771*ec779b8eSAndroid Build Coastguard Worker     while (!queue->empty()) {
1772*ec779b8eSAndroid Build Coastguard Worker         QueueEntry *entry = &*queue->begin();
1773*ec779b8eSAndroid Build Coastguard Worker 
1774*ec779b8eSAndroid Build Coastguard Worker         if (entry->mBuffer != NULL) {
1775*ec779b8eSAndroid Build Coastguard Worker             entry->mNotifyConsumed->post();
1776*ec779b8eSAndroid Build Coastguard Worker         } else if (entry->mNotifyConsumed != nullptr) {
1777*ec779b8eSAndroid Build Coastguard Worker             // Is it needed to open audio sink now?
1778*ec779b8eSAndroid Build Coastguard Worker             onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
1779*ec779b8eSAndroid Build Coastguard Worker         }
1780*ec779b8eSAndroid Build Coastguard Worker 
1781*ec779b8eSAndroid Build Coastguard Worker         queue->erase(queue->begin());
1782*ec779b8eSAndroid Build Coastguard Worker         entry = NULL;
1783*ec779b8eSAndroid Build Coastguard Worker     }
1784*ec779b8eSAndroid Build Coastguard Worker }
1785*ec779b8eSAndroid Build Coastguard Worker 
notifyFlushComplete(bool audio)1786*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
1787*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notify = mNotify->dup();
1788*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("what", kWhatFlushComplete);
1789*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("audio", static_cast<int32_t>(audio));
1790*ec779b8eSAndroid Build Coastguard Worker     notify->post();
1791*ec779b8eSAndroid Build Coastguard Worker }
1792*ec779b8eSAndroid Build Coastguard Worker 
dropBufferIfStale(bool audio,const sp<AMessage> & msg)1793*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::Renderer::dropBufferIfStale(
1794*ec779b8eSAndroid Build Coastguard Worker         bool audio, const sp<AMessage> &msg) {
1795*ec779b8eSAndroid Build Coastguard Worker     int32_t queueGeneration;
1796*ec779b8eSAndroid Build Coastguard Worker     CHECK(msg->findInt32("queueGeneration", &queueGeneration));
1797*ec779b8eSAndroid Build Coastguard Worker 
1798*ec779b8eSAndroid Build Coastguard Worker     if (queueGeneration == getQueueGeneration(audio)) {
1799*ec779b8eSAndroid Build Coastguard Worker         return false;
1800*ec779b8eSAndroid Build Coastguard Worker     }
1801*ec779b8eSAndroid Build Coastguard Worker 
1802*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notifyConsumed;
1803*ec779b8eSAndroid Build Coastguard Worker     if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
1804*ec779b8eSAndroid Build Coastguard Worker         notifyConsumed->post();
1805*ec779b8eSAndroid Build Coastguard Worker     }
1806*ec779b8eSAndroid Build Coastguard Worker 
1807*ec779b8eSAndroid Build Coastguard Worker     return true;
1808*ec779b8eSAndroid Build Coastguard Worker }
1809*ec779b8eSAndroid Build Coastguard Worker 
onAudioSinkChanged()1810*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onAudioSinkChanged() {
1811*ec779b8eSAndroid Build Coastguard Worker     if (offloadingAudio()) {
1812*ec779b8eSAndroid Build Coastguard Worker         return;
1813*ec779b8eSAndroid Build Coastguard Worker     }
1814*ec779b8eSAndroid Build Coastguard Worker     CHECK(!mDrainAudioQueuePending);
1815*ec779b8eSAndroid Build Coastguard Worker     mNumFramesWritten = 0;
1816*ec779b8eSAndroid Build Coastguard Worker     mAnchorNumFramesWritten = -1;
1817*ec779b8eSAndroid Build Coastguard Worker     uint32_t written;
1818*ec779b8eSAndroid Build Coastguard Worker     if (mAudioSink->getFramesWritten(&written) == OK) {
1819*ec779b8eSAndroid Build Coastguard Worker         mNumFramesWritten = written;
1820*ec779b8eSAndroid Build Coastguard Worker     }
1821*ec779b8eSAndroid Build Coastguard Worker }
1822*ec779b8eSAndroid Build Coastguard Worker 
onDisableOffloadAudio()1823*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onDisableOffloadAudio() {
1824*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1825*ec779b8eSAndroid Build Coastguard Worker     mFlags &= ~FLAG_OFFLOAD_AUDIO;
1826*ec779b8eSAndroid Build Coastguard Worker     ++mAudioDrainGeneration;
1827*ec779b8eSAndroid Build Coastguard Worker     if (mAudioRenderingStartGeneration != -1) {
1828*ec779b8eSAndroid Build Coastguard Worker         prepareForMediaRenderingStart_l();
1829*ec779b8eSAndroid Build Coastguard Worker         // PauseTimeout is applied to offload mode only. Cancel pending timer.
1830*ec779b8eSAndroid Build Coastguard Worker         cancelAudioOffloadPauseTimeout();
1831*ec779b8eSAndroid Build Coastguard Worker     }
1832*ec779b8eSAndroid Build Coastguard Worker }
1833*ec779b8eSAndroid Build Coastguard Worker 
onEnableOffloadAudio()1834*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onEnableOffloadAudio() {
1835*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1836*ec779b8eSAndroid Build Coastguard Worker     mFlags |= FLAG_OFFLOAD_AUDIO;
1837*ec779b8eSAndroid Build Coastguard Worker     ++mAudioDrainGeneration;
1838*ec779b8eSAndroid Build Coastguard Worker     if (mAudioRenderingStartGeneration != -1) {
1839*ec779b8eSAndroid Build Coastguard Worker         prepareForMediaRenderingStart_l();
1840*ec779b8eSAndroid Build Coastguard Worker     }
1841*ec779b8eSAndroid Build Coastguard Worker }
1842*ec779b8eSAndroid Build Coastguard Worker 
onPause()1843*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onPause() {
1844*ec779b8eSAndroid Build Coastguard Worker     if (mPaused) {
1845*ec779b8eSAndroid Build Coastguard Worker         return;
1846*ec779b8eSAndroid Build Coastguard Worker     }
1847*ec779b8eSAndroid Build Coastguard Worker 
1848*ec779b8eSAndroid Build Coastguard Worker     startAudioOffloadPauseTimeout();
1849*ec779b8eSAndroid Build Coastguard Worker 
1850*ec779b8eSAndroid Build Coastguard Worker     {
1851*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1852*ec779b8eSAndroid Build Coastguard Worker         // we do not increment audio drain generation so that we fill audio buffer during pause.
1853*ec779b8eSAndroid Build Coastguard Worker         ++mVideoDrainGeneration;
1854*ec779b8eSAndroid Build Coastguard Worker         prepareForMediaRenderingStart_l();
1855*ec779b8eSAndroid Build Coastguard Worker         mPaused = true;
1856*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->setPlaybackRate(0.0);
1857*ec779b8eSAndroid Build Coastguard Worker     }
1858*ec779b8eSAndroid Build Coastguard Worker 
1859*ec779b8eSAndroid Build Coastguard Worker     mDrainAudioQueuePending = false;
1860*ec779b8eSAndroid Build Coastguard Worker     mDrainVideoQueuePending = false;
1861*ec779b8eSAndroid Build Coastguard Worker 
1862*ec779b8eSAndroid Build Coastguard Worker     // Note: audio data may not have been decoded, and the AudioSink may not be opened.
1863*ec779b8eSAndroid Build Coastguard Worker     mAudioSink->pause();
1864*ec779b8eSAndroid Build Coastguard Worker 
1865*ec779b8eSAndroid Build Coastguard Worker     ALOGV("now paused audio queue has %zu entries, video has %zu entries",
1866*ec779b8eSAndroid Build Coastguard Worker           mAudioQueue.size(), mVideoQueue.size());
1867*ec779b8eSAndroid Build Coastguard Worker }
1868*ec779b8eSAndroid Build Coastguard Worker 
onResume()1869*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onResume() {
1870*ec779b8eSAndroid Build Coastguard Worker     if (!mPaused) {
1871*ec779b8eSAndroid Build Coastguard Worker         return;
1872*ec779b8eSAndroid Build Coastguard Worker     }
1873*ec779b8eSAndroid Build Coastguard Worker 
1874*ec779b8eSAndroid Build Coastguard Worker     // Note: audio data may not have been decoded, and the AudioSink may not be opened.
1875*ec779b8eSAndroid Build Coastguard Worker     cancelAudioOffloadPauseTimeout();
1876*ec779b8eSAndroid Build Coastguard Worker     if (mAudioSink->ready()) {
1877*ec779b8eSAndroid Build Coastguard Worker         status_t err = mAudioSink->start();
1878*ec779b8eSAndroid Build Coastguard Worker         if (err != OK) {
1879*ec779b8eSAndroid Build Coastguard Worker             ALOGE("cannot start AudioSink err %d", err);
1880*ec779b8eSAndroid Build Coastguard Worker             notifyAudioTearDown(kDueToError);
1881*ec779b8eSAndroid Build Coastguard Worker         }
1882*ec779b8eSAndroid Build Coastguard Worker     }
1883*ec779b8eSAndroid Build Coastguard Worker 
1884*ec779b8eSAndroid Build Coastguard Worker     {
1885*ec779b8eSAndroid Build Coastguard Worker         Mutex::Autolock autoLock(mLock);
1886*ec779b8eSAndroid Build Coastguard Worker         mPaused = false;
1887*ec779b8eSAndroid Build Coastguard Worker         // rendering started message may have been delayed if we were paused.
1888*ec779b8eSAndroid Build Coastguard Worker         if (mRenderingDataDelivered) {
1889*ec779b8eSAndroid Build Coastguard Worker             notifyIfMediaRenderingStarted_l();
1890*ec779b8eSAndroid Build Coastguard Worker         }
1891*ec779b8eSAndroid Build Coastguard Worker         // configure audiosink as we did not do it when pausing
1892*ec779b8eSAndroid Build Coastguard Worker         if (mAudioSink != NULL && mAudioSink->ready()) {
1893*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->setPlaybackRate(mPlaybackSettings);
1894*ec779b8eSAndroid Build Coastguard Worker         }
1895*ec779b8eSAndroid Build Coastguard Worker 
1896*ec779b8eSAndroid Build Coastguard Worker         mMediaClock->setPlaybackRate(mPlaybackRate);
1897*ec779b8eSAndroid Build Coastguard Worker 
1898*ec779b8eSAndroid Build Coastguard Worker         if (!mAudioQueue.empty()) {
1899*ec779b8eSAndroid Build Coastguard Worker             postDrainAudioQueue_l();
1900*ec779b8eSAndroid Build Coastguard Worker         }
1901*ec779b8eSAndroid Build Coastguard Worker     }
1902*ec779b8eSAndroid Build Coastguard Worker 
1903*ec779b8eSAndroid Build Coastguard Worker     if (!mVideoQueue.empty()) {
1904*ec779b8eSAndroid Build Coastguard Worker         postDrainVideoQueue();
1905*ec779b8eSAndroid Build Coastguard Worker     }
1906*ec779b8eSAndroid Build Coastguard Worker }
1907*ec779b8eSAndroid Build Coastguard Worker 
onSetVideoFrameRate(float fps)1908*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onSetVideoFrameRate(float fps) {
1909*ec779b8eSAndroid Build Coastguard Worker     if (mVideoScheduler == NULL) {
1910*ec779b8eSAndroid Build Coastguard Worker         mVideoScheduler = new VideoFrameScheduler();
1911*ec779b8eSAndroid Build Coastguard Worker     }
1912*ec779b8eSAndroid Build Coastguard Worker     mVideoScheduler->init(fps);
1913*ec779b8eSAndroid Build Coastguard Worker }
1914*ec779b8eSAndroid Build Coastguard Worker 
getQueueGeneration(bool audio)1915*ec779b8eSAndroid Build Coastguard Worker int32_t NuPlayer::Renderer::getQueueGeneration(bool audio) {
1916*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1917*ec779b8eSAndroid Build Coastguard Worker     return (audio ? mAudioQueueGeneration : mVideoQueueGeneration);
1918*ec779b8eSAndroid Build Coastguard Worker }
1919*ec779b8eSAndroid Build Coastguard Worker 
getDrainGeneration(bool audio)1920*ec779b8eSAndroid Build Coastguard Worker int32_t NuPlayer::Renderer::getDrainGeneration(bool audio) {
1921*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1922*ec779b8eSAndroid Build Coastguard Worker     return (audio ? mAudioDrainGeneration : mVideoDrainGeneration);
1923*ec779b8eSAndroid Build Coastguard Worker }
1924*ec779b8eSAndroid Build Coastguard Worker 
getSyncQueues()1925*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::Renderer::getSyncQueues() {
1926*ec779b8eSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mLock);
1927*ec779b8eSAndroid Build Coastguard Worker     return mSyncQueues;
1928*ec779b8eSAndroid Build Coastguard Worker }
1929*ec779b8eSAndroid Build Coastguard Worker 
onAudioTearDown(AudioTearDownReason reason)1930*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) {
1931*ec779b8eSAndroid Build Coastguard Worker     if (mAudioTornDown) {
1932*ec779b8eSAndroid Build Coastguard Worker         return;
1933*ec779b8eSAndroid Build Coastguard Worker     }
1934*ec779b8eSAndroid Build Coastguard Worker 
1935*ec779b8eSAndroid Build Coastguard Worker     // TimeoutWhenPaused is only for offload mode.
1936*ec779b8eSAndroid Build Coastguard Worker     if (reason == kDueToTimeout && !offloadingAudio()) {
1937*ec779b8eSAndroid Build Coastguard Worker         return;
1938*ec779b8eSAndroid Build Coastguard Worker     }
1939*ec779b8eSAndroid Build Coastguard Worker 
1940*ec779b8eSAndroid Build Coastguard Worker     mAudioTornDown = true;
1941*ec779b8eSAndroid Build Coastguard Worker 
1942*ec779b8eSAndroid Build Coastguard Worker     int64_t currentPositionUs;
1943*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> notify = mNotify->dup();
1944*ec779b8eSAndroid Build Coastguard Worker     if (getCurrentPosition(&currentPositionUs) == OK) {
1945*ec779b8eSAndroid Build Coastguard Worker         notify->setInt64("positionUs", currentPositionUs);
1946*ec779b8eSAndroid Build Coastguard Worker     }
1947*ec779b8eSAndroid Build Coastguard Worker 
1948*ec779b8eSAndroid Build Coastguard Worker     mAudioSink->stop();
1949*ec779b8eSAndroid Build Coastguard Worker     mAudioSink->flush();
1950*ec779b8eSAndroid Build Coastguard Worker 
1951*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("what", kWhatAudioTearDown);
1952*ec779b8eSAndroid Build Coastguard Worker     notify->setInt32("reason", reason);
1953*ec779b8eSAndroid Build Coastguard Worker     notify->post();
1954*ec779b8eSAndroid Build Coastguard Worker }
1955*ec779b8eSAndroid Build Coastguard Worker 
startAudioOffloadPauseTimeout()1956*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {
1957*ec779b8eSAndroid Build Coastguard Worker     if (offloadingAudio()) {
1958*ec779b8eSAndroid Build Coastguard Worker         mWakeLock->acquire();
1959*ec779b8eSAndroid Build Coastguard Worker         mWakelockAcquireEvent.updateValues(uptimeMillis(),
1960*ec779b8eSAndroid Build Coastguard Worker                                            mAudioOffloadPauseTimeoutGeneration,
1961*ec779b8eSAndroid Build Coastguard Worker                                            mAudioOffloadPauseTimeoutGeneration);
1962*ec779b8eSAndroid Build Coastguard Worker         sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, this);
1963*ec779b8eSAndroid Build Coastguard Worker         msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration);
1964*ec779b8eSAndroid Build Coastguard Worker         msg->post(kOffloadPauseMaxUs);
1965*ec779b8eSAndroid Build Coastguard Worker     }
1966*ec779b8eSAndroid Build Coastguard Worker }
1967*ec779b8eSAndroid Build Coastguard Worker 
cancelAudioOffloadPauseTimeout()1968*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() {
1969*ec779b8eSAndroid Build Coastguard Worker     // We may have called startAudioOffloadPauseTimeout() without
1970*ec779b8eSAndroid Build Coastguard Worker     // the AudioSink open and with offloadingAudio enabled.
1971*ec779b8eSAndroid Build Coastguard Worker     //
1972*ec779b8eSAndroid Build Coastguard Worker     // When we cancel, it may be that offloadingAudio is subsequently disabled, so regardless
1973*ec779b8eSAndroid Build Coastguard Worker     // we always release the wakelock and increment the pause timeout generation.
1974*ec779b8eSAndroid Build Coastguard Worker     //
1975*ec779b8eSAndroid Build Coastguard Worker     // Note: The acquired wakelock prevents the device from suspending
1976*ec779b8eSAndroid Build Coastguard Worker     // immediately after offload pause (in case a resume happens shortly thereafter).
1977*ec779b8eSAndroid Build Coastguard Worker     mWakeLock->release(true);
1978*ec779b8eSAndroid Build Coastguard Worker     mWakelockCancelEvent.updateValues(uptimeMillis(),
1979*ec779b8eSAndroid Build Coastguard Worker                                       mAudioOffloadPauseTimeoutGeneration,
1980*ec779b8eSAndroid Build Coastguard Worker                                       mAudioOffloadPauseTimeoutGeneration);
1981*ec779b8eSAndroid Build Coastguard Worker     ++mAudioOffloadPauseTimeoutGeneration;
1982*ec779b8eSAndroid Build Coastguard Worker }
1983*ec779b8eSAndroid Build Coastguard Worker 
onOpenAudioSink(const sp<AMessage> & format,bool offloadOnly,bool hasVideo,uint32_t flags,bool isStreaming)1984*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::Renderer::onOpenAudioSink(
1985*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &format,
1986*ec779b8eSAndroid Build Coastguard Worker         bool offloadOnly,
1987*ec779b8eSAndroid Build Coastguard Worker         bool hasVideo,
1988*ec779b8eSAndroid Build Coastguard Worker         uint32_t flags,
1989*ec779b8eSAndroid Build Coastguard Worker         bool isStreaming) {
1990*ec779b8eSAndroid Build Coastguard Worker     ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
1991*ec779b8eSAndroid Build Coastguard Worker             offloadOnly, offloadingAudio());
1992*ec779b8eSAndroid Build Coastguard Worker     ATRACE_BEGIN(StringPrintf("NuPlayer::Renderer::onOpenAudioSink: offloadOnly(%d) "
1993*ec779b8eSAndroid Build Coastguard Worker             "offloadingAudio(%d)", offloadOnly, offloadingAudio()).c_str());
1994*ec779b8eSAndroid Build Coastguard Worker     bool audioSinkChanged = false;
1995*ec779b8eSAndroid Build Coastguard Worker 
1996*ec779b8eSAndroid Build Coastguard Worker     int32_t numChannels;
1997*ec779b8eSAndroid Build Coastguard Worker     CHECK(format->findInt32("channel-count", &numChannels));
1998*ec779b8eSAndroid Build Coastguard Worker 
1999*ec779b8eSAndroid Build Coastguard Worker     // channel mask info as read from the audio format
2000*ec779b8eSAndroid Build Coastguard Worker     int32_t mediaFormatChannelMask;
2001*ec779b8eSAndroid Build Coastguard Worker     // channel mask to use for native playback
2002*ec779b8eSAndroid Build Coastguard Worker     audio_channel_mask_t channelMask;
2003*ec779b8eSAndroid Build Coastguard Worker     if (format->findInt32("channel-mask", &mediaFormatChannelMask)) {
2004*ec779b8eSAndroid Build Coastguard Worker         // KEY_CHANNEL_MASK follows the android.media.AudioFormat java mask
2005*ec779b8eSAndroid Build Coastguard Worker         channelMask = audio_channel_mask_from_media_format_mask(mediaFormatChannelMask);
2006*ec779b8eSAndroid Build Coastguard Worker     } else {
2007*ec779b8eSAndroid Build Coastguard Worker         // no mask found: the mask will be derived from the channel count
2008*ec779b8eSAndroid Build Coastguard Worker         channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
2009*ec779b8eSAndroid Build Coastguard Worker     }
2010*ec779b8eSAndroid Build Coastguard Worker 
2011*ec779b8eSAndroid Build Coastguard Worker     int32_t sampleRate;
2012*ec779b8eSAndroid Build Coastguard Worker     CHECK(format->findInt32("sample-rate", &sampleRate));
2013*ec779b8eSAndroid Build Coastguard Worker 
2014*ec779b8eSAndroid Build Coastguard Worker     // read pcm encoding from MediaCodec output format, if available
2015*ec779b8eSAndroid Build Coastguard Worker     int32_t pcmEncoding;
2016*ec779b8eSAndroid Build Coastguard Worker     audio_format_t audioFormat =
2017*ec779b8eSAndroid Build Coastguard Worker             format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
2018*ec779b8eSAndroid Build Coastguard Worker                     audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
2019*ec779b8eSAndroid Build Coastguard Worker 
2020*ec779b8eSAndroid Build Coastguard Worker     if (offloadingAudio()) {
2021*ec779b8eSAndroid Build Coastguard Worker         AString mime;
2022*ec779b8eSAndroid Build Coastguard Worker         CHECK(format->findString("mime", &mime));
2023*ec779b8eSAndroid Build Coastguard Worker         status_t err = OK;
2024*ec779b8eSAndroid Build Coastguard Worker         if (audioFormat == AUDIO_FORMAT_PCM_16_BIT) {
2025*ec779b8eSAndroid Build Coastguard Worker             // If there is probably no pcm-encoding in the format message, try to get the format by
2026*ec779b8eSAndroid Build Coastguard Worker             // its mimetype.
2027*ec779b8eSAndroid Build Coastguard Worker             err = mapMimeToAudioFormat(audioFormat, mime.c_str());
2028*ec779b8eSAndroid Build Coastguard Worker         }
2029*ec779b8eSAndroid Build Coastguard Worker 
2030*ec779b8eSAndroid Build Coastguard Worker         if (err != OK) {
2031*ec779b8eSAndroid Build Coastguard Worker             ALOGE("Couldn't map mime \"%s\" to a valid "
2032*ec779b8eSAndroid Build Coastguard Worker                     "audio_format", mime.c_str());
2033*ec779b8eSAndroid Build Coastguard Worker             onDisableOffloadAudio();
2034*ec779b8eSAndroid Build Coastguard Worker         } else {
2035*ec779b8eSAndroid Build Coastguard Worker             ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
2036*ec779b8eSAndroid Build Coastguard Worker                     mime.c_str(), audioFormat);
2037*ec779b8eSAndroid Build Coastguard Worker 
2038*ec779b8eSAndroid Build Coastguard Worker             int avgBitRate = 0;
2039*ec779b8eSAndroid Build Coastguard Worker             format->findInt32("bitrate", &avgBitRate);
2040*ec779b8eSAndroid Build Coastguard Worker 
2041*ec779b8eSAndroid Build Coastguard Worker             int32_t aacProfile = -1;
2042*ec779b8eSAndroid Build Coastguard Worker             if (audioFormat == AUDIO_FORMAT_AAC
2043*ec779b8eSAndroid Build Coastguard Worker                     && format->findInt32("aac-profile", &aacProfile)) {
2044*ec779b8eSAndroid Build Coastguard Worker                 // Redefine AAC format as per aac profile
2045*ec779b8eSAndroid Build Coastguard Worker                 mapAACProfileToAudioFormat(
2046*ec779b8eSAndroid Build Coastguard Worker                         audioFormat,
2047*ec779b8eSAndroid Build Coastguard Worker                         aacProfile);
2048*ec779b8eSAndroid Build Coastguard Worker             }
2049*ec779b8eSAndroid Build Coastguard Worker 
2050*ec779b8eSAndroid Build Coastguard Worker             audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
2051*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.duration_us = -1;
2052*ec779b8eSAndroid Build Coastguard Worker             format->findInt64(
2053*ec779b8eSAndroid Build Coastguard Worker                     "durationUs", &offloadInfo.duration_us);
2054*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.sample_rate = sampleRate;
2055*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.channel_mask = channelMask;
2056*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.format = audioFormat;
2057*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
2058*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.bit_rate = avgBitRate;
2059*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.has_video = hasVideo;
2060*ec779b8eSAndroid Build Coastguard Worker             offloadInfo.is_streaming = isStreaming;
2061*ec779b8eSAndroid Build Coastguard Worker 
2062*ec779b8eSAndroid Build Coastguard Worker             if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
2063*ec779b8eSAndroid Build Coastguard Worker                 ALOGV("openAudioSink: no change in offload mode");
2064*ec779b8eSAndroid Build Coastguard Worker                 // no change from previous configuration, everything ok.
2065*ec779b8eSAndroid Build Coastguard Worker                 ATRACE_END();
2066*ec779b8eSAndroid Build Coastguard Worker                 return OK;
2067*ec779b8eSAndroid Build Coastguard Worker             }
2068*ec779b8eSAndroid Build Coastguard Worker             mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
2069*ec779b8eSAndroid Build Coastguard Worker 
2070*ec779b8eSAndroid Build Coastguard Worker             ALOGV("openAudioSink: try to open AudioSink in offload mode");
2071*ec779b8eSAndroid Build Coastguard Worker             uint32_t offloadFlags = flags;
2072*ec779b8eSAndroid Build Coastguard Worker             offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
2073*ec779b8eSAndroid Build Coastguard Worker             offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
2074*ec779b8eSAndroid Build Coastguard Worker             audioSinkChanged = true;
2075*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->close();
2076*ec779b8eSAndroid Build Coastguard Worker 
2077*ec779b8eSAndroid Build Coastguard Worker             err = mAudioSink->open(
2078*ec779b8eSAndroid Build Coastguard Worker                     sampleRate,
2079*ec779b8eSAndroid Build Coastguard Worker                     numChannels,
2080*ec779b8eSAndroid Build Coastguard Worker                     (audio_channel_mask_t)channelMask,
2081*ec779b8eSAndroid Build Coastguard Worker                     audioFormat,
2082*ec779b8eSAndroid Build Coastguard Worker                     0 /* bufferCount - unused */,
2083*ec779b8eSAndroid Build Coastguard Worker                     &NuPlayer::Renderer::AudioSinkCallback,
2084*ec779b8eSAndroid Build Coastguard Worker                     this,
2085*ec779b8eSAndroid Build Coastguard Worker                     (audio_output_flags_t)offloadFlags,
2086*ec779b8eSAndroid Build Coastguard Worker                     &offloadInfo);
2087*ec779b8eSAndroid Build Coastguard Worker 
2088*ec779b8eSAndroid Build Coastguard Worker             if (err == OK) {
2089*ec779b8eSAndroid Build Coastguard Worker                 err = mAudioSink->setPlaybackRate(mPlaybackSettings);
2090*ec779b8eSAndroid Build Coastguard Worker             }
2091*ec779b8eSAndroid Build Coastguard Worker 
2092*ec779b8eSAndroid Build Coastguard Worker             if (err == OK) {
2093*ec779b8eSAndroid Build Coastguard Worker                 // If the playback is offloaded to h/w, we pass
2094*ec779b8eSAndroid Build Coastguard Worker                 // the HAL some metadata information.
2095*ec779b8eSAndroid Build Coastguard Worker                 // We don't want to do this for PCM because it
2096*ec779b8eSAndroid Build Coastguard Worker                 // will be going through the AudioFlinger mixer
2097*ec779b8eSAndroid Build Coastguard Worker                 // before reaching the hardware.
2098*ec779b8eSAndroid Build Coastguard Worker                 // TODO
2099*ec779b8eSAndroid Build Coastguard Worker                 mCurrentOffloadInfo = offloadInfo;
2100*ec779b8eSAndroid Build Coastguard Worker                 if (!mPaused) { // for preview mode, don't start if paused
2101*ec779b8eSAndroid Build Coastguard Worker                     err = mAudioSink->start();
2102*ec779b8eSAndroid Build Coastguard Worker                 }
2103*ec779b8eSAndroid Build Coastguard Worker                 ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
2104*ec779b8eSAndroid Build Coastguard Worker             }
2105*ec779b8eSAndroid Build Coastguard Worker             if (err != OK) {
2106*ec779b8eSAndroid Build Coastguard Worker                 // Clean up, fall back to non offload mode.
2107*ec779b8eSAndroid Build Coastguard Worker                 mAudioSink->close();
2108*ec779b8eSAndroid Build Coastguard Worker                 onDisableOffloadAudio();
2109*ec779b8eSAndroid Build Coastguard Worker                 mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
2110*ec779b8eSAndroid Build Coastguard Worker                 ALOGV("openAudioSink: offload failed");
2111*ec779b8eSAndroid Build Coastguard Worker                 if (offloadOnly) {
2112*ec779b8eSAndroid Build Coastguard Worker                     notifyAudioTearDown(kForceNonOffload);
2113*ec779b8eSAndroid Build Coastguard Worker                 }
2114*ec779b8eSAndroid Build Coastguard Worker             } else {
2115*ec779b8eSAndroid Build Coastguard Worker                 mUseAudioCallback = true;  // offload mode transfers data through callback
2116*ec779b8eSAndroid Build Coastguard Worker                 ++mAudioDrainGeneration;  // discard pending kWhatDrainAudioQueue message.
2117*ec779b8eSAndroid Build Coastguard Worker             }
2118*ec779b8eSAndroid Build Coastguard Worker         }
2119*ec779b8eSAndroid Build Coastguard Worker     }
2120*ec779b8eSAndroid Build Coastguard Worker     if (!offloadOnly && !offloadingAudio()) {
2121*ec779b8eSAndroid Build Coastguard Worker         ALOGV("openAudioSink: open AudioSink in NON-offload mode");
2122*ec779b8eSAndroid Build Coastguard Worker         uint32_t pcmFlags = flags;
2123*ec779b8eSAndroid Build Coastguard Worker         pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
2124*ec779b8eSAndroid Build Coastguard Worker 
2125*ec779b8eSAndroid Build Coastguard Worker         const PcmInfo info = {
2126*ec779b8eSAndroid Build Coastguard Worker                 (audio_channel_mask_t)channelMask,
2127*ec779b8eSAndroid Build Coastguard Worker                 (audio_output_flags_t)pcmFlags,
2128*ec779b8eSAndroid Build Coastguard Worker                 audioFormat,
2129*ec779b8eSAndroid Build Coastguard Worker                 numChannels,
2130*ec779b8eSAndroid Build Coastguard Worker                 sampleRate
2131*ec779b8eSAndroid Build Coastguard Worker         };
2132*ec779b8eSAndroid Build Coastguard Worker         if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
2133*ec779b8eSAndroid Build Coastguard Worker             ALOGV("openAudioSink: no change in pcm mode");
2134*ec779b8eSAndroid Build Coastguard Worker             // no change from previous configuration, everything ok.
2135*ec779b8eSAndroid Build Coastguard Worker             ATRACE_END();
2136*ec779b8eSAndroid Build Coastguard Worker             return OK;
2137*ec779b8eSAndroid Build Coastguard Worker         }
2138*ec779b8eSAndroid Build Coastguard Worker 
2139*ec779b8eSAndroid Build Coastguard Worker         audioSinkChanged = true;
2140*ec779b8eSAndroid Build Coastguard Worker         mAudioSink->close();
2141*ec779b8eSAndroid Build Coastguard Worker         mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
2142*ec779b8eSAndroid Build Coastguard Worker         // Note: It is possible to set up the callback, but not use it to send audio data.
2143*ec779b8eSAndroid Build Coastguard Worker         // This requires a fix in AudioSink to explicitly specify the transfer mode.
2144*ec779b8eSAndroid Build Coastguard Worker         mUseAudioCallback = getUseAudioCallbackSetting();
2145*ec779b8eSAndroid Build Coastguard Worker         if (mUseAudioCallback) {
2146*ec779b8eSAndroid Build Coastguard Worker             ++mAudioDrainGeneration;  // discard pending kWhatDrainAudioQueue message.
2147*ec779b8eSAndroid Build Coastguard Worker         }
2148*ec779b8eSAndroid Build Coastguard Worker 
2149*ec779b8eSAndroid Build Coastguard Worker         // Compute the desired buffer size.
2150*ec779b8eSAndroid Build Coastguard Worker         // For callback mode, the amount of time before wakeup is about half the buffer size.
2151*ec779b8eSAndroid Build Coastguard Worker         const uint32_t frameCount =
2152*ec779b8eSAndroid Build Coastguard Worker                 (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
2153*ec779b8eSAndroid Build Coastguard Worker 
2154*ec779b8eSAndroid Build Coastguard Worker         // The doNotReconnect means AudioSink will signal back and let NuPlayer to re-construct
2155*ec779b8eSAndroid Build Coastguard Worker         // AudioSink. We don't want this when there's video because it will cause a video seek to
2156*ec779b8eSAndroid Build Coastguard Worker         // the previous I frame. But we do want this when there's only audio because it will give
2157*ec779b8eSAndroid Build Coastguard Worker         // NuPlayer a chance to switch from non-offload mode to offload mode.
2158*ec779b8eSAndroid Build Coastguard Worker         // So we only set doNotReconnect when there's no video.
2159*ec779b8eSAndroid Build Coastguard Worker         const bool doNotReconnect = !hasVideo;
2160*ec779b8eSAndroid Build Coastguard Worker 
2161*ec779b8eSAndroid Build Coastguard Worker         // We should always be able to set our playback settings if the sink is closed.
2162*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
2163*ec779b8eSAndroid Build Coastguard Worker                 "onOpenAudioSink: can't set playback rate on closed sink");
2164*ec779b8eSAndroid Build Coastguard Worker         status_t err = mAudioSink->open(
2165*ec779b8eSAndroid Build Coastguard Worker                     sampleRate,
2166*ec779b8eSAndroid Build Coastguard Worker                     numChannels,
2167*ec779b8eSAndroid Build Coastguard Worker                     (audio_channel_mask_t)channelMask,
2168*ec779b8eSAndroid Build Coastguard Worker                     audioFormat,
2169*ec779b8eSAndroid Build Coastguard Worker                     0 /* bufferCount - unused */,
2170*ec779b8eSAndroid Build Coastguard Worker                     mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL,
2171*ec779b8eSAndroid Build Coastguard Worker                     mUseAudioCallback ? this : NULL,
2172*ec779b8eSAndroid Build Coastguard Worker                     (audio_output_flags_t)pcmFlags,
2173*ec779b8eSAndroid Build Coastguard Worker                     NULL,
2174*ec779b8eSAndroid Build Coastguard Worker                     doNotReconnect,
2175*ec779b8eSAndroid Build Coastguard Worker                     frameCount);
2176*ec779b8eSAndroid Build Coastguard Worker         if (err != OK) {
2177*ec779b8eSAndroid Build Coastguard Worker             ALOGW("openAudioSink: non offloaded open failed status: %d", err);
2178*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->close();
2179*ec779b8eSAndroid Build Coastguard Worker             mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
2180*ec779b8eSAndroid Build Coastguard Worker             ATRACE_END();
2181*ec779b8eSAndroid Build Coastguard Worker             return err;
2182*ec779b8eSAndroid Build Coastguard Worker         }
2183*ec779b8eSAndroid Build Coastguard Worker         mCurrentPcmInfo = info;
2184*ec779b8eSAndroid Build Coastguard Worker         if (!mPaused) { // for preview mode, don't start if paused
2185*ec779b8eSAndroid Build Coastguard Worker             mAudioSink->start();
2186*ec779b8eSAndroid Build Coastguard Worker         }
2187*ec779b8eSAndroid Build Coastguard Worker     }
2188*ec779b8eSAndroid Build Coastguard Worker     if (audioSinkChanged) {
2189*ec779b8eSAndroid Build Coastguard Worker         onAudioSinkChanged();
2190*ec779b8eSAndroid Build Coastguard Worker     }
2191*ec779b8eSAndroid Build Coastguard Worker     mAudioTornDown = false;
2192*ec779b8eSAndroid Build Coastguard Worker     ATRACE_END();
2193*ec779b8eSAndroid Build Coastguard Worker     return OK;
2194*ec779b8eSAndroid Build Coastguard Worker }
2195*ec779b8eSAndroid Build Coastguard Worker 
onCloseAudioSink()2196*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onCloseAudioSink() {
2197*ec779b8eSAndroid Build Coastguard Worker     ATRACE_BEGIN("NuPlyer::Renderer::onCloseAudioSink");
2198*ec779b8eSAndroid Build Coastguard Worker     mAudioSink->close();
2199*ec779b8eSAndroid Build Coastguard Worker     mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
2200*ec779b8eSAndroid Build Coastguard Worker     mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
2201*ec779b8eSAndroid Build Coastguard Worker     ATRACE_END();
2202*ec779b8eSAndroid Build Coastguard Worker }
2203*ec779b8eSAndroid Build Coastguard Worker 
onChangeAudioFormat(const sp<AMessage> & meta,const sp<AMessage> & notify)2204*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::onChangeAudioFormat(
2205*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &meta, const sp<AMessage> &notify) {
2206*ec779b8eSAndroid Build Coastguard Worker     sp<AMessage> format;
2207*ec779b8eSAndroid Build Coastguard Worker     CHECK(meta->findMessage("format", &format));
2208*ec779b8eSAndroid Build Coastguard Worker 
2209*ec779b8eSAndroid Build Coastguard Worker     int32_t offloadOnly;
2210*ec779b8eSAndroid Build Coastguard Worker     CHECK(meta->findInt32("offload-only", &offloadOnly));
2211*ec779b8eSAndroid Build Coastguard Worker 
2212*ec779b8eSAndroid Build Coastguard Worker     int32_t hasVideo;
2213*ec779b8eSAndroid Build Coastguard Worker     CHECK(meta->findInt32("has-video", &hasVideo));
2214*ec779b8eSAndroid Build Coastguard Worker 
2215*ec779b8eSAndroid Build Coastguard Worker     uint32_t flags;
2216*ec779b8eSAndroid Build Coastguard Worker     CHECK(meta->findInt32("flags", (int32_t *)&flags));
2217*ec779b8eSAndroid Build Coastguard Worker 
2218*ec779b8eSAndroid Build Coastguard Worker     uint32_t isStreaming;
2219*ec779b8eSAndroid Build Coastguard Worker     CHECK(meta->findInt32("isStreaming", (int32_t *)&isStreaming));
2220*ec779b8eSAndroid Build Coastguard Worker 
2221*ec779b8eSAndroid Build Coastguard Worker     status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
2222*ec779b8eSAndroid Build Coastguard Worker 
2223*ec779b8eSAndroid Build Coastguard Worker     if (err != OK) {
2224*ec779b8eSAndroid Build Coastguard Worker         notify->setInt32("err", err);
2225*ec779b8eSAndroid Build Coastguard Worker     }
2226*ec779b8eSAndroid Build Coastguard Worker     notify->post();
2227*ec779b8eSAndroid Build Coastguard Worker }
2228*ec779b8eSAndroid Build Coastguard Worker 
dump(AString & logString)2229*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::Renderer::WakeLockEvent::dump(AString& logString) {
2230*ec779b8eSAndroid Build Coastguard Worker   logString.append("[");
2231*ec779b8eSAndroid Build Coastguard Worker   logString.append(mTimeMs);
2232*ec779b8eSAndroid Build Coastguard Worker   logString.append(",");
2233*ec779b8eSAndroid Build Coastguard Worker   logString.append(mEventTimeoutGeneration);
2234*ec779b8eSAndroid Build Coastguard Worker   logString.append(",");
2235*ec779b8eSAndroid Build Coastguard Worker   logString.append(mRendererTimeoutGeneration);
2236*ec779b8eSAndroid Build Coastguard Worker   logString.append("]");
2237*ec779b8eSAndroid Build Coastguard Worker }
2238*ec779b8eSAndroid Build Coastguard Worker 
2239*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
2240