// FastMixer线程,负责进行mix fast track,从MonoPipe中获取数据,
// 经过mix运算,输出到AudioStreamOutSink中
bool FastMixer::threadLoop()
{
static const FastMixerState initial;
const FastMixerState *previous = &initial, *current = &initial;
FastMixerState preIdle; // copy of state before we went into idle
struct timespec oldTs = {0, 0};
bool oldTsValid = false;
long slopNs = 0; // accumulated time we've woken up too early (> 0) or too late (< 0)
long sleepNs = -1; // -1: busy wait, 0: sched_yield, > 0: nanosleep
int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks
int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration
unsigned i;
for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
fastTrackNames[i] = -1;
generations[i] = 0;
}
NBAIO_Sink *outputSink = NULL;
int outputSinkGen = 0;
AudioMixer* mixer = NULL;
short *mixBuffer = NULL;
enum {UNDEFINED, MIXED, ZEROED} mixBufferState = UNDEFINED;
NBAIO_Format format = Format_Invalid;
unsigned sampleRate = 0;
int fastTracksGen = 0;
long periodNs = 0; // expected period; the time required to render one mix buffer
long underrunNs = 0; // underrun likely when write cycle is greater than this value
long overrunNs = 0; // overrun likely when write cycle is less than this value
long forceNs = 0; // if overrun detected, force the write cycle to take this much time
long warmupNs = 0; // warmup complete when write cycle is greater than to this value
FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState;
bool ignoreNextOverrun = true; // used to ignore initial overrun and first after an underrun
#ifdef FAST_MIXER_STATISTICS
struct timespec oldLoad = {0, 0}; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
bool oldLoadValid = false; // whether oldLoad is valid
uint32_t bounds = 0;
bool full = false; // whether we have collected at least mSamplingN samples
#ifdef CPU_FREQUENCY_STATISTICS
ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz
#endif
#endif
unsigned coldGen = 0; // last observed mColdGen
bool isWarm = false; // true means ready to mix, false means wait for warmup before mixing
struct timespec measuredWarmupTs = {0, 0}; // how long did it take for warmup to complete
uint32_t warmupCycles = 0; // counter of number of loop cycles required to warmup
NBAIO_Sink* teeSink = NULL; // if non-NULL, then duplicate write() to this non-blocking sink
NBLog::Writer dummyLogWriter, *logWriter = &dummyLogWriter;
uint32_t totalNativeFramesWritten = 0; // copied to dumpState->mFramesWritten
// next 2 fields are valid only when timestampStatus == NO_ERROR
AudioTimestamp timestamp;
uint32_t nativeFramesWrittenButNotPresented = 0; // the = 0 is to silence the compiler
status_t timestampStatus = INVALID_OPERATION;
for (;;) {
// either nanosleep, sched_yield, or busy wait
if (sleepNs >= 0) {
if (sleepNs > 0) {
ALOG_ASSERT(sleepNs < 1000000000);
const struct timespec req = {0, sleepNs};
nanosleep(&req, NULL);
} else {
sched_yield();
}
}
// default to long sleep for next cycle
sleepNs = FAST_DEFAULT_NS;
// poll for state change
const FastMixerState *next = mSQ.poll();
if (next == NULL) {
// continue to use the default initial state until a real state is available
ALOG_ASSERT(current == &initial && previous == &initial);
next = current;
}
FastMixerState::Command command = next->mCommand;
if (next != current) {
// As soon as possible of learning of a new dump area, start using it
dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState;
teeSink = next->mTeeSink;
logWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &dummyLogWriter;
if (mixer != NULL) {
mixer->setLog(logWriter);
}
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.
// So when there is a transition from a non-idle state into an idle state, we make a
// copy of the last known non-idle state so it is still available on return from idle.
// The possible transitions are:
// non-idle -> non-idle update previous from current in-place
// non-idle -> idle update previous from copy of current
// idle -> idle don't update previous
// idle -> non-idle don't update previous
if (!(current->mCommand & FastMixerState::IDLE)) {
if (command & FastMixerState::IDLE) {
preIdle = *current;
current = &preIdle;
oldTsValid = false;
#ifdef FAST_MIXER_STATISTICS
oldLoadValid = false;
#endif
ignoreNextOverrun = true;
}
previous = current;
}
current = next;
}
#if !LOG_NDEBUG
next = NULL; // not referenced again
#endif
dumpState->mCommand = command;
switch (command) {
case FastMixerState::INITIAL:
case FastMixerState::HOT_IDLE:
sleepNs = FAST_HOT_IDLE_NS;
continue;
Audio笔记之FastMixer
最新推荐文章于 2024-05-07 19:09:49 发布
FastMixer线程负责快速混合MonoPipe中的数据,并将其输出到AudioStreamOutSink。循环中,它检查状态变化,进行混合运算,处理不同状态如初始化、空闲和混合操作。此外,它还涉及错误处理、睡眠时间和性能统计。
摘要由CSDN通过智能技术生成