FastMixer.cpp revision e58ccce45598bcf4b4874b0e87cd1eb8d05ba9a9
197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten/* 297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * Copyright (C) 2012 The Android Open Source Project 397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * 497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * you may not use this file except in compliance with the License. 697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * You may obtain a copy of the License at 797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * 897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * 1097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * Unless required by applicable law or agreed to in writing, software 1197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 1297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * See the License for the specific language governing permissions and 1497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten * limitations under the License. 1597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten */ 1697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 1797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#define LOG_TAG "FastMixer" 1897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten//#define LOG_NDEBUG 0 1997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 20d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten//#define ATRACE_TAG ATRACE_TAG_AUDIO 21d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten 2297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include <sys/atomics.h> 2397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include <time.h> 2497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include <utils/Log.h> 25d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten#include <utils/Trace.h> 2697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include <system/audio.h> 2797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#ifdef FAST_MIXER_STATISTICS 2897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include <cpustats/CentralTendencyStatistics.h> 2942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten#include <cpustats/ThreadCpuUsage.h> 3097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 3197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include "AudioMixer.h" 3297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#include "FastMixer.h" 3397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 3497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling 3597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep 36288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten#define MAX_WARMUP_CYCLES 10 // maximum number of loop cycles to wait for warmup 3797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 3897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kastennamespace android { 3997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 4097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten// Fast mixer thread 4197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kastenbool FastMixer::threadLoop() 4297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten{ 4397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten static const FastMixerState initial; 4497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastMixerState *previous = &initial, *current = &initial; 4597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten FastMixerState preIdle; // copy of state before we went into idle 4697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten struct timespec oldTs = {0, 0}; 4797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten bool oldTsValid = false; 4897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten long slopNs = 0; // accumulated time we've woken up too early (> 0) or too late (< 0) 4997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten long sleepNs = -1; // -1: busy wait, 0: sched_yield, > 0: nanosleep 5097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks 5197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration 5297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned i; 5397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 5497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTrackNames[i] = -1; 5597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten generations[i] = 0; 5697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 5797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten NBAIO_Sink *outputSink = NULL; 5897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int outputSinkGen = 0; 5997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten AudioMixer* mixer = NULL; 6097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten short *mixBuffer = NULL; 6197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten enum {UNDEFINED, MIXED, ZEROED} mixBufferState = UNDEFINED; 6297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten NBAIO_Format format = Format_Invalid; 6397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned sampleRate = 0; 6497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int fastTracksGen = 0; 6597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten long periodNs = 0; // expected period; the time required to render one mix buffer 66288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten long underrunNs = 0; // underrun likely when write cycle is greater than this value 67288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten long overrunNs = 0; // overrun likely when write cycle is less than this value 68288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten long warmupNs = 0; // warmup complete when write cycle is greater than to this value 6997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState; 7097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten bool ignoreNextOverrun = true; // used to ignore initial overrun and first after an underrun 7197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#ifdef FAST_MIXER_STATISTICS 7242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten struct timespec oldLoad = {0, 0}; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID) 7342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten bool oldLoadValid = false; // whether oldLoad is valid 7442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t bounds = 0; 7542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten bool full = false; // whether we have collected at least kSamplingN samples 7642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz 7797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 7897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned coldGen = 0; // last observed mColdGen 79288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten bool isWarm = false; // true means ready to mix, false means wait for warmup before mixing 80288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten struct timespec measuredWarmupTs = {0, 0}; // how long did it take for warmup to complete 81288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten uint32_t warmupCycles = 0; // counter of number of loop cycles required to warmup 8297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 8397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten for (;;) { 8497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 8597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // either nanosleep, sched_yield, or busy wait 8697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (sleepNs >= 0) { 8797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (sleepNs > 0) { 8897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(sleepNs < 1000000000); 8997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const struct timespec req = {0, sleepNs}; 9097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten nanosleep(&req, NULL); 9197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 9297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sched_yield(); 9397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 9497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 9597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // default to long sleep for next cycle 9697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = FAST_DEFAULT_NS; 9797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 9897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // poll for state change 9997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastMixerState *next = mSQ.poll(); 10097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (next == NULL) { 10197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // continue to use the default initial state until a real state is available 10297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(current == &initial && previous == &initial); 10397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten next = current; 10497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 10597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 10697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten FastMixerState::Command command = next->mCommand; 10797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (next != current) { 10897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 10997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // As soon as possible of learning of a new dump area, start using it 11097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState; 11197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 11297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // We want to always have a valid reference to the previous (non-idle) state. 11397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // However, the state queue only guarantees access to current and previous states. 11497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // So when there is a transition from a non-idle state into an idle state, we make a 11597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // copy of the last known non-idle state so it is still available on return from idle. 11697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // The possible transitions are: 11797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // non-idle -> non-idle update previous from current in-place 11897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // non-idle -> idle update previous from copy of current 11997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // idle -> idle don't update previous 12097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // idle -> non-idle don't update previous 12197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (!(current->mCommand & FastMixerState::IDLE)) { 12297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (command & FastMixerState::IDLE) { 12397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten preIdle = *current; 12497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten current = &preIdle; 12597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten oldTsValid = false; 12642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten oldLoadValid = false; 12797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ignoreNextOverrun = true; 12897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 12997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten previous = current; 13097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 13197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten current = next; 13297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 13397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#if !LOG_NDEBUG 13497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten next = NULL; // not referenced again 13597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 13697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 13797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mCommand = command; 13897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 13997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten switch (command) { 14097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::INITIAL: 14197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::HOT_IDLE: 14297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = FAST_HOT_IDLE_NS; 14397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten continue; 14497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::COLD_IDLE: 14597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // only perform a cold idle command once 14621e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten // FIXME consider checking previous state and only perform if previous != COLD_IDLE 14797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (current->mColdGen != coldGen) { 14897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int32_t *coldFutexAddr = current->mColdFutexAddr; 14997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(coldFutexAddr != NULL); 15097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int32_t old = android_atomic_dec(coldFutexAddr); 15197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (old <= 0) { 15297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL); 15397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 154288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // This may be overly conservative; there could be times that the normal mixer 155288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // requests such a brief cold idle that it doesn't require resetting this flag. 156288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten isWarm = false; 157288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_sec = 0; 158288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_nsec = 0; 159288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten warmupCycles = 0; 16097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = -1; 16197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten coldGen = current->mColdGen; 16242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten bounds = 0; 16342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten full = false; 16497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 16597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = FAST_HOT_IDLE_NS; 16697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 16797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten continue; 16897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::EXIT: 16997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten delete mixer; 17097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten delete[] mixBuffer; 17197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten return false; 17297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::MIX: 17397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::WRITE: 17497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::MIX_WRITE: 17597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 17697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten default: 17797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten LOG_FATAL("bad command %d", command); 17897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 17997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 18097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // there is a non-idle state available to us; did the state change? 18197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten size_t frameCount = current->mFrameCount; 18297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (current != previous) { 18397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 18497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // handle state change here, but since we want to diff the state, 18597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // we're prepared for previous == &initial the first time through 18697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned previousTrackMask; 18797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 18897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // check for change in output HAL configuration 18997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten NBAIO_Format previousFormat = format; 19097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (current->mOutputSinkGen != outputSinkGen) { 19197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten outputSink = current->mOutputSink; 19297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten outputSinkGen = current->mOutputSinkGen; 19397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (outputSink == NULL) { 19497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten format = Format_Invalid; 19597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sampleRate = 0; 19697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 19797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten format = outputSink->format(); 19897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sampleRate = Format_sampleRate(format); 19997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(Format_channelCount(format) == 2); 20097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 20121e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten dumpState->mSampleRate = sampleRate; 20297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 20397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 20497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if ((format != previousFormat) || (frameCount != previous->mFrameCount)) { 20597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME to avoid priority inversion, don't delete here 20697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten delete mixer; 20797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer = NULL; 20897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten delete[] mixBuffer; 20997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBuffer = NULL; 21097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (frameCount > 0 && sampleRate > 0) { 21197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME new may block for unbounded time at internal mutex of the heap 21297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // implementation; it would be better to have normal mixer allocate for us 21397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // to avoid blocking here and to prevent possible priority inversion 21497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks); 21597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBuffer = new short[frameCount * 2]; 21697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 21797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 21897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25 219288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50 22097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 22197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten periodNs = 0; 22297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten underrunNs = 0; 22397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten overrunNs = 0; 22497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 22597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBufferState = UNDEFINED; 22697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#if !LOG_NDEBUG 22797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 22897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTrackNames[i] = -1; 22997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 23097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 23197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // we need to reconfigure all active tracks 23297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten previousTrackMask = 0; 23397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTracksGen = current->mFastTracksGen - 1; 23421e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten dumpState->mFrameCount = frameCount; 23597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 23697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten previousTrackMask = previous->mTrackMask; 23797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 23897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 23997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // check for change in active track set 24097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned currentTrackMask = current->mTrackMask; 24197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (current->mFastTracksGen != fastTracksGen) { 24297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(mixBuffer != NULL); 24397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int name; 24497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 24597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // process removed tracks first to avoid running out of track names 24697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned removedTracks = previousTrackMask & ~currentTrackMask; 24797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten while (removedTracks != 0) { 24897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten i = __builtin_ctz(removedTracks); 24997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten removedTracks &= ~(1 << i); 25097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastTrack* fastTrack = ¤t->mFastTracks[i]; 251288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten ALOG_ASSERT(fastTrack->mBufferProvider == NULL); 25297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (mixer != NULL) { 25397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten name = fastTrackNames[i]; 25497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(name >= 0); 25597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->deleteTrackName(name); 25697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 25797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#if !LOG_NDEBUG 25897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTrackNames[i] = -1; 25997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 260288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // don't reset track dump state, since other side is ignoring it 26197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten generations[i] = fastTrack->mGeneration; 26297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 26397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 26497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // now process added tracks 26597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned addedTracks = currentTrackMask & ~previousTrackMask; 26697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten while (addedTracks != 0) { 26797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten i = __builtin_ctz(addedTracks); 26897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten addedTracks &= ~(1 << i); 26997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastTrack* fastTrack = ¤t->mFastTracks[i]; 27097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 27197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); 27297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (mixer != NULL) { 2739bd23229fdec1657398abc682ccccfce1c95f8aaJean-Michel Trivi // calling getTrackName with default channel mask 2749bd23229fdec1657398abc682ccccfce1c95f8aaJean-Michel Trivi name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO); 27597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(name >= 0); 27697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTrackNames[i] = name; 27797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setBufferProvider(name, bufferProvider); 27897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 27997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (void *) mixBuffer); 28097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // newly allocated track names default to full scale volume 28121e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten if (fastTrack->mSampleRate != 0 && fastTrack->mSampleRate != sampleRate) { 28221e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mixer->setParameter(name, AudioMixer::RESAMPLE, 28321e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate); 28421e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten } 28521e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 28621e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten (void *) fastTrack->mChannelMask); 28797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->enable(name); 28897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 28997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten generations[i] = fastTrack->mGeneration; 29097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 29197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 29297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // finally process modified tracks; these use the same slot 29397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // but may have a different buffer provider or volume provider 29497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten unsigned modifiedTracks = currentTrackMask & previousTrackMask; 29597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten while (modifiedTracks != 0) { 29697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten i = __builtin_ctz(modifiedTracks); 29797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten modifiedTracks &= ~(1 << i); 29897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastTrack* fastTrack = ¤t->mFastTracks[i]; 29997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (fastTrack->mGeneration != generations[i]) { 30097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 30197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(bufferProvider != NULL); 30297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (mixer != NULL) { 30397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten name = fastTrackNames[i]; 30497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(name >= 0); 30597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setBufferProvider(name, bufferProvider); 30697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (fastTrack->mVolumeProvider == NULL) { 30797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 30897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (void *)0x1000); 30997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 31097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (void *)0x1000); 31197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 31221e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten if (fastTrack->mSampleRate != 0 && 31321e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten fastTrack->mSampleRate != sampleRate) { 31421e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mixer->setParameter(name, AudioMixer::RESAMPLE, 31521e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate); 31621e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten } else { 31721e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mixer->setParameter(name, AudioMixer::RESAMPLE, 31821e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten AudioMixer::REMOVE, NULL); 31921e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten } 32021e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 32121e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten (void *) fastTrack->mChannelMask); 32297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // already enabled 32397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 32497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten generations[i] = fastTrack->mGeneration; 32597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 32697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 32797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 32897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fastTracksGen = current->mFastTracksGen; 32997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 33097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mNumTracks = popcount(currentTrackMask); 33197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 33297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 33397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#if 1 // FIXME shouldn't need this 33497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // only process state change once 33597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten previous = current; 33697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 33797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 33897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 33997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // do work using current state here 340288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) { 34197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(mixBuffer != NULL); 342288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // for each track, update volume and check for underrun 343288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten unsigned currentTrackMask = current->mTrackMask; 344288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten while (currentTrackMask != 0) { 345288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten i = __builtin_ctz(currentTrackMask); 346288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten currentTrackMask &= ~(1 << i); 34797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten const FastTrack* fastTrack = ¤t->mFastTracks[i]; 34897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int name = fastTrackNames[i]; 34997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOG_ASSERT(name >= 0); 35097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (fastTrack->mVolumeProvider != NULL) { 35197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 35297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 35397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (void *)(vlr & 0xFFFF)); 35497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 35597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (void *)(vlr >> 16)); 35697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 357288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // FIXME The current implementation of framesReady() for fast tracks 358288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // takes a tryLock, which can block 359288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // up to 1 ms. If enough active tracks all blocked in sequence, this would result 360288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // in the overall fast mix cycle being delayed. Should use a non-blocking FIFO. 361288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten size_t framesReady = fastTrack->mBufferProvider->framesReady(); 362288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten FastTrackDump *ftDump = &dumpState->mTracks[i]; 363288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten uint32_t underruns = ftDump->mUnderruns; 364288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if (framesReady < frameCount) { 365d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten ATRACE_INT("underrun", i); 366288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten ftDump->mUnderruns = (underruns + 2) | 1; 367288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if (framesReady == 0) { 368288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mixer->disable(name); 369288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } else { 370288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // allow mixing partial buffer 371288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mixer->enable(name); 372288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } 373288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } else if (underruns & 1) { 374288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten ftDump->mUnderruns = underruns & ~1; 375288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mixer->enable(name); 376288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } 37797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 37897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // process() is CPU-bound 37997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixer->process(AudioBufferProvider::kInvalidPTS); 38097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBufferState = MIXED; 38197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else if (mixBufferState == MIXED) { 38297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBufferState = UNDEFINED; 38397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 384288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten bool attemptedWrite = false; 385288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten //bool didFullWrite = false; // dumpsys could display a count of partial writes 38697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) { 38797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (mixBufferState == UNDEFINED) { 38897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten memset(mixBuffer, 0, frameCount * 2 * sizeof(short)); 38997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mixBufferState = ZEROED; 39097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 39197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 39297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // but this code should be modified to handle both non-blocking and blocking sinks 39397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mWriteSequence++; 394d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten Tracer::traceBegin(ATRACE_TAG, "write"); 39597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ssize_t framesWritten = outputSink->write(mixBuffer, frameCount); 396d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten Tracer::traceEnd(ATRACE_TAG); 39797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mWriteSequence++; 39897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (framesWritten >= 0) { 399288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten ALOG_ASSERT(framesWritten <= frameCount); 40097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mFramesWritten += framesWritten; 401288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten //if ((size_t) framesWritten == frameCount) { 402288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // didFullWrite = true; 403288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten //} 40497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 40597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mWriteErrors++; 40697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 407288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten attemptedWrite = true; 40897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 40997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 41097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 41197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // To be exactly periodic, compute the next sleep time based on current time. 41297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // This code doesn't have long-term stability when the sink is non-blocking. 41397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME To avoid drift, use the local audio clock or watch the sink's fill status. 41497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten struct timespec newTs; 41597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 41697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (rc == 0) { 41797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (oldTsValid) { 41897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten time_t sec = newTs.tv_sec - oldTs.tv_sec; 41997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten long nsec = newTs.tv_nsec - oldTs.tv_nsec; 42097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (nsec < 0) { 42197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten --sec; 42297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten nsec += 1000000000; 42397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 424288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // To avoid an initial underrun on fast tracks after exiting standby, 425288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // do not start pulling data from tracks and mixing until warmup is complete. 426288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // Warmup is considered complete after the earlier of: 427288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // first successful single write() that blocks for more than warmupNs 428288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // MAX_WARMUP_CYCLES write() attempts. 429288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten // This is overly conservative, but to get better accuracy requires a new HAL API. 430288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if (!isWarm && attemptedWrite) { 431288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_sec += sec; 432288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_nsec += nsec; 433288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if (measuredWarmupTs.tv_nsec >= 1000000000) { 434288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_sec++; 435288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten measuredWarmupTs.tv_nsec -= 1000000000; 436288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } 437288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten ++warmupCycles; 438288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten if ((attemptedWrite && nsec > warmupNs) || 439288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten (warmupCycles >= MAX_WARMUP_CYCLES)) { 440288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten isWarm = true; 441288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten dumpState->mMeasuredWarmupTs = measuredWarmupTs; 442288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten dumpState->mWarmupCycles = warmupCycles; 443288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } 444288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten } 44597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (sec > 0 || nsec > underrunNs) { 446d8e6fd35ec2b59ee7d873daf1f1d9d348221c7bcGlenn Kasten ScopedTrace st(ATRACE_TAG, "underrun"); 44797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME only log occasionally 44897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOGV("underrun: time since last cycle %d.%03ld sec", 44997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (int) sec, nsec / 1000000L); 45097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mUnderruns++; 45197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = -1; 45297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ignoreNextOverrun = true; 45397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else if (nsec < overrunNs) { 45497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten if (ignoreNextOverrun) { 45597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ignoreNextOverrun = false; 45697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 45797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // FIXME only log occasionally 45897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ALOGV("overrun: time since last cycle %d.%03ld sec", 45997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten (int) sec, nsec / 1000000L); 46097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten dumpState->mOverruns++; 46197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 46297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = periodNs - overrunNs; 46397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 46497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = -1; 46597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ignoreNextOverrun = false; 46697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 46797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#ifdef FAST_MIXER_STATISTICS 46842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // advance the FIFO queue bounds 46942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten size_t i = bounds & (FastMixerDumpState::kSamplingN - 1); 470e58ccce45598bcf4b4874b0e87cd1eb8d05ba9a9Glenn Kasten bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF); 47142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (full) { 47242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten bounds += 0x10000; 47342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } else if (!(bounds & (FastMixerDumpState::kSamplingN - 1))) { 47442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten full = true; 47597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 47642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // compute the delta value of clock_gettime(CLOCK_MONOTONIC) 47742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t monotonicNs = nsec; 47842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (sec > 0 && sec < 4) { 47942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten monotonicNs += sec * 1000000000; 48042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 48142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // compute the raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID) 48242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t loadNs = 0; 48342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten struct timespec newLoad; 48442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad); 48542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (rc == 0) { 48642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (oldLoadValid) { 48742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten sec = newLoad.tv_sec - oldLoad.tv_sec; 48842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten nsec = newLoad.tv_nsec - oldLoad.tv_nsec; 48942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (nsec < 0) { 49042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten --sec; 49142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten nsec += 1000000000; 49242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 49342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadNs = nsec; 49442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (sec > 0 && sec < 4) { 49542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadNs += sec * 1000000000; 49642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 49742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } else { 49842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // first time through the loop 49942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten oldLoadValid = true; 50042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 50142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten oldLoad = newLoad; 50242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 50342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // get the absolute value of CPU clock frequency in kHz 50442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten int cpuNum = sched_getcpu(); 50542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t kHz = tcu.getCpukHz(cpuNum); 50642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten kHz = (kHz & ~0xF) | (cpuNum & 0xF); 50742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // save values in FIFO queues for dumpsys 50842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // these stores #1, #2, #3 are not atomic with respect to each other, 50942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // or with respect to store #4 below 51042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten dumpState->mMonotonicNs[i] = monotonicNs; 51142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten dumpState->mLoadNs[i] = loadNs; 51242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten dumpState->mCpukHz[i] = kHz; 51342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // this store #4 is not atomic with respect to stores #1, #2, #3 above, but 51442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // the newest open and oldest closed halves are atomic with respect to each other 51542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten dumpState->mBounds = bounds; 51697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 51797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 51897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // first time through the loop 51997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten oldTsValid = true; 52097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = periodNs; 52197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten ignoreNextOverrun = true; 52297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 52397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten oldTs = newTs; 52497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } else { 52597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // monotonic clock is broken 52697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten oldTsValid = false; 52797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten sleepNs = periodNs; 52897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 52997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 53042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten 53197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } // for (;;) 53297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 53397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion 53497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten} 53597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 53697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn KastenFastMixerDumpState::FastMixerDumpState() : 53797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0), 53821e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0), 539288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0) 54097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#ifdef FAST_MIXER_STATISTICS 54142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten , mBounds(0) 54297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 54397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten{ 544288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mMeasuredWarmupTs.tv_sec = 0; 545288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten mMeasuredWarmupTs.tv_nsec = 0; 54642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // sample arrays aren't accessed atomically with respect to the bounds, 54742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // so clearing reduces chance for dumpsys to read random uninitialized samples 54842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten memset(&mMonotonicNs, 0, sizeof(mMonotonicNs)); 54942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten memset(&mLoadNs, 0, sizeof(mLoadNs)); 55042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten memset(&mCpukHz, 0, sizeof(mCpukHz)); 55197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten} 55297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 55397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn KastenFastMixerDumpState::~FastMixerDumpState() 55497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten{ 55597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten} 55697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 55797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kastenvoid FastMixerDumpState::dump(int fd) 55897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten{ 55997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#define COMMAND_MAX 32 56097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten char string[COMMAND_MAX]; 56197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten switch (mCommand) { 56297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::INITIAL: 56397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "INITIAL"); 56497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 56597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::HOT_IDLE: 56697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "HOT_IDLE"); 56797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 56897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::COLD_IDLE: 56997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "COLD_IDLE"); 57097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 57197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::EXIT: 57297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "EXIT"); 57397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 57497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::MIX: 57597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "MIX"); 57697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 57797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::WRITE: 57897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "WRITE"); 57997b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 58097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten case FastMixerState::MIX_WRITE: 58197b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten strcpy(string, "MIX_WRITE"); 58297b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 58397b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten default: 58497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten snprintf(string, COMMAND_MAX, "%d", mCommand); 58597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten break; 58697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten } 58742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + 588288ed2103d96f3aabd7e6bea3c080ab6db164049Glenn Kasten (mMeasuredWarmupTs.tv_nsec / 1000000.0); 58942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten double mixPeriodSec = (double) mFrameCount / (double) mSampleRate; 59097b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n" 59121e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" 59242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " sampleRate=%u frameCount=%u measuredWarmup=%.3g ms, warmupCycles=%u\n" 59342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " mixPeriod=%.2f ms\n", 59497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten string, mWriteSequence, mFramesWritten, 59521e8c50bd13ebe44f3088e26c9c6df0e163c469cGlenn Kasten mNumTracks, mWriteErrors, mUnderruns, mOverruns, 59642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, 59742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten mixPeriodSec * 1e3); 59897b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#ifdef FAST_MIXER_STATISTICS 59942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // find the interval of valid samples 60042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t bounds = mBounds; 60142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t newestOpen = bounds & 0xFFFF; 60242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t oldestClosed = bounds >> 16; 60342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; 60442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (n > kSamplingN) { 60542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten ALOGE("too many samples %u", n); 60642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten n = kSamplingN; 60742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 60842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, 60942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // and adjusted CPU load in MHz normalized for CPU clock frequency 61042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten CentralTendencyStatistics wall, loadNs, kHz, loadMHz; 61142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // only compute adjusted CPU load in Hz if current CPU number and CPU clock frequency are stable 61242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten bool valid = false; 61342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t previousCpukHz = 0; 61442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten // loop over all the samples 61542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten for (; n > 0; --n) { 61642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten size_t i = oldestClosed++ & (kSamplingN - 1); 61742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t wallNs = mMonotonicNs[i]; 61842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten wall.sample(wallNs); 61942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t sampleLoadNs = mLoadNs[i]; 62042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten uint32_t sampleCpukHz = mCpukHz[i]; 62142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadNs.sample(sampleLoadNs); 62242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten kHz.sample(sampleCpukHz & ~0xF); 62342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten if (sampleCpukHz == previousCpukHz) { 624e58ccce45598bcf4b4874b0e87cd1eb8d05ba9a9Glenn Kasten double megacycles = (double) sampleLoadNs * (double) sampleCpukHz * 1e-12; 62542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 62642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadMHz.sample(adjMHz); 62742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 62842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten previousCpukHz = sampleCpukHz; 62942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten } 63042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten fdprintf(fd, "Simple moving statistics over last %.1f seconds:\n", wall.n() * mixPeriodSec); 63142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten fdprintf(fd, " wall clock time in ms per mix cycle:\n" 63242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", 63342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, wall.stddev()*1e-6); 63442d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten fdprintf(fd, " raw CPU load in us per mix cycle:\n" 63542d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", 63642d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, 63742d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadNs.stddev()*1e-3); 63842d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten fdprintf(fd, " CPU clock frequency in MHz:\n" 63942d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", 64042d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); 64142d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten fdprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" 64242d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", 64342d45cfd0c3d62357a6549c62f535e4d4fe08d91Glenn Kasten loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); 64497b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten#endif 64597b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten} 64697b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten 64797b5d0d5b5ef766eb5dd680d05a5d199662d4ae0Glenn Kasten} // namespace android 648