RecordThread 类继承ThreadBase,而ThreadBase又继承Thread ,在调用RecordThread .run的方法由父类的父类Thread时序,在Thread的run方法中会创建一个线程,并且允许其_threadLoop方法,在_threadLoop方法中会允许其子类的threadLoop方法,RecordThread 的threadLoop方法如下:
RecordThread 类继承ThreadBase,而ThreadBase又继承Thread ,在调用RecordThread .run的方法由父类的父类Thread时序,在Thread的run方法中会创建一个线程,并且允许其_threadLoop方法,在_threadLoop方法中会允许其子类的threadLoop方法,RecordThread 的threadLoop方法如下:
//frameworks/av/services/audioflinger/Threads.cpp
bool AudioFlinger::RecordThread::threadLoop()
{
nsecs_t lastWarning = 0;
inputStandBy();
reacquire_wakelock:
sp<RecordTrack> activeTrack;
{
Mutex::Autolock _l(mLock);
acquireWakeLock_l();
}
// used to request a deferred sleep, to be executed later while mutex is unlocked
uint32_t sleepUs = 0;
int64_t lastLoopCountRead = -2; // never matches "previous" loop, when loopCount = 0.
// loop while there is work to do
for (int64_t loopCount = 0;; ++loopCount) { // loopCount used for statistics tracking
Vector< sp<EffectChain> > effectChains;
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
// reference to the (first and only) active fast track
sp<RecordTrack> fastTrack;
// reference to a fast track which is about to be removed
sp<RecordTrack> fastTrackToRemove;
bool silenceFastCapture = false;
{ // scope for mLock
Mutex::Autolock _l(mLock);
processConfigEvents_l(); //判断mConfigEvents中是否存在事件, 若存在则向外发送mConfigEvents中的事件(createAudioPath、setParameters等)
// check exitPending here because checkForNewParameters_l() and
// checkForNewParameters_l() can temporarily release mLock
if (exitPending()) {
break;
}
// sleep with mutex unlocked
if (sleepUs > 0) {
ATRACE_BEGIN("sleepC");
mWaitWorkCV.waitRelative(mLock, microseconds((nsecs_t)sleepUs)); //然后Thread会在这里睡眠等待,直到AudioRecord:: start发送广播唤醒或超时
ATRACE_END();
sleepUs = 0;
continue;
}
//判断mActiveTracks.size(), Threads.cpp中调用AudioFlinger::RecordThread::start方法时,
//会将创建好的RecordThread加入到mActiveTracks中, 所以mActiveTracks中存放的是之前创建的RecordThread对象
// if no active track(s), then standby and release wakelock
size_t size = mActiveTracks.size();
if (size == 0) {
standbyIfNotAlreadyInStandby();
// exitPending() can't become true here
releaseWakeLock_l();
ALOGV("RecordThread: loop stopping");
// go to sleep
mWaitWorkCV.wait(mLock); //然后Thread会在这里睡眠等待,直到AudioRecord:: start发送广播唤醒
ALOGV("RecordThread: loop starting");
goto reacquire_wakelock;
}
bool doBroadcast = false;
bool allStopped = true;
for (size_t i = 0; i < size; ) {
activeTrack = mActiveTracks[i];//从mActiveTracks中获取activeTrack
if (activeTrack->isTerminated()) {
if (activeTrack->isFastTrack()) {
ALOG_ASSERT(fastTrackToRemove == 0);
fastTrackToRemove = activeTrack;
}
removeTrack_l(activeTrack); //从mTracks移除activeTrack
mActiveTracks.remove(activeTrack); //从mActiveTracks移除activeTrack
size--;
continue;
}
//获取activeTracks的状态, 在add mActiveTracks时, mState = STARTING_1, start执行完毕, mState = STARTING_2,//threadLoop等待start执行完毕, 否则一直处于sleep中
TrackBase::track_state activeTrackState = activeTrack->mState;
switch (activeTrackState) {
case TrackBase::PAUSING:
mActiveTracks.remove(activeTrack);
activeTrack->mState = TrackBase::PAUSED;
doBroadcast = true;
size--;
continue;
case TrackBase::STARTING_1:
sleepUs = 10000;
i++;
allStopped = false;
continue;
case TrackBase::STARTING_2:
doBroadcast = true;
if (mStandby) {
mThreadMetrics.logBeginInterval();
mThreadSnapshot.onBegin();
mStandby = false;
}
activeTrack->mState = TrackBase::ACTIVE;
allStopped = false;
break;
case TrackBase::ACTIVE:
allStopped = false;
break;
case TrackBase::IDLE: // cannot be on ActiveTracks if idle
case TrackBase::PAUSED: // cannot be on ActiveTracks if paused
case TrackBase::STOPPED: // cannot be on ActiveTracks if destroyed/terminated
default:
LOG_ALWAYS_FATAL("%s: Unexpected active track state:%d, id:%d, tracks:%zu",
__func__, activeTrackState, activeTrack->id(), size);
}
if (activeTrack->isFastTrack()) {
ALOG_ASSERT(!mFastTrackAvail);
ALOG_ASSERT(fastTrack == 0);
// if the active fast track is silenced either:
// 1) silence the whole capture from fast capture buffer if this is
// the only active track
// 2) invalidate this track: this will cause the client to reconnect and possibly
// be invalidated again until unsilenced
bool invalidate = false;
if (activeTrack->isSilenced()) {
if (size > 1) {
invalidate = true;
} else {
silenceFastCapture = true;
}
}
// Invalidate fast tracks if access to audio history is required as this is not
// possible with fast tracks. Once the fast track has been invalidated, no new
// fast track will be created until mMaxSharedAudioHistoryMs is cleared.
if (mMaxSharedAudioHistoryMs != 0) {
invalidate = true;
}
if (invalidate) {
activeTrack->invalidate();
ALOG_ASSERT(fastTrackToRemove == 0);
fastTrackToRemove = activeTrack;
removeTrack_l(activeTrack); //从mTracks移除activeTrack
mActiveTracks.remove(activeTrack); //从mActiveTracks移除activeTrack
size--;
continue;
}
fastTrack = activeTrack;
}
activeTracks.add(activeTrack);
i++;
}
mActiveTracks.updatePowerState(this);
updateMetadata_l();
if (allStopped) {
standbyIfNotAlreadyInStandby();
}
if (doBroadcast) {
mStartStopCond.broadcast();
}
// sleep if there are no active tracks to process
if (activeTracks.isEmpty()) {
if (sleepUs == 0) {
sleepUs = kRecordThreadSleepUs;
}
continue;
}
sleepUs = 0;
lockEffectChains_l(effectChains);
}
// thread mutex is now unlocked, mActiveTracks unknown, activeTracks.size() > 0
size_t size = effectChains.size();
for (size_t i = 0; i < size; i++) {
// thread mutex is not locked, but effect chain is locked
effectChains[i]->process_l();
}
// Push a new fast capture state if fast capture is not already running, or cblk change
if (mFastCapture != 0) {
FastCaptureStateQueue *sq = mFastCapture->sq();
FastCaptureState *state = sq->begin();
bool didModify = false;
FastCaptureStateQueue::block_t block = FastCaptureStateQueue::BLOCK_UNTIL_PUSHED;
if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
(kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
if (state->mCommand == FastCaptureState::COLD_IDLE) {
int32_t old = android_atomic_inc(&mFastCaptureFutex);
if (old == -1) {
(void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
}
}
state->mCommand = FastCaptureState::READ_WRITE;
#if 0 // FIXME
mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
FastThreadDumpState::kSamplingNforLowRamDevice :
FastThreadDumpState::kSamplingN);
#endif
didModify = true;
}
audio_track_cblk_t *cblkOld = state->mCblk;
audio_track_cblk_t *cblkNew = fastTrack != 0 ? fastTrack->cblk() : NULL;
if (cblkNew != cblkOld) {
state->mCblk = cblkNew;
// block until acked if removing a fast track
if (cblkOld != NULL) {
block = FastCaptureStateQueue::BLOCK_UNTIL_ACKED;
}
didModify = true;
}
AudioBufferProvider* abp = (fastTrack != 0 && fastTrack->isPatchTrack()) ?
reinterpret_cast<AudioBufferProvider*>(fastTrack.get()) : nullptr;
if (state->mFastPatchRecordBufferProvider != abp) {
state->mFastPatchRecordBufferProvider = abp;
state->mFastPatchRecordFormat = fastTrack == 0 ?
AUDIO_FORMAT_INVALID : fastTrack->format();
didModify = true;
}
if (state->mSilenceCapture != silenceFastCapture) {
state->mSilenceCapture = silenceFastCapture;
didModify = true;
}
sq->end(didModify);
if (didModify) {
sq->push(block);
#if 0
if (kUseFastCapture == FastCapture_Dynamic) {
mNormalSource = mPipeSource;
}
#endif
}
}
// now run the fast track destructor with thread mutex unlocked
fastTrackToRemove.clear();
// Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
// Only the client(s) that are too slow will overrun. But if even the fastest client is too
// slow, then this RecordThread will overrun by not calling HAL read often enough.
// If destination is non-contiguous, first read past the nominal end of buffer, then
// copy to the right place. Permitted because mRsmpInBuffer was over-allocated.
int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
ssize_t framesRead;
const int64_t lastIoBeginNs = systemTime(); // start IO timing
// If an NBAIO source is present, use it to read the normal capture's data
if (mPipeSource != 0) {
size_t framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
// The audio fifo read() returns OVERRUN on overflow, and advances the read pointer
// to the full buffer point (clearing the overflow condition). Upon OVERRUN error,
// we immediately retry the read() to get data and prevent another overflow.
for (int retries = 0; retries <= 2; ++retries) {
ALOGW_IF(retries > 0, "overrun on read from pipe, retry #%d", retries);
framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
framesToRead);
if (framesRead != OVERRUN) break;
}
const ssize_t availableToRead = mPipeSource->availableToRead();
if (availableToRead >= 0) {
mMonopipePipeDepthStats.add(availableToRead);
// PipeSource is the primary clock. It is up to the AudioRecord client to keep up.
LOG_ALWAYS_FATAL_IF((size_t)availableToRead > mPipeFramesP2,
"more frames to read than fifo size, %zd > %zu",
availableToRead, mPipeFramesP2);
const size_t pipeFramesFree = mPipeFramesP2 - availableToRead;
const size_t sleepFrames = min(pipeFramesFree, mRsmpInFramesP2) / 2;
ALOGVV("mPipeFramesP2:%zu mRsmpInFramesP2:%zu sleepFrames:%zu availableToRead:%zd",
mPipeFramesP2, mRsmpInFramesP2, sleepFrames, availableToRead);
sleepUs = (sleepFrames * 1000000LL) / mSampleRate;
}
if (framesRead < 0) {
status_t status = (status_t) framesRead;
switch (status) {
case OVERRUN:
ALOGW("overrun on read from pipe");
framesRead = 0;
break;
case NEGOTIATE:
ALOGE("re-negotiation is needed");
framesRead = -1; // Will cause an attempt to recover.
break;
default:
ALOGE("unknown error %d on read from pipe", status);
break;
}
}
// otherwise use the HAL / AudioStreamIn directly
} else {
ATRACE_BEGIN("read");
size_t bytesRead;
status_t result = mSource->read(
(uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead); //从AudioHAL读取数据
ATRACE_END();
if (result < 0) {
framesRead = result;
} else {
framesRead = bytesRead / mFrameSize;
}
}
const int64_t lastIoEndNs = systemTime(); // end IO timing
// Update server timestamp with server stats
// systemTime() is optional if the hardware supports timestamps.
if (framesRead >= 0) {
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = lastIoEndNs;
}
// Update server timestamp with kernel stats
if (mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity(audio_is_linear_pcm(mFormat) ?
mTimestampVerifier.DISCONTINUITY_MODE_CONTINUOUS :
mTimestampVerifier.DISCONTINUITY_MODE_ZERO);
} else if (mSource->getCapturePosition(&position, &time) == NO_ERROR
&& time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
mTimestampVerifier.add(position, time, mSampleRate);
// Correct timestamps
if (isTimestampCorrectionEnabled()) {
ALOGVV("TS_BEFORE: %d %lld %lld",
id(), (long long)time, (long long)position);
auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
position = correctedTimestamp.mFrames;
time = correctedTimestamp.mTimeNs;
ALOGVV("TS_AFTER: %d %lld %lld",
id(), (long long)time, (long long)position);
}
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
// Note: In general record buffers should tend to be empty in
// a properly running pipeline.
//
// Also, it is not advantageous to call get_presentation_position during the read
// as the read obtains a lock, preventing the timestamp call from executing.
} else {
mTimestampVerifier.error();
}
}
// From the timestamp, input read latency is negative output write latency.
const audio_input_flags_t flags = mInput != NULL ? mInput->flags : AUDIO_INPUT_FLAG_NONE;
const double latencyMs = RecordTrack::checkServerLatencySupported(mFormat, flags)
? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
if (latencyMs != 0.) { // note 0. means timestamp is empty.
mLatencyMs.add(latencyMs);
}
// Use this to track timestamp information
// ALOGD("%s", mTimestamp.toString().c_str());
if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
ALOGE("read failed: framesRead=%zd", framesRead);
// Force input into standby so that it tries to recover at next read attempt
inputStandBy(); //调用Hal层in_standby方法, 执行与否取决于in->standby的值
sleepUs = kRecordThreadSleepUs;
}
if (framesRead <= 0) {
goto unlock;
}
ALOG_ASSERT(framesRead > 0);
mFramesRead += framesRead;
#ifdef TEE_SINK
(void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
#endif
// If destination is non-contiguous, we now correct for reading past end of buffer.
{
size_t part1 = mRsmpInFramesP2 - rear;
if ((size_t) framesRead > part1) {
memcpy(mRsmpInBuffer, (uint8_t*)mRsmpInBuffer + mRsmpInFramesP2 * mFrameSize,
(framesRead - part1) * mFrameSize);
}
}
mRsmpInRear = audio_utils::safe_add_overflow(mRsmpInRear, (int32_t)framesRead);
size = activeTracks.size();
// loop over each active track
for (size_t i = 0; i < size; i++) {
activeTrack = activeTracks[i];
// skip fast tracks, as those are handled directly by FastCapture
if (activeTrack->isFastTrack()) {
continue;
}
// TODO: This code probably should be moved to RecordTrack.
// TODO: Update the activeTrack buffer converter in case of reconfigure.
enum {
OVERRUN_UNKNOWN,
OVERRUN_TRUE,
OVERRUN_FALSE
} overrun = OVERRUN_UNKNOWN;
// loop over getNextBuffer to handle circular sink
for (;;) {
activeTrack->mSink.frameCount = ~0;
status_t status = activeTrack->getNextBuffer(&activeTrack->mSink);
size_t framesOut = activeTrack->mSink.frameCount;
LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0));
// check available frames and handle overrun conditions
// if the record track isn't draining fast enough.
bool hasOverrun;
size_t framesIn;
activeTrack->mResamplerBufferProvider->sync(&framesIn, &hasOverrun);
if (hasOverrun) {
overrun = OVERRUN_TRUE;
}
if (framesOut == 0 || framesIn == 0) {
break;
}
// Don't allow framesOut to be larger than what is possible with resampling
// from framesIn.
// This isn't strictly necessary but helps limit buffer resizing in
// RecordBufferConverter. TODO: remove when no longer needed.
framesOut = min(framesOut,
destinationFramesPossible(
framesIn, mSampleRate, activeTrack->mSampleRate));
if (activeTrack->isDirect()) {
// No RecordBufferConverter used for direct streams. Pass
// straight from RecordThread buffer to RecordTrack buffer.
AudioBufferProvider::Buffer buffer;
buffer.frameCount = framesOut;
status_t status = activeTrack->mResamplerBufferProvider->getNextBuffer(&buffer);
if (status == OK && buffer.frameCount != 0) {
ALOGV_IF(buffer.frameCount != framesOut,
"%s() read less than expected (%zu vs %zu)",
__func__, buffer.frameCount, framesOut);
framesOut = buffer.frameCount;
memcpy(activeTrack->mSink.raw, buffer.raw, buffer.frameCount * mFrameSize);
activeTrack->mResamplerBufferProvider->releaseBuffer(&buffer);
} else {
framesOut = 0;
ALOGE("%s() cannot fill request, status: %d, frameCount: %zu",
__func__, status, buffer.frameCount);
}
} else {
// process frames from the RecordThread buffer provider to the RecordTrack
// buffer
framesOut = activeTrack->mRecordBufferConverter->convert(
activeTrack->mSink.raw,
activeTrack->mResamplerBufferProvider,
framesOut);
}
if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
overrun = OVERRUN_FALSE;
}
if (activeTrack->mFramesToDrop == 0) {
if (framesOut > 0) {
activeTrack->mSink.frameCount = framesOut;
// Sanitize before releasing if the track has no access to the source data
// An idle UID receives silence from non virtual devices until active
if (activeTrack->isSilenced()) {
memset(activeTrack->mSink.raw, 0, framesOut * activeTrack->frameSize());
}
activeTrack->releaseBuffer(&activeTrack->mSink);
}
} else {
// FIXME could do a partial drop of framesOut
if (activeTrack->mFramesToDrop > 0) {
activeTrack->mFramesToDrop -= (ssize_t)framesOut;
if (activeTrack->mFramesToDrop <= 0) {
activeTrack->clearSyncStartEvent();
}
} else {
activeTrack->mFramesToDrop += framesOut;
if (activeTrack->mFramesToDrop >= 0 || activeTrack->mSyncStartEvent == 0 ||
activeTrack->mSyncStartEvent->isCancelled()) {
ALOGW("Synced record %s, session %d, trigger session %d",
(activeTrack->mFramesToDrop >= 0) ? "timed out" : "cancelled",
activeTrack->sessionId(),
(activeTrack->mSyncStartEvent != 0) ?
activeTrack->mSyncStartEvent->triggerSession() :
AUDIO_SESSION_NONE);
activeTrack->clearSyncStartEvent();
}
}
}
if (framesOut == 0) {
break;
}
}
switch (overrun) {
case OVERRUN_TRUE:
// client isn't retrieving buffers fast enough
if (!activeTrack->setOverflow()) {
nsecs_t now = systemTime();
// FIXME should lastWarning per track?
if ((now - lastWarning) > kWarningThrottleNs) {
ALOGW("RecordThread: buffer overflow");
lastWarning = now;
}
}
break;
case OVERRUN_FALSE:
activeTrack->clearOverflow();
break;
case OVERRUN_UNKNOWN:
break;
}
// update frame information and push timestamp out
activeTrack->updateTrackFrameInfo(
activeTrack->mServerProxy->framesReleased(),
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER],
mSampleRate, mTimestamp);
}
unlock:
// enable changes in effect chain
unlockEffectChains(effectChains);
// effectChains doesn't need to be cleared, since it is cleared by destructor at scope end
if (audio_has_proportional_frames(mFormat)
&& loopCount == lastLoopCountRead + 1) {
const int64_t readPeriodNs = lastIoEndNs - mLastIoEndNs;
const double jitterMs =
TimestampVerifier<int64_t, int64_t>::computeJitterMs(
{framesRead, readPeriodNs},
{0, 0} /* lastTimestamp */, mSampleRate);
const double processMs = (lastIoBeginNs - mLastIoEndNs) * 1e-6;
Mutex::Autolock _l(mLock);
mIoJitterMs.add(jitterMs);
mProcessTimeMs.add(processMs);
}
// update timing info.
mLastIoBeginNs = lastIoBeginNs;
mLastIoEndNs = lastIoEndNs;
lastLoopCountRead = loopCount;
}
standbyIfNotAlreadyInStandby();
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mTracks.size(); i++) {
sp<RecordTrack> track = mTracks[i];
track->invalidate();
}
mActiveTracks.clear();
mStartStopCond.broadcast();
}
releaseWakeLock();
ALOGV("RecordThread %p exiting", this);
return false;
}
待更新