xref: /aosp_15_r20/frameworks/av/services/audioflinger/fastpath/FastMixer.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 = &current->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 = &current->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