Audio笔记之PlaybackThread::threadLoop

来源:互联网 发布:淘宝买东西后退款bug 编辑:程序博客网 时间:2024/04/26 05:35
bool AudioFlinger::PlaybackThread::threadLoop(){    Vector< sp<Track> > tracksToRemove;    standbyTime = systemTime();    // MIXER    nsecs_t lastWarning = 0;    // DUPLICATING    // FIXME could this be made local to while loop?    writeFrames = 0;    int lastGeneration = 0;    cacheParameters_l();    sleepTime = idleSleepTime;    if (mType == MIXER) {        sleepTimeShift = 0;    }    CpuStats cpuStats;    const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));    acquireWakeLock();    // mNBLogWriter->log can only be called while thread mutex mLock is held.    // So if you need to log when mutex is unlocked, set logString to a non-NULL string,    // and then that string will be logged at the next convenient opportunity.    const char *logString = NULL;    checkSilentMode_l();    while (!exitPending())    {        cpuStats.sample(myName);        Vector< sp<EffectChain> > effectChains;        processConfigEvents();        { // scope for mLock            Mutex::Autolock _l(mLock);            if (logString != NULL) {                mNBLogWriter->logTimestamp();                mNBLogWriter->log(logString);                logString = NULL;            }            if (mLatchDValid) {                mLatchQ = mLatchD;                mLatchDValid = false;                mLatchQValid = true;            }            //检查客户端设置的更新,客户端通过setParameters进行设置            if (checkForNewParameters_l()) {                cacheParameters_l();            }            saveOutputTracks();            //判断是否有track加入            if (mSignalPending) {                // A signal was raised while we were unlocked                mSignalPending = false;            } else if (waitingAsyncCallback_l()) {//offload时返回true                if (exitPending()) {                    break;                }                releaseWakeLock_l();                mWakeLockUids.clear();                mActiveTracksGeneration++;                ALOGV("wait async completion");                mWaitWorkCV.wait(mLock);                ALOGV("async completion/wake");                acquireWakeLock_l();                standbyTime = systemTime() + standbyDelay;                sleepTime = 0;                continue;            }            //两种情况需要硬件进入standby              //第一:没有活跃音轨而且standbyTime过期              //第二:需要Suspend              if ((!mActiveTracks.size() && systemTime() > standbyTime) ||                                   isSuspended()) {                // put audio hardware into standby after short delay                if (shouldStandby_l()) {                    threadLoop_standby();                    mStandby = true;                }                //如果当前config event也为空,则进入阻塞状态                if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {                    // we're about to wait, flush the binder command buffer                    IPCThreadState::self()->flushCommands();                    clearOutputTracks();                    if (exitPending()) {                        break;                    }                    releaseWakeLock_l();                    mWakeLockUids.clear();                    mActiveTracksGeneration++;                    // wait until we have something to do...                    // 当前没有可供使用的active track,进程进入阻塞状态,                    // 等待广播消息唤醒,包括配置参数、活跃音轨添加等消息                    ALOGV("%s going to sleep", myName.string());                    mWaitWorkCV.wait(mLock);                    ALOGV("%s waking up", myName.string());                    acquireWakeLock_l();                    mMixerStatus = MIXER_IDLE;                    mMixerStatusIgnoringFastTracks = MIXER_IDLE;                    mBytesWritten = 0;                    mBytesRemaining = 0;                    checkSilentMode_l();                    standbyTime = systemTime() + standbyDelay;                    sleepTime = idleSleepTime;                    if (mType == MIXER) {                        sleepTimeShift = 0;                    }                    continue;                }            }            // mMixerStatusIgnoringFastTracks is also updated internally            // 准备音轨,为混音做准备            mMixerStatus = prepareTracks_l(&tracksToRemove);            // compare with previously applied list            if (lastGeneration != mActiveTracksGeneration) {                // update wakelock                updateWakeLockUids_l(mWakeLockUids);                lastGeneration = mActiveTracksGeneration;            }            // prevent any changes in effect chain list and in each effect chain            // during mixing and effect process as the audio buffers could be deleted            // or modified if an effect is created or deleted            lockEffectChains_l(effectChains);        } // mLock scope ends        //混音处理后数据全部写入Hal之后,会将mBytesRemaining置为0        //即表示当前可以进行新一轮的Mix操作        if (mBytesRemaining == 0) {            mCurrentWriteLength = 0;            if (mMixerStatus == MIXER_TRACKS_READY) {                // threadLoop_mix() sets mCurrentWriteLength                threadLoop_mix();            } else if ((mMixerStatus != MIXER_DRAIN_TRACK)                        && (mMixerStatus != MIXER_DRAIN_ALL)) {                // threadLoop_sleepTime sets sleepTime to 0 if data                // must be written to HAL                threadLoop_sleepTime();                if (sleepTime == 0) {                    mCurrentWriteLength = mixBufferSize;                }            }            mBytesRemaining = mCurrentWriteLength;            if (isSuspended()) {                sleepTime = suspendSleepTimeUs();                // simulate write to HAL when suspended                mBytesWritten += mixBufferSize;                mBytesRemaining = 0;            }            // only process effects if we're going to write            // 进行音效处理,同时避免offload类型的输出重复处理            if (sleepTime == 0 && mType != OFFLOAD) {                for (size_t i = 0; i < effectChains.size(); i ++) {                    effectChains[i]->process_l();                }            }        }        // Process effect chains for offloaded thread even if no audio        // was read from audio track: process only updates effect state        // and thus does have to be synchronized with audio writes but may have        // to be called while waiting for async write callback        // 当输出线程为offload类型时,即使没有读取track数据,        // 也需要对effect chain进行处理,更新effect状态        if (mType == OFFLOAD) {            for (size_t i = 0; i < effectChains.size(); i ++) {                effectChains[i]->process_l();            }        }        // enable changes in effect chain        unlockEffectChains(effectChains);        //需要对OffloadThread类型的输出进行条件判断,        //其它情况为true        if (!waitingAsyncCallback()) {            // sleepTime == 0 means we must write to audio hardware            //1、休眠时间为0,且MIX处理之后的数据不会空时,将数据写入到Hal,            //   返回写入的数据量,如果小于零,则直接将mBytesRemaining置0            //   其它情况则增加已写入数据量,减少Mix已处理量            if (sleepTime == 0) {                if (mBytesRemaining) {                    ssize_t ret = threadLoop_write();                    if (ret < 0) {                        mBytesRemaining = 0;                    } else {                        mBytesWritten += ret;                        mBytesRemaining -= ret;                    }                } else if ((mMixerStatus == MIXER_DRAIN_TRACK) ||                        (mMixerStatus == MIXER_DRAIN_ALL)) {                    threadLoop_drain();                }                //如果该线程为混音线程,总共有五类线程,计算该线程上一次写入和                //和本次写入的时间差,如果大于最多允许的延迟时间,则增加延迟的计数,                //并发出警告,属于underrun    /*    enum type_t {        MIXER,              // Thread class is MixerThread        DIRECT,             // Thread class is DirectOutputThread        DUPLICATING,        // Thread class is DuplicatingThread        RECORD,             // Thread class is RecordThread        OFFLOAD             // Thread class is OffloadThread    };     */                if (mType == MIXER) {                    // write blocked detection                    nsecs_t now = systemTime();                    nsecs_t delta = now - mLastWriteTime;                    if (!mStandby && delta > maxPeriod) {                        mNumDelayedWrites++;                        if ((now - lastWarning) > kWarningThrottleNs) {                            ATRACE_NAME("underrun");                            ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",                                ns2ms(delta), mNumDelayedWrites, this);                            lastWarning = now;                        }                    }               }            } else {                usleep(sleepTime);            }        }        // Finally let go of removed track(s), without the lock held        // since we can't guarantee the destructors won't acquire that        // same lock.  This will also mutate and push a new fast mixer state.        threadLoop_removeTracks(tracksToRemove);        tracksToRemove.clear();        // FIXME I don't understand the need for this here;        //       it was in the original code but maybe the        //       assignment in saveOutputTracks() makes this unnecessary?        clearOutputTracks();        // Effect chains will be actually deleted here if they were removed from        // mEffectChains list during mixing or effects processing        effectChains.clear();        // FIXME Note that the above .clear() is no longer necessary since effectChains        // is now local to this block, but will keep it for now (at least until merge done).    }    threadLoop_exit();    // for DuplicatingThread, standby mode is handled by the outputTracks, otherwise ...    if (mType == MIXER || mType == DIRECT || mType == OFFLOAD) {        // put output stream into standby mode        if (!mStandby) {            mOutput->stream->common.standby(&mOutput->stream->common);        }    }    releaseWakeLock();    mWakeLockUids.clear();    mActiveTracksGeneration++;    ALOGV("Thread %p type %d exiting", this, mType);    return false;}void AudioFlinger::ThreadBase::processConfigEvents(){    mLock.lock();    while (!mConfigEvents.isEmpty()) {        ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());        ConfigEvent *event = mConfigEvents[0];        mConfigEvents.removeAt(0);        // release mLock before locking AudioFlinger mLock: lock order is always        // AudioFlinger then ThreadBase to avoid cross deadlock        mLock.unlock();        switch(event->type()) {            case CFG_EVENT_PRIO: {                PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);                // FIXME Need to understand why this has be done asynchronously                int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),                        true /*asynchronous*/);                if (err != 0) {                    ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; "                          "error %d",                          prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);                }            } break;            case CFG_EVENT_IO: {                IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);                mAudioFlinger->mLock.lock();                audioConfigChanged_l(ioEvent->event(), ioEvent->param());                mAudioFlinger->mLock.unlock();            } break;            default:                ALOGE("processConfigEvents() unknown event type %d", event->type());                break;        }        delete event;        mLock.lock();    }    mLock.unlock();}// Parameter sequence by client: binder thread calling setParameters()://  1. Lock mLock//  2. Append to mNewParameters//  3. mWaitWorkCV.signal//  4. mParamCond.waitRelative with timeout//  5. read mParamStatus//  6. mWaitWorkCV.signal//  7. Unlockstatus_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs){    status_t status;    ALOGV("ThreadBase::setParameters() %s", keyValuePairs.string());    Mutex::Autolock _l(mLock);    mNewParameters.add(keyValuePairs);    mWaitWorkCV.signal();//唤醒loop线程,设置parameters    // wait condition with timeout in case the thread loop has exited    // before the request could be processed    // 休眠等待,之后返回checkForNewParameters_l设置参数的状态mParamStatus    if (mParamCond.waitRelative(mLock, kSetParametersTimeoutNs) == NO_ERROR) {        status = mParamStatus;        mWaitWorkCV.signal();//唤醒loop线程    } else {        status = TIMED_OUT;    }    return status;}// Parameter sequence by server: threadLoop calling checkForNewParameters_l():// 1. Lock mLock// 2. If there is an entry in mNewParameters proceed ...// 2. Read first entry in mNewParameters// 3. Process// 4. Remove first entry from mNewParameters// 5. Set mParamStatus// 6. mParamCond.signal// 7. mWaitWorkCV.wait with timeout (this is to avoid overwriting mParamStatus)// 8. Unlockbool AudioFlinger::MixerThread::checkForNewParameters_l(){    // if !&IDLE, holds the FastMixer state to restore after new parameters processed    FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;    bool reconfig = false;    while (!mNewParameters.isEmpty()) {        if (mFastMixer != NULL) {            FastMixerStateQueue *sq = mFastMixer->sq();            FastMixerState *state = sq->begin();            if (!(state->mCommand & FastMixerState::IDLE)) {                previousCommand = state->mCommand;                state->mCommand = FastMixerState::HOT_IDLE;                sq->end();                sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);            } else {                sq->end(false /*didModify*/);            }        }        status_t status = NO_ERROR;        String8 keyValuePair = mNewParameters[0];        AudioParameter param = AudioParameter(keyValuePair);        int value;        if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {            reconfig = true;        }        if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {            if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {                status = BAD_VALUE;            } else {                reconfig = true;            }        }        if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {            if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {                status = BAD_VALUE;            } else {                reconfig = true;            }        }        if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {            // do not accept frame count changes if tracks are open as the track buffer            // size depends on frame count and correct behavior would not be guaranteed            // if frame count is changed after track creation            if (!mTracks.isEmpty()) {                status = INVALID_OPERATION;            } else {                reconfig = true;            }        }        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {            // forward device change to effects that have requested to be            // aware of attached audio device.            if (value != AUDIO_DEVICE_NONE) {                mOutDevice = value;                for (size_t i = 0; i < mEffectChains.size(); i++) {                    mEffectChains[i]->setDevice_l(mOutDevice);                }            }        }        if (status == NO_ERROR) {            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,                                                    keyValuePair.string());            if (!mStandby && status == INVALID_OPERATION) {                mOutput->stream->common.standby(&mOutput->stream->common);                mStandby = true;                mBytesWritten = 0;                status = mOutput->stream->common.set_parameters(&mOutput->stream->common,                                                       keyValuePair.string());            }            if (status == NO_ERROR && reconfig) {                readOutputParameters();                delete mAudioMixer;                mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);                for (size_t i = 0; i < mTracks.size() ; i++) {                    int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);                    if (name < 0) {                        break;                    }                    mTracks[i]->mName = name;                }                sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);            }        }        //移除此参数        mNewParameters.removeAt(0);        mParamStatus = status;        mParamCond.signal();//唤醒track对象        // wait for condition with time out in case the thread calling ThreadBase::setParameters()        // already timed out waiting for the status and will never signal the condition.        // 休眠等待track端处理        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);    }    if (!(previousCommand & FastMixerState::IDLE)) {        ALOG_ASSERT(mFastMixer != NULL);        FastMixerStateQueue *sq = mFastMixer->sq();        FastMixerState *state = sq->begin();        ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE);        state->mCommand = previousCommand;        sq->end();        sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);    }    return reconfig;}void AudioFlinger::MixerThread::threadLoop_standby(){    // Idle the fast mixer if it's currently running    if (mFastMixer != NULL) {        FastMixerStateQueue *sq = mFastMixer->sq();        FastMixerState *state = sq->begin();        if (!(state->mCommand & FastMixerState::IDLE)) {            state->mCommand = FastMixerState::COLD_IDLE;            state->mColdFutexAddr = &mFastMixerFutex;            state->mColdGen++;            mFastMixerFutex = 0;            sq->end();            // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now            sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);            if (kUseFastMixer == FastMixer_Dynamic) {                mNormalSink = mOutputSink;            }#ifdef AUDIO_WATCHDOG            if (mAudioWatchdog != 0) {                mAudioWatchdog->pause();            }#endif        } else {            sq->end(false /*didModify*/);        }    }    PlaybackThread::threadLoop_standby();}void AudioFlinger::PlaybackThread::threadLoop_standby(){    ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended);    mOutput->stream->common.standby(&mOutput->stream->common);    if (mUseAsyncWrite != 0) {        // discard any pending drain or write ack by incrementing sequence        mWriteAckSequence = (mWriteAckSequence + 2) & ~1;        mDrainSequence = (mDrainSequence + 2) & ~1;        ALOG_ASSERT(mCallbackThread != 0);        mCallbackThread->setWriteBlocked(mWriteAckSequence);        mCallbackThread->setDraining(mDrainSequence);    }}void AudioFlinger::MixerThread::threadLoop_mix(){    // obtain the presentation timestamp of the next output buffer    int64_t pts;    status_t status = INVALID_OPERATION;    if (mNormalSink != 0) {        status = mNormalSink->getNextWriteTimestamp(&pts);    } else {        status = mOutputSink->getNextWriteTimestamp(&pts);    }    if (status != NO_ERROR) {        pts = AudioBufferProvider::kInvalidPTS;    }    // mix buffers...    mAudioMixer->process(pts);    mCurrentWriteLength = mixBufferSize;    // increase sleep time progressively when application underrun condition clears.    // Only increase sleep time if the mixer is ready for two consecutive times to avoid    // that a steady state of alternating ready/not ready conditions keeps the sleep time    // such that we would underrun the audio HAL.    if ((sleepTime == 0) && (sleepTimeShift > 0)) {        sleepTimeShift--;    }    sleepTime = 0;    standbyTime = systemTime() + standbyDelay;    //TODO: delay standby when effects have a tail}void AudioFlinger::MixerThread::threadLoop_sleepTime(){    // If no tracks are ready, sleep once for the duration of an output    // buffer size, then write 0s to the output    if (sleepTime == 0) {        if (mMixerStatus == MIXER_TRACKS_ENABLED) {            sleepTime = activeSleepTime >> sleepTimeShift;            if (sleepTime < kMinThreadSleepTimeUs) {                sleepTime = kMinThreadSleepTimeUs;            }            // reduce sleep time in case of consecutive application underruns to avoid            // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer            // duration we would end up writing less data than needed by the audio HAL if            // the condition persists.            if (sleepTimeShift < kMaxThreadSleepTimeShift) {                sleepTimeShift++;            }        } else {            sleepTime = idleSleepTime;        }    } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {        memset (mMixBuffer, 0, mixBufferSize);        sleepTime = 0;        ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED),                "anticipated start");    }    // TODO add standby time extension fct of effect tail}void AudioFlinger::PlaybackThread::threadLoop_drain(){    if (mOutput->stream->drain) {        ALOGV("draining %s", (mMixerStatus == MIXER_DRAIN_TRACK) ? "early" : "full");        if (mUseAsyncWrite) {            ALOGW_IF(mDrainSequence & 1, "threadLoop_drain(): out of sequence drain request");            mDrainSequence |= 1;            ALOG_ASSERT(mCallbackThread != 0);            mCallbackThread->setDraining(mDrainSequence);        }        mOutput->stream->drain(mOutput->stream,            (mMixerStatus == MIXER_DRAIN_TRACK) ? AUDIO_DRAIN_EARLY_NOTIFY                                                : AUDIO_DRAIN_ALL);    }}void AudioFlinger::MixerThread::threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove){    PlaybackThread::threadLoop_removeTracks(tracksToRemove);}void AudioFlinger::PlaybackThread::threadLoop_removeTracks(        const Vector< sp<Track> >& tracksToRemove){    size_t count = tracksToRemove.size();    if (count) {        for (size_t i = 0 ; i < count ; i++) {            const sp<Track>& track = tracksToRemove.itemAt(i);            if (!track->isOutputTrack()) {                AudioSystem::stopOutput(mId, track->streamType(), track->sessionId());#ifdef ADD_BATTERY_DATA                // to track the speaker usage                addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);#endif                if (track->isTerminated()) {                    AudioSystem::releaseOutput(mId);                }            }        }    }}

0 0
原创粉丝点击