FastMixer.cpp revision e8a1ced4da17dc6c07803dc2af8060f62a8389c1
1dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com/* 2dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * Copyright (C) 2012 The Android Open Source Project 3dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * 4dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 5dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * you may not use this file except in compliance with the License. 6dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * You may obtain a copy of the License at 7dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * 8dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * http://www.apache.org/licenses/LICENSE-2.0 9dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * 10dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * Unless required by applicable law or agreed to in writing, software 11dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * distributed under the License is distributed on an "AS IS" BASIS, 12dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * See the License for the specific language governing permissions and 14dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com * limitations under the License. 15dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com */ 16dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 17dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// <IMPORTANT_WARNING> 18dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// Design rules for threadLoop() are given in the comments at section "Fast mixer thread" of 19dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// StateQueue.h. In particular, avoid library and system calls except at well-known points. 20dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// The design rules are only for threadLoop(), and don't apply to FastMixerDumpState methods. 21dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// </IMPORTANT_WARNING> 22dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 23dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#define LOG_TAG "FastMixer" 24dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com//#define LOG_NDEBUG 0 25dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 26dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#define ATRACE_TAG ATRACE_TAG_AUDIO 27dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 28dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include "Configuration.h" 29dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <sys/atomics.h> 30dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <time.h> 31dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <utils/Log.h> 32dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <utils/Trace.h> 33dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <system/audio.h> 34dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 35dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <cpustats/CentralTendencyStatistics.h> 36dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef CPU_FREQUENCY_STATISTICS 37dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include <cpustats/ThreadCpuUsage.h> 38dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 39dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 40dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include "AudioMixer.h" 41dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#include "FastMixer.h" 42dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 43dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#define FCC_2 2 // fixed channel count assumption 44dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 45dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comnamespace android { 46dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 47dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com/*static*/ const FastMixerState FastMixer::initial; 48dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 49dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comFastMixer::FastMixer() : FastThread(), 50dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com slopNs(0), 51dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // fastTrackNames 52dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // generations 53dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com outputSink(NULL), 54dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com outputSinkGen(0), 55dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer(NULL), 56dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBuffer(NULL), 57dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBufferState(UNDEFINED), 58dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com format(Format_Invalid), 59dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com sampleRate(0), 60dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTracksGen(0), 61dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com totalNativeFramesWritten(0), 62dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // timestamp 63dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com nativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler 64dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 65dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME pass initial as parameter to base class constructor, and make it static local 66dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com previous = &initial; 67dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com current = &initial; 68dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 69dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mDummyDumpState = &dummyDumpState; 70dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 71dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned i; 72dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 73dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrackNames[i] = -1; 74dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com generations[i] = 0; 75dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 76dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 77dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com oldLoad.tv_sec = 0; 78dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com oldLoad.tv_nsec = 0; 79dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 80dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 81dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 82dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comFastMixer::~FastMixer() 83dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 84dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 85dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 86dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comFastMixerStateQueue* FastMixer::sq() 87dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 88dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return &mSQ; 89dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 90dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 91dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comconst FastThreadState *FastMixer::poll() 92dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 93dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return mSQ.poll(); 94dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 95dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 96dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixer::setLog(NBLog::Writer *logWriter) 97dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 98dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mixer != NULL) { 99dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setLog(logWriter); 100dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 101dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 102dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 103dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixer::onIdle() 104dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 105dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com preIdle = *(const FastMixerState *)current; 106dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com current = &preIdle; 107dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 108dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 109dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixer::onExit() 110dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 111dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com delete mixer; 112dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com delete[] mixBuffer; 113dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 114dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 115dff7e11c2000d6745261de046d76b1500a05ece9reed@google.combool FastMixer::isSubClassCommand(FastThreadState::Command command) 116dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 117dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com switch ((FastMixerState::Command) command) { 118dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::MIX: 119dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::WRITE: 120dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::MIX_WRITE: 121dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return true; 122dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com default: 123dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return false; 124dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 125dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 126dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 127dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixer::onStateChange() 128dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 129dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastMixerState * const current = (const FastMixerState *) this->current; 130dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastMixerState * const previous = (const FastMixerState *) this->previous; 131dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; 132dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const size_t frameCount = current->mFrameCount; 133dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 134dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // handle state change here, but since we want to diff the state, 135dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // we're prepared for previous == &initial the first time through 136dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned previousTrackMask; 137dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 138dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // check for change in output HAL configuration 139dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com NBAIO_Format previousFormat = format; 140dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (current->mOutputSinkGen != outputSinkGen) { 141dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com outputSink = current->mOutputSink; 142dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com outputSinkGen = current->mOutputSinkGen; 143dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (outputSink == NULL) { 144dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com format = Format_Invalid; 145dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com sampleRate = 0; 146dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 147dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com format = outputSink->format(); 148dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com sampleRate = Format_sampleRate(format); 149dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(Format_channelCount(format) == FCC_2); 150dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 151dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mSampleRate = sampleRate; 152dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 153dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 154dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) { 155dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME to avoid priority inversion, don't delete here 156dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com delete mixer; 157dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer = NULL; 158dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com delete[] mixBuffer; 159dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBuffer = NULL; 160dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (frameCount > 0 && sampleRate > 0) { 161dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME new may block for unbounded time at internal mutex of the heap 162dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // implementation; it would be better to have normal mixer allocate for us 163dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // to avoid blocking here and to prevent possible priority inversion 164dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks); 165dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBuffer = new short[frameCount * FCC_2]; 166dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 167dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 168dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50 169dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95 170dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com warmupNs = (frameCount * 500000000LL) / sampleRate; // 0.50 171dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 172dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com periodNs = 0; 173dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underrunNs = 0; 174dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com overrunNs = 0; 175dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com forceNs = 0; 176dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com warmupNs = 0; 177dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 178dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBufferState = UNDEFINED; 179dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#if !LOG_NDEBUG 180dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 181dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrackNames[i] = -1; 182dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 183dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 184dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // we need to reconfigure all active tracks 185dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com previousTrackMask = 0; 186dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTracksGen = current->mFastTracksGen - 1; 187dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mFrameCount = frameCount; 188dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 189dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com previousTrackMask = previous->mTrackMask; 190dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 191dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 192dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // check for change in active track set 193dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const unsigned currentTrackMask = current->mTrackMask; 194dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mTrackMask = currentTrackMask; 195dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (current->mFastTracksGen != fastTracksGen) { 196dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(mixBuffer != NULL); 197dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int name; 198dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 199dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // process removed tracks first to avoid running out of track names 200dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned removedTracks = previousTrackMask & ~currentTrackMask; 201dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com while (removedTracks != 0) { 202dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int i = __builtin_ctz(removedTracks); 203dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com removedTracks &= ~(1 << i); 204dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrack* fastTrack = ¤t->mFastTracks[i]; 205dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(fastTrack->mBufferProvider == NULL); 206dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mixer != NULL) { 207dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com name = fastTrackNames[i]; 208dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(name >= 0); 209dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->deleteTrackName(name); 210dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 211dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#if !LOG_NDEBUG 212dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrackNames[i] = -1; 213dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 214dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // don't reset track dump state, since other side is ignoring it 215dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com generations[i] = fastTrack->mGeneration; 216dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 217dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 218dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // now process added tracks 219dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned addedTracks = currentTrackMask & ~previousTrackMask; 220dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com while (addedTracks != 0) { 221dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int i = __builtin_ctz(addedTracks); 222dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com addedTracks &= ~(1 << i); 223dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrack* fastTrack = ¤t->mFastTracks[i]; 224dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 225dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); 226dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mixer != NULL) { 227dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com name = mixer->getTrackName(fastTrack->mChannelMask, 228dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX); 229dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(name >= 0); 230dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrackNames[i] = name; 231dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setBufferProvider(name, bufferProvider); 232dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 233dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *) mixBuffer); 234dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // newly allocated track names default to full scale volume 235dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->enable(name); 236dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 237dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com generations[i] = fastTrack->mGeneration; 238dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 239dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 240dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // finally process (potentially) modified tracks; these use the same slot 241dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // but may have a different buffer provider or volume provider 242dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned modifiedTracks = currentTrackMask & previousTrackMask; 243dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com while (modifiedTracks != 0) { 244dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int i = __builtin_ctz(modifiedTracks); 245dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com modifiedTracks &= ~(1 << i); 246dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrack* fastTrack = ¤t->mFastTracks[i]; 247dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (fastTrack->mGeneration != generations[i]) { 248dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // this track was actually modified 249dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 250dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(bufferProvider != NULL); 251dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mixer != NULL) { 252dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com name = fastTrackNames[i]; 253dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(name >= 0); 254dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setBufferProvider(name, bufferProvider); 255dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (fastTrack->mVolumeProvider == NULL) { 256dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 257dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *)0x1000); 258dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 259dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *)0x1000); 260dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 261dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::RESAMPLE, 262dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com AudioMixer::REMOVE, NULL); 263dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 264dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *)(uintptr_t) fastTrack->mChannelMask); 265dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // already enabled 266dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 267dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com generations[i] = fastTrack->mGeneration; 268dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 269dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 270dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 271dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTracksGen = current->mFastTracksGen; 272dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 273dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mNumTracks = popcount(currentTrackMask); 274dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 275dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 276dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 277dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixer::onWork() 278dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 279dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastMixerState * const current = (const FastMixerState *) this->current; 280dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; 281dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastMixerState::Command command = this->command; 282dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const size_t frameCount = current->mFrameCount; 283dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 284dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) { 285dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(mixBuffer != NULL); 286dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // for each track, update volume and check for underrun 287dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com unsigned currentTrackMask = current->mTrackMask; 288dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com while (currentTrackMask != 0) { 289dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int i = __builtin_ctz(currentTrackMask); 290dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com currentTrackMask &= ~(1 << i); 291dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrack* fastTrack = ¤t->mFastTracks[i]; 292dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 293dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // Refresh the per-track timestamp 294dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (timestampStatus == NO_ERROR) { 295dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t trackFramesWrittenButNotPresented = 296dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com nativeFramesWrittenButNotPresented; 297dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased(); 298dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // Can't provide an AudioTimestamp before first frame presented, 299dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // or during the brief 32-bit wraparound window 300dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (trackFramesWritten >= trackFramesWrittenButNotPresented) { 301dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com AudioTimestamp perTrackTimestamp; 302dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com perTrackTimestamp.mPosition = 303dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com trackFramesWritten - trackFramesWrittenButNotPresented; 304dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com perTrackTimestamp.mTime = timestamp.mTime; 305dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp); 306dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 307dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 308dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 309dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int name = fastTrackNames[i]; 310dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT(name >= 0); 311dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (fastTrack->mVolumeProvider != NULL) { 312dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 313dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 314dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *)(uintptr_t)(vlr & 0xFFFF)); 315dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 316dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void *)(uintptr_t)(vlr >> 16)); 317dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 318dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME The current implementation of framesReady() for fast tracks 319dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // takes a tryLock, which can block 320dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // up to 1 ms. If enough active tracks all blocked in sequence, this would result 321dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // in the overall fast mix cycle being delayed. Should use a non-blocking FIFO. 322dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com size_t framesReady = fastTrack->mBufferProvider->framesReady(); 323dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (ATRACE_ENABLED()) { 324dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // I wish we had formatted trace names 325dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com char traceName[16]; 326dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(traceName, "fRdy"); 327dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com traceName[4] = i + (i < 10 ? '0' : 'A' - 10); 328dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com traceName[5] = '\0'; 329dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ATRACE_INT(traceName, framesReady); 330dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 331dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com FastTrackDump *ftDump = &dumpState->mTracks[i]; 332dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com FastTrackUnderruns underruns = ftDump->mUnderruns; 333dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (framesReady < frameCount) { 334dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (framesReady == 0) { 335dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mEmpty++; 336dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY; 337dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->disable(name); 338dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 339dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // allow mixing partial buffer 340dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mPartial++; 341dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL; 342dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->enable(name); 343dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 344dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 345dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mFull++; 346dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com underruns.mBitFields.mMostRecent = UNDERRUN_FULL; 347dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->enable(name); 348dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 349dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ftDump->mUnderruns = underruns; 350dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ftDump->mFramesReady = framesReady; 351dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 352dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 353dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com int64_t pts; 354dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) { 355dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com pts = AudioBufferProvider::kInvalidPTS; 356dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 357dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 358dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // process() is CPU-bound 359dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixer->process(pts); 360dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBufferState = MIXED; 361dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else if (mixBufferState == MIXED) { 362dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBufferState = UNDEFINED; 363dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 364dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com //bool didFullWrite = false; // dumpsys could display a count of partial writes 365dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) { 366dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mixBufferState == UNDEFINED) { 367dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com memset(mixBuffer, 0, frameCount * FCC_2 * sizeof(short)); 368dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixBufferState = ZEROED; 369dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 370dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // if non-NULL, then duplicate write() to this non-blocking sink 371dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com NBAIO_Sink* teeSink; 372dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if ((teeSink = current->mTeeSink) != NULL) { 373dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (void) teeSink->write(mixBuffer, frameCount); 374dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 375dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 376dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // but this code should be modified to handle both non-blocking and blocking sinks 377dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mWriteSequence++; 378dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ATRACE_BEGIN("write"); 379dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ssize_t framesWritten = outputSink->write(mixBuffer, frameCount); 380dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ATRACE_END(); 381dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mWriteSequence++; 382dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (framesWritten >= 0) { 383dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOG_ASSERT((size_t) framesWritten <= frameCount); 384dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com totalNativeFramesWritten += framesWritten; 385dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mFramesWritten = totalNativeFramesWritten; 386dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com //if ((size_t) framesWritten == frameCount) { 387dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // didFullWrite = true; 388dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com //} 389dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 390dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com dumpState->mWriteErrors++; 391dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 392dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com attemptedWrite = true; 393dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 394dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 395dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com timestampStatus = outputSink->getTimestamp(timestamp); 396dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (timestampStatus == NO_ERROR) { 397dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t totalNativeFramesPresented = timestamp.mPosition; 398dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (totalNativeFramesPresented <= totalNativeFramesWritten) { 399dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com nativeFramesWrittenButNotPresented = 400dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com totalNativeFramesWritten - totalNativeFramesPresented; 401dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 402dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // HAL reported that more frames were presented than were written 403dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com timestampStatus = INVALID_OPERATION; 404dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 405dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 406dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 407dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 408dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 409dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comFastMixerDumpState::FastMixerDumpState( 410dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 411dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t samplingN 412dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 413dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ) : FastThreadDumpState(), 414dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mWriteSequence(0), mFramesWritten(0), 415dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mNumTracks(0), mWriteErrors(0), 416dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mSampleRate(0), mFrameCount(0), 417dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mTrackMask(0) 418dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 419dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 420dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com increaseSamplingN(samplingN); 421dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 422dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 423dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 424dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 425dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixerDumpState::increaseSamplingN(uint32_t samplingN) 426dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 427dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) { 428dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return; 429dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 430dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t additional = samplingN - mSamplingN; 431dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // sample arrays aren't accessed atomically with respect to the bounds, 432dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // so clearing reduces chance for dumpsys to read random uninitialized samples 433dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional); 434dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional); 435dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef CPU_FREQUENCY_STATISTICS 436dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional); 437dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 438dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mSamplingN = samplingN; 439dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 440dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 441dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 442dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comFastMixerDumpState::~FastMixerDumpState() 443dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 444dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 445dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 446dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com// helper function called by qsort() 447dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comstatic int compare_uint32_t(const void *pa, const void *pb) 448dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 449dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t a = *(const uint32_t *)pa; 450dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t b = *(const uint32_t *)pb; 451dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (a < b) { 452dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return -1; 453dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else if (a > b) { 454dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return 1; 455dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 456dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return 0; 457dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 458dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 459dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 460dff7e11c2000d6745261de046d76b1500a05ece9reed@google.comvoid FastMixerDumpState::dump(int fd) const 461dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com{ 462dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (mCommand == FastMixerState::INITIAL) { 463dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " FastMixer not initialized\n"); 464dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com return; 465dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 466dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#define COMMAND_MAX 32 467dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com char string[COMMAND_MAX]; 468dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com switch (mCommand) { 469dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::INITIAL: 470dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "INITIAL"); 471dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 472dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::HOT_IDLE: 473dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "HOT_IDLE"); 474dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 475dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::COLD_IDLE: 476dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "COLD_IDLE"); 477dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 478dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::EXIT: 479dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "EXIT"); 480dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 481dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::MIX: 482dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "MIX"); 483dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 484dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::WRITE: 485dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "WRITE"); 486dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 487dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case FastMixerState::MIX_WRITE: 488dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com strcpy(string, "MIX_WRITE"); 489dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 490dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com default: 491dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com snprintf(string, COMMAND_MAX, "%d", mCommand); 492dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 493dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 494dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) + 495dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (mMeasuredWarmupTs.tv_nsec / 1000000.0); 496dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com double mixPeriodSec = (double) mFrameCount / (double) mSampleRate; 497dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n" 498dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" 499dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n" 500dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " mixPeriod=%.2f ms\n", 501dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com string, mWriteSequence, mFramesWritten, 502dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mNumTracks, mWriteErrors, mUnderruns, mOverruns, 503dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles, 504dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mixPeriodSec * 1e3); 505dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef FAST_MIXER_STATISTICS 506dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // find the interval of valid samples 507dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t bounds = mBounds; 508dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t newestOpen = bounds & 0xFFFF; 509dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t oldestClosed = bounds >> 16; 510dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t n = (newestOpen - oldestClosed) & 0xFFFF; 511dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (n > mSamplingN) { 512dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com ALOGE("too many samples %u", n); 513dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com n = mSamplingN; 514dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 515dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency, 516dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // and adjusted CPU load in MHz normalized for CPU clock frequency 517dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com CentralTendencyStatistics wall, loadNs; 518dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef CPU_FREQUENCY_STATISTICS 519dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com CentralTendencyStatistics kHz, loadMHz; 520dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t previousCpukHz = 0; 521dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 522dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // Assuming a normal distribution for cycle times, three standard deviations on either side of 523dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the 524dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // sample set, we get 99.8% combined, or close to three standard deviations. 525dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com static const uint32_t kTailDenominator = 1000; 526dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL; 527dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // loop over all the samples 528dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com for (uint32_t j = 0; j < n; ++j) { 529dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com size_t i = oldestClosed++ & (mSamplingN - 1); 530dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t wallNs = mMonotonicNs[i]; 531dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (tail != NULL) { 532dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com tail[j] = wallNs; 533dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 534dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com wall.sample(wallNs); 535dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t sampleLoadNs = mLoadNs[i]; 536dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com loadNs.sample(sampleLoadNs); 537dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef CPU_FREQUENCY_STATISTICS 538dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t sampleCpukHz = mCpukHz[i]; 539dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // skip bad kHz samples 540dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if ((sampleCpukHz & ~0xF) != 0) { 541dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com kHz.sample(sampleCpukHz >> 4); 542dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (sampleCpukHz == previousCpukHz) { 543dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12; 544dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9 545dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com loadMHz.sample(adjMHz); 546dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 547dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 548dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com previousCpukHz = sampleCpukHz; 549dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 550dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 551dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (n) { 552dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " Simple moving statistics over last %.1f seconds:\n", 553dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com wall.n() * mixPeriodSec); 554dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " wall clock time in ms per mix cycle:\n" 555dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", 556dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, 557dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com wall.stddev()*1e-6); 558dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " raw CPU load in us per mix cycle:\n" 559dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", 560dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3, 561dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com loadNs.stddev()*1e-3); 562dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } else { 563dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " No FastMixer statistics available currently\n"); 564dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 565dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#ifdef CPU_FREQUENCY_STATISTICS 566dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " CPU clock frequency in MHz:\n" 567dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n", 568dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3); 569dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n" 570dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", 571dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev()); 572dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 573dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com if (tail != NULL) { 574dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com qsort(tail, n, sizeof(uint32_t), compare_uint32_t); 575dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // assume same number of tail samples on each side, left and right 576dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t count = n / kTailDenominator; 577dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com CentralTendencyStatistics left, right; 578dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com for (uint32_t i = 0; i < count; ++i) { 579dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com left.sample(tail[i]); 580dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com right.sample(tail[n - (i + 1)]); 581dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 582dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n" 583dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n" 584dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n", 585dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6, 586dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6, 587dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com right.stddev()*1e-6); 588dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com delete[] tail; 589dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 590dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com#endif 591dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // The active track mask and track states are updated non-atomically. 592dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // So if we relied on isActive to decide whether to display, 593dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // then we might display an obsolete track or omit an active track. 594dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // Instead we always display all tracks, with an indication 595dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com // of whether we think the track is active. 596dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com uint32_t trackMask = mTrackMask; 597dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n", 598dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com FastMixerState::kMaxFastTracks, trackMask); 599dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " Index Active Full Partial Empty Recent Ready\n"); 600dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) { 601dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com bool isActive = trackMask & 1; 602dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrackDump *ftDump = &mTracks[i]; 603dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const FastTrackUnderruns& underruns = ftDump->mUnderruns; 604dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com const char *mostRecent; 605dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com switch (underruns.mBitFields.mMostRecent) { 606dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case UNDERRUN_FULL: 607dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mostRecent = "full"; 608dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 609dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case UNDERRUN_PARTIAL: 610dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mostRecent = "partial"; 611dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 612dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com case UNDERRUN_EMPTY: 613dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mostRecent = "empty"; 614dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 615dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com default: 616dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mostRecent = "?"; 617dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com break; 618dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 619dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com fdprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no", 620dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (underruns.mBitFields.mFull) & UNDERRUN_MASK, 621dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (underruns.mBitFields.mPartial) & UNDERRUN_MASK, 622dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com (underruns.mBitFields.mEmpty) & UNDERRUN_MASK, 623dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com mostRecent, ftDump->mFramesReady); 624dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com } 625dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} 626dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com 627dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com} // namespace android 628dff7e11c2000d6745261de046d76b1500a05ece9reed@google.com