FastMixer.cpp 23 KB

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