mSleepTimeUs与其在systrace的表现

1、mSleepTimeUs
表示要sleep的时间,一般是等于mIdleSleepTimeUs,而mIdleSleepTimeUs是idleSleepTimeUs()的返回。

uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
{
return (uint32_t)(((mNormalFrameCount * 1000) / mSampleRate) * 1000) / 2;
}

大概就是等于out_write一次数据的时间的一半。比如mNormalFrameCount = 1920, mSampleRate = 48000, 那idleSleepTimeUs = 1920/4800/2 = 20ms,但是mNormalFrameCount还不一定
等于hal层返回的framecount,mNormalFrameCount = multiplier * mFrameCount;
mFrameCount 才是hal层返回的framecount,mFrameCount = mBufferSize / mFrameSize;

2、mActiveSleepTimeUs
mActiveSleepTimeUs = activeSleepTimeUs();

uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs() const
{
return (uint32_t)((uint32_t)((mNormalFrameCount * 1000) / mSampleRate) * 1000);
}

所以mActiveSleepTimeUs会等于idleSleepTimeUs的2倍,大概是40ms。

3、sleepTimeShift
一个移位参数,主要用于计算实际mSleepTimeUs的值, mSleepTimeUs 不超过kMaxThreadSleepTimeShift(即static const uint32_t kMaxThreadSleepTimeShift = 2;)


PlaybackThread::threadLoop:

cacheParameters_l(); //把mActiveSleepTimeUs,和mIdleSleepTimeUs、mStandbyDelayNs初始化
mIdleSleepTimeUs,设为mIdleSleepTimeUs
sleepTimeShift 为0


// wait until we have something to do...
ALOGV("%s going to sleep", myName.string());
mWaitWorkCV.wait(mLock);
ALOGV("%s waking up", myName.string());

在wake up后,mSleepTimeUs还是设为mIdleSleepTimeUs

然后进入prepareTracks_l,再根据prepareTracks_l的返回值选择进行mix还是sleep

如果mMixerStatus为enabled,就不进入mix,而是进入threadLoop_sleepTime函数:
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
ALOGD("mActiveSleepTimeUs = %d, sleepTimeShift = %d, mMixerStatus = %d", mActiveSleepTimeUs, sleepTimeShift, mMixerStatus);
if (mSleepTimeUs == 0) {
if (mMixerStatus == MIXER_TRACKS_ENABLED) {
mSleepTimeUs = mActiveSleepTimeUs >> sleepTimeShift;
if (mSleepTimeUs < kMinThreadSleepTimeUs) {
mSleepTimeUs = 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 {
mSleepTimeUs = mIdleSleepTimeUs + mIdleTimeOffsetUs;
mIdleTimeOffsetUs = 0;
}
} else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
// clear out mMixerBuffer or mSinkBuffer, to ensure buffers are cleared
// before effects processing or output.
if (mMixerBufferValid) {
memset(mMixerBuffer, 0, mMixerBufferSize);
} else {
memset(mSinkBuffer, 0, mSinkBufferSize);
}
mSleepTimeUs = 0;
ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED),
"anticipated start");
}
// TODO add standby time extension fct of effect tail
}

而mix函数:
if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) {
sleepTimeShift--;
}
mSleepTimeUs = 0;
mStandbyTimeNs = systemTime() + mStandbyDelayNs;
//TODO: delay standby when effects have a tail

所以进入threadLoop_sleepTime之前,是否先进入过mix,如果进入过mix,那此时进入threadLoop_sleepTime时,mSleepTimeUs应该是为0
否则,mSleepTimeUs是为mIdleSleepTimeUs。

在threadLoop_sleepTime函数中,如果mSleepTimeUs为0,也就是说前一次是有进行过mix的,则这时会计算mSleepTimeU,让thread进入sleep状态,等待上层填充数据。
而mSleepTimeUs的计算是为mSleepTimeUs = mActiveSleepTimeUs >> sleepTimeShift;

所以就会第一次为40ms,第一次为40 >> 1 = 20ms,第三次为40 >> 2 = 10ms。当然这种计算会因为mix改变sleepTimeShift而不会依次这样排序。

如果是在第二次中,因为第一次sleep后有足够的数据mix,那再次进入threadLoop_sleepTime时,sleepTimeShift会和第一次的相等,因为mix中:
if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) {
sleepTimeShift--;
}

sleep或者写0数据,主要是根据mSleepTimeUs的值,如果mSleepTimeUs不为0,则会写0数据给hal层。
那什么时候mSleepTimeUs不为0呢?
(1)第一次prepared时,由于mSleepTimeUs初始化为mIdleSleepTimeUs,如果此时进入threadLoop_sleepTime,那mSleepTimeUs是为mIdleSleepTimeUs,那就会写0数据给hal。
(2)进入threadLoop_sleepTime时mSleepTimeUs,然后计算mSleepTimeUs后,进入sleep,再次进入threadLoop_sleepTime时,mSleepTimeUs也不为0,此时也会写0数据。


mSleepTimeUs在systrace的表现:
第一次sleep(记sleep1,依此类推),时间是40ms,说明sleep1前的write1是写音频数据,sleep1后的write2写的时间很短,是因为上层sleep后,底层数据写完了,此次写有足够的buffer,不会
受阻塞,那write2是写0数据还是音频数据?

看sleep2,时间为40ms,说明write3是写音频数据,因为sleepTimeShift为0,只有经过mix,sleepTimeShift才会变化。
另一个假设,如果write3写0数据,那write2写音频数据,把sleepTimeShift减1,sleep2才有可能是40ms。那如果write2写音频数据,那mSleepTimeUs应该是0,那这样的话肯定是不会接着写0数据的,这种情况下,write3应该是sleep,因此,write3肯定是写音频数据的

write2 可能是写0数据,和写音频数:
(1)如果是写0数据,那sleepTimeShift为1,mSleepTimeUs为40ms,接着write3写音频数据时,把这两个参数清0。到sleep2时,表现也如图。
(2)如果是写音频数据,那就更加正常,sleepTimeShift为0,mSleepTimeUs为0,sleep2就是这样的表现。

很明显,write4和write5都是写0数据。





阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页