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. Unlock status_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. Unlock bool 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); } } } } }