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 = &current->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 = &current->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 = &current->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 = &current->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