Android音频系统之AudioTrack起播线与underrun问题研究(Android 5.1)

探讨使用AudioTrack播放PCM数据时的underrun问题,分析underrun的判断依据和处理机制,包括AudioFlinger的buffer机制、threadLoop的工作流程,以及如何通过实验验证underrun的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、引言:
使用audiotrack进行pcm数据播放的时候,复杂场景下会遇到underrun问题,所谓underrun,是指生产者提供数据的速度跟不上消费者使用数据的速度。因为网上讲述这类问题的博客很少,所以这里分享一下自己的研究心得,但是由于underrun和audiotrack的buffer机制非常复杂,所以也会遗留一些问题,欢迎大神补充指正。

二、代码分析:
1.添加活跃track:
首先,我们回顾下活跃track的添加,前几篇博文已经分析过,thread起来之后并不是立马不停地去处理数据,这样对功耗和CPU而言是一种浪费,当上层调用audiotrack的start接口之后,线程会添加当前track为活跃track,并且发送广播,threadloop就开始转起来处理数据了,先看一下addTrack_l函数:

AudioFlinger::PlaybackThread::addTrack_l@Threads.cpp
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
   
	...
    // set retry count for buffer fill
    track->mRetryCount = kMaxTrackStartupRetries;
    ...
    mActiveTracks.add(track);
    ...
}

注意看,这个函数进来先对track设置了一个最大开始尝试次数,但是我从代码中来看,这个值并没有使用处,反倒是和它一起定义的kMaxTrackRetries 很有用,这个值会跟underrun扯上关系,假如thread在kMaxTrackRetries 的次数内持续underrun,那么,系统就认为这个track已经“死了”,会将其从mActiveTracks中移除,我们看一下系统设置的这个值大小:

// retry counts for buffer fill timeout
// 50 * ~20msecs = 1 second
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;

注意注释,告诉我们threadloop每执行一次为20ms;

2.prepareTracks_l:
接下来我们去threadloop里面,首先关注的是肯定是prepareTracks_l,因为这个函数会去遍历所有的活跃track,计算buffer中的数据等操作,然后给后续的mixer使用,这里先抛出一个结果,track动起来之后,threadloop每执行一次的值确实是20ms,这个值的计算很复杂,是由threadloop来控制的(不是prepareTracks_l做的),在代码中我没有明显的看到这个值的得出结论。下面简化一下prepareTracks_l的代码:

AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
        Vector< sp<Track> > *tracksToRemove)
{
   
	/* 先将mixer状态设置为IDLE */
	mixer_state mixerStatus = MIXER_IDLE;	
	...
	/* fasttrack下,设置try值为50 */
	case TrackBase::ACTIVE:
    if (recentFull > 0 || recentPartial > 0) {
   
        // track has provided at least some frames recently: reset retry count
        track->mRetryCount = kMaxTrackRetries;
    }
    ...
    audio_track_cblk_t* cblk = track->cblk();
    ...
    size_t desiredFrames;
    uint32_t sr = track->sampleRate();
    if (sr == mSampleRate) {
   
    	desiredFrames = mNormalFrameCount;
	} else
	{
   
		...
	}
	minFrames = desiredFrames;
	/* 获取共享buffer中的帧数 */
	size_t framesReady = track->framesReady();
	/* 如果目前帧数大于minFrames */
    if ((framesReady >= minFrames) && track->isReady
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值