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> ¬ify,
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> ¬ifyConsumed) {
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> ¬ify) {
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", ¬ify));
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", ¬ifyConsumed));
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", ¬ifyConsumed)) {
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(¤tPositionUs) == 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> ¬ify) {
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