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