Audio笔记之FastMixer

// 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;
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值