1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2012 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 // <IMPORTANT_WARNING>
18*ec779b8eSAndroid Build Coastguard Worker // Design rules for threadLoop() are given in the comments at section "Fast mixer thread" of
19*ec779b8eSAndroid Build Coastguard Worker // StateQueue.h. In particular, avoid library and system calls except at well-known points.
20*ec779b8eSAndroid Build Coastguard Worker // The design rules are only for threadLoop(), and don't apply to FastMixerDumpState methods.
21*ec779b8eSAndroid Build Coastguard Worker // </IMPORTANT_WARNING>
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "FastMixer"
24*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
25*ec779b8eSAndroid Build Coastguard Worker
26*ec779b8eSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_AUDIO
27*ec779b8eSAndroid Build Coastguard Worker
28*ec779b8eSAndroid Build Coastguard Worker #include "Configuration.h"
29*ec779b8eSAndroid Build Coastguard Worker #include <time.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <utils/Trace.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <system/audio.h>
33*ec779b8eSAndroid Build Coastguard Worker #ifdef FAST_THREAD_STATISTICS
34*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/Statistics.h>
35*ec779b8eSAndroid Build Coastguard Worker #ifdef CPU_FREQUENCY_STATISTICS
36*ec779b8eSAndroid Build Coastguard Worker #include <cpustats/ThreadCpuUsage.h>
37*ec779b8eSAndroid Build Coastguard Worker #endif
38*ec779b8eSAndroid Build Coastguard Worker #endif
39*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/Trace.h>
40*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/channels.h>
41*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/format.h>
42*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/mono_blend.h>
43*ec779b8eSAndroid Build Coastguard Worker #include <cutils/bitops.h>
44*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioMixer.h>
45*ec779b8eSAndroid Build Coastguard Worker #include "FastMixer.h"
46*ec779b8eSAndroid Build Coastguard Worker #include <afutils/TypedLogger.h>
47*ec779b8eSAndroid Build Coastguard Worker
48*ec779b8eSAndroid Build Coastguard Worker namespace android {
49*ec779b8eSAndroid Build Coastguard Worker
50*ec779b8eSAndroid Build Coastguard Worker /*static*/ const FastMixerState FastMixer::sInitial;
51*ec779b8eSAndroid Build Coastguard Worker
getChannelMaskFromCount(size_t count)52*ec779b8eSAndroid Build Coastguard Worker static audio_channel_mask_t getChannelMaskFromCount(size_t count) {
53*ec779b8eSAndroid Build Coastguard Worker const audio_channel_mask_t mask = audio_channel_out_mask_from_count(count);
54*ec779b8eSAndroid Build Coastguard Worker if (mask == AUDIO_CHANNEL_INVALID) {
55*ec779b8eSAndroid Build Coastguard Worker // some counts have no positional masks. TODO: Update this to return index count?
56*ec779b8eSAndroid Build Coastguard Worker return audio_channel_mask_for_index_assignment_from_count(count);
57*ec779b8eSAndroid Build Coastguard Worker }
58*ec779b8eSAndroid Build Coastguard Worker return mask;
59*ec779b8eSAndroid Build Coastguard Worker }
60*ec779b8eSAndroid Build Coastguard Worker
FastMixer(audio_io_handle_t parentIoHandle)61*ec779b8eSAndroid Build Coastguard Worker FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
62*ec779b8eSAndroid Build Coastguard Worker : FastThread("cycle_ms", "load_us"),
63*ec779b8eSAndroid Build Coastguard Worker // mFastTrackNames
64*ec779b8eSAndroid Build Coastguard Worker // mGenerations
65*ec779b8eSAndroid Build Coastguard Worker // timestamp
66*ec779b8eSAndroid Build Coastguard Worker mThreadIoHandle(parentIoHandle)
67*ec779b8eSAndroid Build Coastguard Worker {
68*ec779b8eSAndroid Build Coastguard Worker // FIXME pass sInitial as parameter to base class constructor, and make it static local
69*ec779b8eSAndroid Build Coastguard Worker mPrevious = &sInitial;
70*ec779b8eSAndroid Build Coastguard Worker mCurrent = &sInitial;
71*ec779b8eSAndroid Build Coastguard Worker mDummyDumpState = &mDummyFastMixerDumpState;
72*ec779b8eSAndroid Build Coastguard Worker
73*ec779b8eSAndroid Build Coastguard Worker // TODO: Add channel mask to NBAIO_Format.
74*ec779b8eSAndroid Build Coastguard Worker // We assume that the channel mask must be a valid positional channel mask.
75*ec779b8eSAndroid Build Coastguard Worker mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
76*ec779b8eSAndroid Build Coastguard Worker mBalance.setChannelMask(mSinkChannelMask);
77*ec779b8eSAndroid Build Coastguard Worker
78*ec779b8eSAndroid Build Coastguard Worker #ifdef FAST_THREAD_STATISTICS
79*ec779b8eSAndroid Build Coastguard Worker mOldLoad.tv_sec = 0;
80*ec779b8eSAndroid Build Coastguard Worker mOldLoad.tv_nsec = 0;
81*ec779b8eSAndroid Build Coastguard Worker #endif
82*ec779b8eSAndroid Build Coastguard Worker }
83*ec779b8eSAndroid Build Coastguard Worker
sq()84*ec779b8eSAndroid Build Coastguard Worker FastMixerStateQueue* FastMixer::sq()
85*ec779b8eSAndroid Build Coastguard Worker {
86*ec779b8eSAndroid Build Coastguard Worker return &mSQ;
87*ec779b8eSAndroid Build Coastguard Worker }
88*ec779b8eSAndroid Build Coastguard Worker
poll()89*ec779b8eSAndroid Build Coastguard Worker const FastThreadState *FastMixer::poll()
90*ec779b8eSAndroid Build Coastguard Worker {
91*ec779b8eSAndroid Build Coastguard Worker return mSQ.poll();
92*ec779b8eSAndroid Build Coastguard Worker }
93*ec779b8eSAndroid Build Coastguard Worker
setNBLogWriter(NBLog::Writer * logWriter __unused)94*ec779b8eSAndroid Build Coastguard Worker void FastMixer::setNBLogWriter(NBLog::Writer *logWriter __unused)
95*ec779b8eSAndroid Build Coastguard Worker {
96*ec779b8eSAndroid Build Coastguard Worker }
97*ec779b8eSAndroid Build Coastguard Worker
onIdle()98*ec779b8eSAndroid Build Coastguard Worker void FastMixer::onIdle()
99*ec779b8eSAndroid Build Coastguard Worker {
100*ec779b8eSAndroid Build Coastguard Worker mPreIdle = *(const FastMixerState *)mCurrent;
101*ec779b8eSAndroid Build Coastguard Worker mCurrent = &mPreIdle;
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker
onExit()104*ec779b8eSAndroid Build Coastguard Worker void FastMixer::onExit()
105*ec779b8eSAndroid Build Coastguard Worker {
106*ec779b8eSAndroid Build Coastguard Worker delete mMixer;
107*ec779b8eSAndroid Build Coastguard Worker free(mMixerBuffer);
108*ec779b8eSAndroid Build Coastguard Worker free(mSinkBuffer);
109*ec779b8eSAndroid Build Coastguard Worker }
110*ec779b8eSAndroid Build Coastguard Worker
isSubClassCommand(FastThreadState::Command command)111*ec779b8eSAndroid Build Coastguard Worker bool FastMixer::isSubClassCommand(FastThreadState::Command command)
112*ec779b8eSAndroid Build Coastguard Worker {
113*ec779b8eSAndroid Build Coastguard Worker switch ((FastMixerState::Command) command) {
114*ec779b8eSAndroid Build Coastguard Worker case FastMixerState::MIX:
115*ec779b8eSAndroid Build Coastguard Worker case FastMixerState::WRITE:
116*ec779b8eSAndroid Build Coastguard Worker case FastMixerState::MIX_WRITE:
117*ec779b8eSAndroid Build Coastguard Worker return true;
118*ec779b8eSAndroid Build Coastguard Worker default:
119*ec779b8eSAndroid Build Coastguard Worker return false;
120*ec779b8eSAndroid Build Coastguard Worker }
121*ec779b8eSAndroid Build Coastguard Worker }
122*ec779b8eSAndroid Build Coastguard Worker
updateMixerTrack(int index,Reason reason)123*ec779b8eSAndroid Build Coastguard Worker void FastMixer::updateMixerTrack(int index, Reason reason) {
124*ec779b8eSAndroid Build Coastguard Worker const FastMixerState * const current = (const FastMixerState *) mCurrent;
125*ec779b8eSAndroid Build Coastguard Worker const FastTrack * const fastTrack = ¤t->mFastTracks[index];
126*ec779b8eSAndroid Build Coastguard Worker
127*ec779b8eSAndroid Build Coastguard Worker // check and update generation
128*ec779b8eSAndroid Build Coastguard Worker if (reason == REASON_MODIFY && mGenerations[index] == fastTrack->mGeneration) {
129*ec779b8eSAndroid Build Coastguard Worker return; // no change on an already configured track.
130*ec779b8eSAndroid Build Coastguard Worker }
131*ec779b8eSAndroid Build Coastguard Worker mGenerations[index] = fastTrack->mGeneration;
132*ec779b8eSAndroid Build Coastguard Worker
133*ec779b8eSAndroid Build Coastguard Worker // mMixer == nullptr on configuration failure (check done after generation update).
134*ec779b8eSAndroid Build Coastguard Worker if (mMixer == nullptr) {
135*ec779b8eSAndroid Build Coastguard Worker return;
136*ec779b8eSAndroid Build Coastguard Worker }
137*ec779b8eSAndroid Build Coastguard Worker
138*ec779b8eSAndroid Build Coastguard Worker switch (reason) {
139*ec779b8eSAndroid Build Coastguard Worker case REASON_REMOVE:
140*ec779b8eSAndroid Build Coastguard Worker mMixer->destroy(index);
141*ec779b8eSAndroid Build Coastguard Worker break;
142*ec779b8eSAndroid Build Coastguard Worker case REASON_ADD: {
143*ec779b8eSAndroid Build Coastguard Worker const status_t status = mMixer->create(
144*ec779b8eSAndroid Build Coastguard Worker index, fastTrack->mChannelMask, fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
145*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
146*ec779b8eSAndroid Build Coastguard Worker "%s: cannot create fast track index"
147*ec779b8eSAndroid Build Coastguard Worker " %d, mask %#x, format %#x in AudioMixer",
148*ec779b8eSAndroid Build Coastguard Worker __func__, index, fastTrack->mChannelMask, fastTrack->mFormat);
149*ec779b8eSAndroid Build Coastguard Worker }
150*ec779b8eSAndroid Build Coastguard Worker [[fallthrough]]; // now fallthrough to update the newly created track.
151*ec779b8eSAndroid Build Coastguard Worker case REASON_MODIFY:
152*ec779b8eSAndroid Build Coastguard Worker mMixer->setBufferProvider(index, fastTrack->mBufferProvider);
153*ec779b8eSAndroid Build Coastguard Worker
154*ec779b8eSAndroid Build Coastguard Worker float vlf, vrf;
155*ec779b8eSAndroid Build Coastguard Worker if (fastTrack->mVolumeProvider != nullptr) {
156*ec779b8eSAndroid Build Coastguard Worker const gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
157*ec779b8eSAndroid Build Coastguard Worker vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
158*ec779b8eSAndroid Build Coastguard Worker vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
159*ec779b8eSAndroid Build Coastguard Worker } else {
160*ec779b8eSAndroid Build Coastguard Worker vlf = vrf = AudioMixer::UNITY_GAIN_FLOAT;
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker
163*ec779b8eSAndroid Build Coastguard Worker // set volume to avoid ramp whenever the track is updated (or created).
164*ec779b8eSAndroid Build Coastguard Worker // Note: this does not distinguish from starting fresh or
165*ec779b8eSAndroid Build Coastguard Worker // resuming from a paused state.
166*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
167*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
168*ec779b8eSAndroid Build Coastguard Worker
169*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::RESAMPLE, AudioMixer::REMOVE, nullptr);
170*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
171*ec779b8eSAndroid Build Coastguard Worker (void *)mMixerBuffer);
172*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT,
173*ec779b8eSAndroid Build Coastguard Worker (void *)(uintptr_t)mMixerBufferFormat);
174*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::FORMAT,
175*ec779b8eSAndroid Build Coastguard Worker (void *)(uintptr_t)fastTrack->mFormat);
176*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
177*ec779b8eSAndroid Build Coastguard Worker (void *)(uintptr_t)fastTrack->mChannelMask);
178*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
179*ec779b8eSAndroid Build Coastguard Worker (void *)(uintptr_t)mSinkChannelMask);
180*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
181*ec779b8eSAndroid Build Coastguard Worker (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
182*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::HAPTIC_SCALE,
183*ec779b8eSAndroid Build Coastguard Worker (void *)(&(fastTrack->mHapticScale)));
184*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::HAPTIC_MAX_AMPLITUDE,
185*ec779b8eSAndroid Build Coastguard Worker (void *)(&(fastTrack->mHapticMaxAmplitude)));
186*ec779b8eSAndroid Build Coastguard Worker
187*ec779b8eSAndroid Build Coastguard Worker mMixer->enable(index);
188*ec779b8eSAndroid Build Coastguard Worker break;
189*ec779b8eSAndroid Build Coastguard Worker default:
190*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("%s: invalid update reason %d", __func__, reason);
191*ec779b8eSAndroid Build Coastguard Worker }
192*ec779b8eSAndroid Build Coastguard Worker }
193*ec779b8eSAndroid Build Coastguard Worker
onStateChange()194*ec779b8eSAndroid Build Coastguard Worker void FastMixer::onStateChange()
195*ec779b8eSAndroid Build Coastguard Worker {
196*ec779b8eSAndroid Build Coastguard Worker const FastMixerState * const current = (const FastMixerState *) mCurrent;
197*ec779b8eSAndroid Build Coastguard Worker const FastMixerState * const previous = (const FastMixerState *) mPrevious;
198*ec779b8eSAndroid Build Coastguard Worker FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
199*ec779b8eSAndroid Build Coastguard Worker const size_t frameCount = current->mFrameCount;
200*ec779b8eSAndroid Build Coastguard Worker
201*ec779b8eSAndroid Build Coastguard Worker // update boottime offset, in case it has changed
202*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
203*ec779b8eSAndroid Build Coastguard Worker mBoottimeOffset.load();
204*ec779b8eSAndroid Build Coastguard Worker
205*ec779b8eSAndroid Build Coastguard Worker // handle state change here, but since we want to diff the state,
206*ec779b8eSAndroid Build Coastguard Worker // we're prepared for previous == &sInitial the first time through
207*ec779b8eSAndroid Build Coastguard Worker unsigned previousTrackMask;
208*ec779b8eSAndroid Build Coastguard Worker
209*ec779b8eSAndroid Build Coastguard Worker // check for change in output HAL configuration
210*ec779b8eSAndroid Build Coastguard Worker const NBAIO_Format previousFormat = mFormat;
211*ec779b8eSAndroid Build Coastguard Worker if (current->mOutputSinkGen != mOutputSinkGen) {
212*ec779b8eSAndroid Build Coastguard Worker mOutputSink = current->mOutputSink;
213*ec779b8eSAndroid Build Coastguard Worker mOutputSinkGen = current->mOutputSinkGen;
214*ec779b8eSAndroid Build Coastguard Worker mSinkChannelMask = current->mSinkChannelMask;
215*ec779b8eSAndroid Build Coastguard Worker mBalance.setChannelMask(mSinkChannelMask);
216*ec779b8eSAndroid Build Coastguard Worker if (mOutputSink == nullptr) {
217*ec779b8eSAndroid Build Coastguard Worker mFormat = Format_Invalid;
218*ec779b8eSAndroid Build Coastguard Worker mSampleRate = 0;
219*ec779b8eSAndroid Build Coastguard Worker mSinkChannelCount = 0;
220*ec779b8eSAndroid Build Coastguard Worker mSinkChannelMask = AUDIO_CHANNEL_NONE;
221*ec779b8eSAndroid Build Coastguard Worker mAudioChannelCount = 0;
222*ec779b8eSAndroid Build Coastguard Worker } else {
223*ec779b8eSAndroid Build Coastguard Worker mFormat = mOutputSink->format();
224*ec779b8eSAndroid Build Coastguard Worker mSampleRate = Format_sampleRate(mFormat);
225*ec779b8eSAndroid Build Coastguard Worker mSinkChannelCount = Format_channelCount(mFormat);
226*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS);
227*ec779b8eSAndroid Build Coastguard Worker
228*ec779b8eSAndroid Build Coastguard Worker if (mSinkChannelMask == AUDIO_CHANNEL_NONE) {
229*ec779b8eSAndroid Build Coastguard Worker mSinkChannelMask = getChannelMaskFromCount(mSinkChannelCount);
230*ec779b8eSAndroid Build Coastguard Worker }
231*ec779b8eSAndroid Build Coastguard Worker mAudioChannelCount = mSinkChannelCount - audio_channel_count_from_out_mask(
232*ec779b8eSAndroid Build Coastguard Worker mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
233*ec779b8eSAndroid Build Coastguard Worker }
234*ec779b8eSAndroid Build Coastguard Worker dumpState->mSampleRate = mSampleRate;
235*ec779b8eSAndroid Build Coastguard Worker }
236*ec779b8eSAndroid Build Coastguard Worker
237*ec779b8eSAndroid Build Coastguard Worker if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) {
238*ec779b8eSAndroid Build Coastguard Worker // FIXME to avoid priority inversion, don't delete here
239*ec779b8eSAndroid Build Coastguard Worker delete mMixer;
240*ec779b8eSAndroid Build Coastguard Worker mMixer = nullptr;
241*ec779b8eSAndroid Build Coastguard Worker free(mMixerBuffer);
242*ec779b8eSAndroid Build Coastguard Worker mMixerBuffer = nullptr;
243*ec779b8eSAndroid Build Coastguard Worker free(mSinkBuffer);
244*ec779b8eSAndroid Build Coastguard Worker mSinkBuffer = nullptr;
245*ec779b8eSAndroid Build Coastguard Worker if (frameCount > 0 && mSampleRate > 0) {
246*ec779b8eSAndroid Build Coastguard Worker // FIXME new may block for unbounded time at internal mutex of the heap
247*ec779b8eSAndroid Build Coastguard Worker // implementation; it would be better to have normal mixer allocate for us
248*ec779b8eSAndroid Build Coastguard Worker // to avoid blocking here and to prevent possible priority inversion
249*ec779b8eSAndroid Build Coastguard Worker mMixer = new AudioMixer(frameCount, mSampleRate);
250*ec779b8eSAndroid Build Coastguard Worker // FIXME See the other FIXME at FastMixer::setNBLogWriter()
251*ec779b8eSAndroid Build Coastguard Worker NBLog::thread_params_t params;
252*ec779b8eSAndroid Build Coastguard Worker params.frameCount = frameCount;
253*ec779b8eSAndroid Build Coastguard Worker params.sampleRate = mSampleRate;
254*ec779b8eSAndroid Build Coastguard Worker LOG_THREAD_PARAMS(params);
255*ec779b8eSAndroid Build Coastguard Worker const size_t mixerFrameSize = mSinkChannelCount
256*ec779b8eSAndroid Build Coastguard Worker * audio_bytes_per_sample(mMixerBufferFormat);
257*ec779b8eSAndroid Build Coastguard Worker mMixerBufferSize = mixerFrameSize * frameCount;
258*ec779b8eSAndroid Build Coastguard Worker (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
259*ec779b8eSAndroid Build Coastguard Worker const size_t sinkFrameSize = mSinkChannelCount
260*ec779b8eSAndroid Build Coastguard Worker * audio_bytes_per_sample(mFormat.mFormat);
261*ec779b8eSAndroid Build Coastguard Worker if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
262*ec779b8eSAndroid Build Coastguard Worker mSinkBufferSize = sinkFrameSize * frameCount;
263*ec779b8eSAndroid Build Coastguard Worker (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
264*ec779b8eSAndroid Build Coastguard Worker }
265*ec779b8eSAndroid Build Coastguard Worker mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00
266*ec779b8eSAndroid Build Coastguard Worker mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75
267*ec779b8eSAndroid Build Coastguard Worker mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50
268*ec779b8eSAndroid Build Coastguard Worker mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95
269*ec779b8eSAndroid Build Coastguard Worker mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75
270*ec779b8eSAndroid Build Coastguard Worker mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25
271*ec779b8eSAndroid Build Coastguard Worker } else {
272*ec779b8eSAndroid Build Coastguard Worker mPeriodNs = 0;
273*ec779b8eSAndroid Build Coastguard Worker mUnderrunNs = 0;
274*ec779b8eSAndroid Build Coastguard Worker mOverrunNs = 0;
275*ec779b8eSAndroid Build Coastguard Worker mForceNs = 0;
276*ec779b8eSAndroid Build Coastguard Worker mWarmupNsMin = 0;
277*ec779b8eSAndroid Build Coastguard Worker mWarmupNsMax = LONG_MAX;
278*ec779b8eSAndroid Build Coastguard Worker }
279*ec779b8eSAndroid Build Coastguard Worker mMixerBufferState = UNDEFINED;
280*ec779b8eSAndroid Build Coastguard Worker // we need to reconfigure all active tracks
281*ec779b8eSAndroid Build Coastguard Worker previousTrackMask = 0;
282*ec779b8eSAndroid Build Coastguard Worker mFastTracksGen = current->mFastTracksGen - 1;
283*ec779b8eSAndroid Build Coastguard Worker dumpState->mFrameCount = frameCount;
284*ec779b8eSAndroid Build Coastguard Worker #ifdef TEE_SINK
285*ec779b8eSAndroid Build Coastguard Worker mTee.set(mFormat, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
286*ec779b8eSAndroid Build Coastguard Worker mTee.setId(std::string("_") + std::to_string(mThreadIoHandle) + "_F");
287*ec779b8eSAndroid Build Coastguard Worker #endif
288*ec779b8eSAndroid Build Coastguard Worker } else {
289*ec779b8eSAndroid Build Coastguard Worker previousTrackMask = previous->mTrackMask;
290*ec779b8eSAndroid Build Coastguard Worker }
291*ec779b8eSAndroid Build Coastguard Worker
292*ec779b8eSAndroid Build Coastguard Worker // check for change in active track set
293*ec779b8eSAndroid Build Coastguard Worker const unsigned currentTrackMask = current->mTrackMask;
294*ec779b8eSAndroid Build Coastguard Worker dumpState->mTrackMask = currentTrackMask;
295*ec779b8eSAndroid Build Coastguard Worker dumpState->mNumTracks = popcount(currentTrackMask);
296*ec779b8eSAndroid Build Coastguard Worker if (current->mFastTracksGen != mFastTracksGen) {
297*ec779b8eSAndroid Build Coastguard Worker
298*ec779b8eSAndroid Build Coastguard Worker // process removed tracks first to avoid running out of track names
299*ec779b8eSAndroid Build Coastguard Worker unsigned removedTracks = previousTrackMask & ~currentTrackMask;
300*ec779b8eSAndroid Build Coastguard Worker while (removedTracks != 0) {
301*ec779b8eSAndroid Build Coastguard Worker const int i = __builtin_ctz(removedTracks);
302*ec779b8eSAndroid Build Coastguard Worker removedTracks &= ~(1 << i);
303*ec779b8eSAndroid Build Coastguard Worker updateMixerTrack(i, REASON_REMOVE);
304*ec779b8eSAndroid Build Coastguard Worker // don't reset track dump state, since other side is ignoring it
305*ec779b8eSAndroid Build Coastguard Worker }
306*ec779b8eSAndroid Build Coastguard Worker
307*ec779b8eSAndroid Build Coastguard Worker // now process added tracks
308*ec779b8eSAndroid Build Coastguard Worker unsigned addedTracks = currentTrackMask & ~previousTrackMask;
309*ec779b8eSAndroid Build Coastguard Worker while (addedTracks != 0) {
310*ec779b8eSAndroid Build Coastguard Worker const int i = __builtin_ctz(addedTracks);
311*ec779b8eSAndroid Build Coastguard Worker addedTracks &= ~(1 << i);
312*ec779b8eSAndroid Build Coastguard Worker updateMixerTrack(i, REASON_ADD);
313*ec779b8eSAndroid Build Coastguard Worker }
314*ec779b8eSAndroid Build Coastguard Worker
315*ec779b8eSAndroid Build Coastguard Worker // finally process (potentially) modified tracks; these use the same slot
316*ec779b8eSAndroid Build Coastguard Worker // but may have a different buffer provider or volume provider
317*ec779b8eSAndroid Build Coastguard Worker unsigned modifiedTracks = currentTrackMask & previousTrackMask;
318*ec779b8eSAndroid Build Coastguard Worker while (modifiedTracks != 0) {
319*ec779b8eSAndroid Build Coastguard Worker const int i = __builtin_ctz(modifiedTracks);
320*ec779b8eSAndroid Build Coastguard Worker modifiedTracks &= ~(1 << i);
321*ec779b8eSAndroid Build Coastguard Worker updateMixerTrack(i, REASON_MODIFY);
322*ec779b8eSAndroid Build Coastguard Worker }
323*ec779b8eSAndroid Build Coastguard Worker
324*ec779b8eSAndroid Build Coastguard Worker mFastTracksGen = current->mFastTracksGen;
325*ec779b8eSAndroid Build Coastguard Worker }
326*ec779b8eSAndroid Build Coastguard Worker }
327*ec779b8eSAndroid Build Coastguard Worker
onWork()328*ec779b8eSAndroid Build Coastguard Worker void FastMixer::onWork()
329*ec779b8eSAndroid Build Coastguard Worker {
330*ec779b8eSAndroid Build Coastguard Worker // TODO: pass an ID parameter to indicate which time series we want to write to in NBLog.cpp
331*ec779b8eSAndroid Build Coastguard Worker // Or: pass both of these into a single call with a boolean
332*ec779b8eSAndroid Build Coastguard Worker const FastMixerState * const current = (const FastMixerState *) mCurrent;
333*ec779b8eSAndroid Build Coastguard Worker FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
334*ec779b8eSAndroid Build Coastguard Worker
335*ec779b8eSAndroid Build Coastguard Worker if (mIsWarm) {
336*ec779b8eSAndroid Build Coastguard Worker // Logging timestamps for FastMixer is currently disabled to make memory room for logging
337*ec779b8eSAndroid Build Coastguard Worker // other statistics in FastMixer.
338*ec779b8eSAndroid Build Coastguard Worker // To re-enable, delete the #ifdef FASTMIXER_LOG_HIST_TS lines (and the #endif lines).
339*ec779b8eSAndroid Build Coastguard Worker #ifdef FASTMIXER_LOG_HIST_TS
340*ec779b8eSAndroid Build Coastguard Worker LOG_HIST_TS();
341*ec779b8eSAndroid Build Coastguard Worker #endif
342*ec779b8eSAndroid Build Coastguard Worker //ALOGD("Eric FastMixer::onWork() mIsWarm");
343*ec779b8eSAndroid Build Coastguard Worker } else {
344*ec779b8eSAndroid Build Coastguard Worker dumpState->mTimestampVerifier.discontinuity(
345*ec779b8eSAndroid Build Coastguard Worker dumpState->mTimestampVerifier.DISCONTINUITY_MODE_CONTINUOUS);
346*ec779b8eSAndroid Build Coastguard Worker // See comment in if block.
347*ec779b8eSAndroid Build Coastguard Worker #ifdef FASTMIXER_LOG_HIST_TS
348*ec779b8eSAndroid Build Coastguard Worker LOG_AUDIO_STATE();
349*ec779b8eSAndroid Build Coastguard Worker #endif
350*ec779b8eSAndroid Build Coastguard Worker }
351*ec779b8eSAndroid Build Coastguard Worker const FastMixerState::Command command = mCommand;
352*ec779b8eSAndroid Build Coastguard Worker const size_t frameCount = current->mFrameCount;
353*ec779b8eSAndroid Build Coastguard Worker
354*ec779b8eSAndroid Build Coastguard Worker if ((command & FastMixerState::MIX) && (mMixer != nullptr) && mIsWarm) {
355*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(mMixerBuffer != nullptr);
356*ec779b8eSAndroid Build Coastguard Worker
357*ec779b8eSAndroid Build Coastguard Worker // AudioMixer::mState.enabledTracks is undefined if mState.hook == process__validate,
358*ec779b8eSAndroid Build Coastguard Worker // so we keep a side copy of enabledTracks
359*ec779b8eSAndroid Build Coastguard Worker bool anyEnabledTracks = false;
360*ec779b8eSAndroid Build Coastguard Worker
361*ec779b8eSAndroid Build Coastguard Worker // for each track, update volume and check for underrun
362*ec779b8eSAndroid Build Coastguard Worker unsigned currentTrackMask = current->mTrackMask;
363*ec779b8eSAndroid Build Coastguard Worker while (currentTrackMask != 0) {
364*ec779b8eSAndroid Build Coastguard Worker const int i = __builtin_ctz(currentTrackMask);
365*ec779b8eSAndroid Build Coastguard Worker currentTrackMask &= ~(1 << i);
366*ec779b8eSAndroid Build Coastguard Worker const FastTrack* fastTrack = ¤t->mFastTracks[i];
367*ec779b8eSAndroid Build Coastguard Worker
368*ec779b8eSAndroid Build Coastguard Worker const int64_t trackFramesWrittenButNotPresented =
369*ec779b8eSAndroid Build Coastguard Worker mNativeFramesWrittenButNotPresented;
370*ec779b8eSAndroid Build Coastguard Worker const int64_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased();
371*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp perTrackTimestamp(mTimestamp);
372*ec779b8eSAndroid Build Coastguard Worker
373*ec779b8eSAndroid Build Coastguard Worker // Can't provide an ExtendedTimestamp before first frame presented.
374*ec779b8eSAndroid Build Coastguard Worker // Also, timestamp may not go to very last frame on stop().
375*ec779b8eSAndroid Build Coastguard Worker if (trackFramesWritten >= trackFramesWrittenButNotPresented &&
376*ec779b8eSAndroid Build Coastguard Worker perTrackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] > 0) {
377*ec779b8eSAndroid Build Coastguard Worker perTrackTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
378*ec779b8eSAndroid Build Coastguard Worker trackFramesWritten - trackFramesWrittenButNotPresented;
379*ec779b8eSAndroid Build Coastguard Worker } else {
380*ec779b8eSAndroid Build Coastguard Worker perTrackTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = 0;
381*ec779b8eSAndroid Build Coastguard Worker perTrackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = -1;
382*ec779b8eSAndroid Build Coastguard Worker }
383*ec779b8eSAndroid Build Coastguard Worker perTrackTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = trackFramesWritten;
384*ec779b8eSAndroid Build Coastguard Worker fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
385*ec779b8eSAndroid Build Coastguard Worker
386*ec779b8eSAndroid Build Coastguard Worker const int name = i;
387*ec779b8eSAndroid Build Coastguard Worker if (fastTrack->mVolumeProvider != nullptr) {
388*ec779b8eSAndroid Build Coastguard Worker const gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
389*ec779b8eSAndroid Build Coastguard Worker float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
390*ec779b8eSAndroid Build Coastguard Worker float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
391*ec779b8eSAndroid Build Coastguard Worker
392*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME0, &vlf);
393*ec779b8eSAndroid Build Coastguard Worker mMixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME1, &vrf);
394*ec779b8eSAndroid Build Coastguard Worker }
395*ec779b8eSAndroid Build Coastguard Worker // FIXME The current implementation of framesReady() for fast tracks
396*ec779b8eSAndroid Build Coastguard Worker // takes a tryLock, which can block
397*ec779b8eSAndroid Build Coastguard Worker // up to 1 ms. If enough active tracks all blocked in sequence, this would result
398*ec779b8eSAndroid Build Coastguard Worker // in the overall fast mix cycle being delayed. Should use a non-blocking FIFO.
399*ec779b8eSAndroid Build Coastguard Worker const size_t framesReady = fastTrack->mBufferProvider->framesReady();
400*ec779b8eSAndroid Build Coastguard Worker if (ATRACE_ENABLED()) {
401*ec779b8eSAndroid Build Coastguard Worker ATRACE_INT(fastTrack->mTraceName, framesReady);
402*ec779b8eSAndroid Build Coastguard Worker }
403*ec779b8eSAndroid Build Coastguard Worker FastTrackDump *ftDump = &dumpState->mTracks[i];
404*ec779b8eSAndroid Build Coastguard Worker FastTrackUnderruns underruns = ftDump->mUnderruns;
405*ec779b8eSAndroid Build Coastguard Worker if (framesReady < frameCount) {
406*ec779b8eSAndroid Build Coastguard Worker if (framesReady == 0) {
407*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mEmpty++;
408*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY;
409*ec779b8eSAndroid Build Coastguard Worker mMixer->disable(name);
410*ec779b8eSAndroid Build Coastguard Worker } else {
411*ec779b8eSAndroid Build Coastguard Worker // allow mixing partial buffer
412*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mPartial++;
413*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL;
414*ec779b8eSAndroid Build Coastguard Worker mMixer->enable(name);
415*ec779b8eSAndroid Build Coastguard Worker anyEnabledTracks = true;
416*ec779b8eSAndroid Build Coastguard Worker }
417*ec779b8eSAndroid Build Coastguard Worker } else {
418*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mFull++;
419*ec779b8eSAndroid Build Coastguard Worker underruns.mBitFields.mMostRecent = UNDERRUN_FULL;
420*ec779b8eSAndroid Build Coastguard Worker mMixer->enable(name);
421*ec779b8eSAndroid Build Coastguard Worker anyEnabledTracks = true;
422*ec779b8eSAndroid Build Coastguard Worker }
423*ec779b8eSAndroid Build Coastguard Worker ftDump->mUnderruns = underruns;
424*ec779b8eSAndroid Build Coastguard Worker ftDump->mFramesReady = framesReady;
425*ec779b8eSAndroid Build Coastguard Worker ftDump->mFramesWritten = trackFramesWritten;
426*ec779b8eSAndroid Build Coastguard Worker }
427*ec779b8eSAndroid Build Coastguard Worker
428*ec779b8eSAndroid Build Coastguard Worker if (anyEnabledTracks) {
429*ec779b8eSAndroid Build Coastguard Worker // process() is CPU-bound
430*ec779b8eSAndroid Build Coastguard Worker mMixer->process();
431*ec779b8eSAndroid Build Coastguard Worker mMixerBufferState = MIXED;
432*ec779b8eSAndroid Build Coastguard Worker } else if (mMixerBufferState != ZEROED) {
433*ec779b8eSAndroid Build Coastguard Worker mMixerBufferState = UNDEFINED;
434*ec779b8eSAndroid Build Coastguard Worker }
435*ec779b8eSAndroid Build Coastguard Worker
436*ec779b8eSAndroid Build Coastguard Worker } else if (mMixerBufferState == MIXED) {
437*ec779b8eSAndroid Build Coastguard Worker mMixerBufferState = UNDEFINED;
438*ec779b8eSAndroid Build Coastguard Worker }
439*ec779b8eSAndroid Build Coastguard Worker //bool didFullWrite = false; // dumpsys could display a count of partial writes
440*ec779b8eSAndroid Build Coastguard Worker if ((command & FastMixerState::WRITE)
441*ec779b8eSAndroid Build Coastguard Worker && (mOutputSink != nullptr) && (mMixerBuffer != nullptr)) {
442*ec779b8eSAndroid Build Coastguard Worker if (mMixerBufferState == UNDEFINED) {
443*ec779b8eSAndroid Build Coastguard Worker memset(mMixerBuffer, 0, mMixerBufferSize);
444*ec779b8eSAndroid Build Coastguard Worker mMixerBufferState = ZEROED;
445*ec779b8eSAndroid Build Coastguard Worker }
446*ec779b8eSAndroid Build Coastguard Worker
447*ec779b8eSAndroid Build Coastguard Worker if (mMasterMono.load()) { // memory_order_seq_cst
448*ec779b8eSAndroid Build Coastguard Worker mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount,
449*ec779b8eSAndroid Build Coastguard Worker true /*limit*/);
450*ec779b8eSAndroid Build Coastguard Worker }
451*ec779b8eSAndroid Build Coastguard Worker
452*ec779b8eSAndroid Build Coastguard Worker // Balance must take effect after mono conversion.
453*ec779b8eSAndroid Build Coastguard Worker // mBalance detects zero balance within the class for speed (not needed here).
454*ec779b8eSAndroid Build Coastguard Worker mBalance.setBalance(mMasterBalance.load());
455*ec779b8eSAndroid Build Coastguard Worker mBalance.process((float *)mMixerBuffer, frameCount);
456*ec779b8eSAndroid Build Coastguard Worker
457*ec779b8eSAndroid Build Coastguard Worker // prepare the buffer used to write to sink
458*ec779b8eSAndroid Build Coastguard Worker void *buffer = mSinkBuffer != nullptr ? mSinkBuffer : mMixerBuffer;
459*ec779b8eSAndroid Build Coastguard Worker if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
460*ec779b8eSAndroid Build Coastguard Worker memcpy_by_audio_format(buffer, mFormat.mFormat, mMixerBuffer, mMixerBufferFormat,
461*ec779b8eSAndroid Build Coastguard Worker frameCount * Format_channelCount(mFormat));
462*ec779b8eSAndroid Build Coastguard Worker }
463*ec779b8eSAndroid Build Coastguard Worker if (mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
464*ec779b8eSAndroid Build Coastguard Worker // When there are haptic channels, the sample data is partially interleaved.
465*ec779b8eSAndroid Build Coastguard Worker // Make the sample data fully interleaved here.
466*ec779b8eSAndroid Build Coastguard Worker adjust_channels_non_destructive(buffer, mAudioChannelCount, buffer, mSinkChannelCount,
467*ec779b8eSAndroid Build Coastguard Worker audio_bytes_per_sample(mFormat.mFormat),
468*ec779b8eSAndroid Build Coastguard Worker frameCount * audio_bytes_per_frame(mAudioChannelCount, mFormat.mFormat));
469*ec779b8eSAndroid Build Coastguard Worker }
470*ec779b8eSAndroid Build Coastguard Worker // if non-nullptr, then duplicate write() to this non-blocking sink
471*ec779b8eSAndroid Build Coastguard Worker #ifdef TEE_SINK
472*ec779b8eSAndroid Build Coastguard Worker mTee.write(buffer, frameCount);
473*ec779b8eSAndroid Build Coastguard Worker #endif
474*ec779b8eSAndroid Build Coastguard Worker // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
475*ec779b8eSAndroid Build Coastguard Worker // but this code should be modified to handle both non-blocking and blocking sinks
476*ec779b8eSAndroid Build Coastguard Worker dumpState->mWriteSequence++;
477*ec779b8eSAndroid Build Coastguard Worker ATRACE_BEGIN("write");
478*ec779b8eSAndroid Build Coastguard Worker const ssize_t framesWritten = mOutputSink->write(buffer, frameCount);
479*ec779b8eSAndroid Build Coastguard Worker ATRACE_END();
480*ec779b8eSAndroid Build Coastguard Worker dumpState->mWriteSequence++;
481*ec779b8eSAndroid Build Coastguard Worker if (framesWritten >= 0) {
482*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) framesWritten <= frameCount);
483*ec779b8eSAndroid Build Coastguard Worker mTotalNativeFramesWritten += framesWritten;
484*ec779b8eSAndroid Build Coastguard Worker dumpState->mFramesWritten = mTotalNativeFramesWritten;
485*ec779b8eSAndroid Build Coastguard Worker //if ((size_t) framesWritten == frameCount) {
486*ec779b8eSAndroid Build Coastguard Worker // didFullWrite = true;
487*ec779b8eSAndroid Build Coastguard Worker //}
488*ec779b8eSAndroid Build Coastguard Worker } else {
489*ec779b8eSAndroid Build Coastguard Worker dumpState->mWriteErrors++;
490*ec779b8eSAndroid Build Coastguard Worker }
491*ec779b8eSAndroid Build Coastguard Worker mAttemptedWrite = true;
492*ec779b8eSAndroid Build Coastguard Worker // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
493*ec779b8eSAndroid Build Coastguard Worker
494*ec779b8eSAndroid Build Coastguard Worker if (mIsWarm) {
495*ec779b8eSAndroid Build Coastguard Worker ExtendedTimestamp timestamp; // local
496*ec779b8eSAndroid Build Coastguard Worker status_t status = mOutputSink->getTimestamp(timestamp);
497*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
498*ec779b8eSAndroid Build Coastguard Worker dumpState->mTimestampVerifier.add(
499*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
500*ec779b8eSAndroid Build Coastguard Worker timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
501*ec779b8eSAndroid Build Coastguard Worker mSampleRate);
502*ec779b8eSAndroid Build Coastguard Worker const int64_t totalNativeFramesPresented =
503*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
504*ec779b8eSAndroid Build Coastguard Worker if (totalNativeFramesPresented <= mTotalNativeFramesWritten) {
505*ec779b8eSAndroid Build Coastguard Worker mNativeFramesWrittenButNotPresented =
506*ec779b8eSAndroid Build Coastguard Worker mTotalNativeFramesWritten - totalNativeFramesPresented;
507*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
508*ec779b8eSAndroid Build Coastguard Worker timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
509*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
510*ec779b8eSAndroid Build Coastguard Worker timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
511*ec779b8eSAndroid Build Coastguard Worker // We don't compensate for server - kernel time difference and
512*ec779b8eSAndroid Build Coastguard Worker // only update latency if we have valid info.
513*ec779b8eSAndroid Build Coastguard Worker const double latencyMs =
514*ec779b8eSAndroid Build Coastguard Worker (double)mNativeFramesWrittenButNotPresented * 1000 / mSampleRate;
515*ec779b8eSAndroid Build Coastguard Worker dumpState->mLatencyMs = latencyMs;
516*ec779b8eSAndroid Build Coastguard Worker LOG_LATENCY(latencyMs);
517*ec779b8eSAndroid Build Coastguard Worker } else {
518*ec779b8eSAndroid Build Coastguard Worker // HAL reported that more frames were presented than were written
519*ec779b8eSAndroid Build Coastguard Worker mNativeFramesWrittenButNotPresented = 0;
520*ec779b8eSAndroid Build Coastguard Worker status = INVALID_OPERATION;
521*ec779b8eSAndroid Build Coastguard Worker }
522*ec779b8eSAndroid Build Coastguard Worker } else {
523*ec779b8eSAndroid Build Coastguard Worker dumpState->mTimestampVerifier.error();
524*ec779b8eSAndroid Build Coastguard Worker }
525*ec779b8eSAndroid Build Coastguard Worker if (status == NO_ERROR) {
526*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
527*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
528*ec779b8eSAndroid Build Coastguard Worker } else {
529*ec779b8eSAndroid Build Coastguard Worker // fetch server time if we can't get timestamp
530*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] =
531*ec779b8eSAndroid Build Coastguard Worker systemTime(SYSTEM_TIME_MONOTONIC);
532*ec779b8eSAndroid Build Coastguard Worker // clear out kernel cached position as this may get rapidly stale
533*ec779b8eSAndroid Build Coastguard Worker // if we never get a new valid timestamp
534*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = 0;
535*ec779b8eSAndroid Build Coastguard Worker mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = -1;
536*ec779b8eSAndroid Build Coastguard Worker }
537*ec779b8eSAndroid Build Coastguard Worker }
538*ec779b8eSAndroid Build Coastguard Worker }
539*ec779b8eSAndroid Build Coastguard Worker }
540*ec779b8eSAndroid Build Coastguard Worker
541*ec779b8eSAndroid Build Coastguard Worker } // namespace android
542