对cpp 不熟,只是了解一些基本概念 。所以下面的记录难免会有认识上的错误,随时更正
代码位置 ;frameworks/av/services/audioflinger/AudioFlinger.cpp
AudioMixer.cpp 已经编译为prebuilt,看不到代码,只有一个头文件在
问题描述 : speaker headset 下pop音,几乎所有的android都是都有:播放、暂停切换时有爆音,上下首歌的时候爆音严重。用普通的音乐测试不明显,单频音测试十分明显,Galaxy3 惨不忍睹。
分析 :speaker时,经过对pcm数据的dump,发现有pop音的时候没有对音量进行ramp处理; 只要有ramp处理的时候几乎很少出现pop音(seekbar除外,这个情况比较特殊,不知道为什么)。 pre/next 按键时几乎所有情况下都会有pop音。headset情况pop音比speaker严重。 speaker下,播放暂停切换几乎不会出现pop音(所有测试中均未听到,可以认为没有) 。 所以根据以上观察到的情况, 优先分析speaker下的情况,待将speaker解决了再解决headset情况。
1 由于播放暂停在speaker下几乎没有pop音。 所以现分析播放暂停的动作流程。
1 在frameworks/av/service/audioflinger/AudioFlinger.cpp中
AudioFlinger.h 定义了几种状态,貌似audioflinger用了状态机。
track_state
{ IDLE, TERMINATED,FLUSHED, STOPPED, STOPPING_1, STOPPING_2,RESUMING,ACTIVE,PAUSING,PAUSED
}
stopping_1 :waiting for first underrun //应该是af读的快,at写的慢,读在等待写,缓冲区空所以sotp
stopping_2 : waiting for presentation complete //应该是 af读的慢,at写的快,缓冲区慢,at停止写入
//以上这两个判断 需要验证
A 下面分析代码 pause
AudioFlinger::playbackThraed::Track::pause() //这个应该是按下pause的时候调用的
|
if (mState ==Active || mState ==RESUMING)
{
mState = PAUSING ; // 如果现在的状态(按下pause时的状态)是 active 或者是resuming,那么就把状态置成pausing(这个其实应该理解为下一个状态,按下pause的下一个状态)
ALOG("ACTIVE/RESUMING => PAUSING.......")
if (!isOutputTrack())
{
thread->mLock.unlock();
AudioSystem::stopOutput(thread->id(),mStreamType,mSessionId);
thread->mLock.lock();
}
}
//其实pause就相当于改变了mState的状态
AudioFlinge::playbackThread::Track::start(....)
{
....
if(mState ==PAUSED)
{
mState == TrackBase::RESUMING; //如果上一个状态是paused,那么下一个状态就是resuming
ALOG(....);
}
else
{
mState == TrackBase::Active; //如果上一个状态不是paused,那么下一个状态就是active
}
// paused --> resuming --> active
//other state-----> active 只有是paused的时候到active要经过resuming,其余状态点击播放按钮,就直接到active
if (!isOutputTrack() && state != ACTIVE && state != RESUMING)
{
thread->mLock.unlock();
status = AudioSystem::startOutput(thread->id(),mStreamType, mSessionId);
thead -> mLock.lock();
}
下面是设定线程优先级,然后 addTrack_l(...)
}
//上面只看到对mState进行改变,但是并没有看大实际是怎么设置音量的。
在
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(...)
{
// 这个函数很复杂,
//先对音效处理 ,看不懂
//然后进入for
size_t count = mActiveTracks.size(); // 貌似count是activetrack的数量
for (size_t i=0; i< mActiveTrack.size();i++) // 应该是对所有activetrack进行处理
{
if (track->isFastTrack())
{... 直接忽略,这里不是fastrack
}
//下面这个没有条件,直接是两个大括号,肯定不论什么情况都可以走到
{
audio_track_cblk_t *cblk=track->cblk(); //得到cblk 下面除了和音量处理的全部跳过
。。。。 跳过好多。。。
int param = AudioMixer:: VOLUME; //这里开始处理音量
if (track-> mFillingUpStatus == Track ::FS_FILLED)
// filling 和 filled 这两个状态应该是at往cblk填充数据的状态,感觉是只有filled的时候才能读数据,filling的时候貌似不能读。进一步看代码确定。
{ //no ramp for the first volume setting //这句注释很奇怪,明明已经ramp了
//所以,打算在这个地方加入读其他情况ramp的判断,比如pre/next等情况,
track->mFillingUpStatus == Track::FS_ACTIVE; // 不明白这个状态有什么用
// 。。。。。。。实验失败
if(mState != Track::ACTIVE) //不可以这么做,虽然mState状态改了,setparameter 也调用了,但是ramp没有起作用
{
// 如果不是active状态,就ramp,这个不是active状态,自然包含了下面的resuming状态,因为pre/next的时候需要现stop,然后再开始,所以有了这个,凡是不是active(播放)的时候全部都加上ramp处理。
param = AudioMixer::RAMP_VOLUME;
}
//。。。。。。。。实验失败
track-> mFillingUpStatus = Track ::FS_ACTIVE;
if(track->mState == TrackBase::RESUMING) {
track->mState = TrackBase ::ACTIVE;
param = AudioMixer:: RAMP_VOLUME; // 如果现在的状态是resuming,那么ramp
// 所以在speaker的时候,rusume的时候从来都没有pop音,因为这里做了ramp,pop音被渐变掩盖了
}
mAudioMixer -> setParameter(name, AudioMixer::RESAMPLE,Audio::RESET, NULL);
//这里不明白为什么要设置resampler
}
else if (cblk->server !=0){
param = AudioMixer::RAMP_VOLUME; //server是af从cblk读取的指针,user是at写入cblk的指针,这个是playbackThread的分析,如果是record的user和server应该换换;所以,这句貌似应该才是判断是不是第一次播放,第一次播放时server应该是0,刚开始, 不是第一次播放,server不是0 ?这个貌似也不一定,碰巧某次读完可能就回到0了,不知道怎么判断这种特殊情况。
}
//下面开始判断音量
if(track->isMuted() || track->isPausing || mStreamType[track->streamType()].mute) {
vl = vr = va =0; // 左右音量置0 ,va是什么 ?
//之后又判断了pausing
}
else {
vlr = cblk->getVolumeLR(); //读左右声道音量
。。。。。。。。。。 //一堆计算
//包括chain ,最大最小音量 等等。
mAudioMixer->setBufferProvider(.....); //暂时不关注
mAudioMixer->setPrameter(name,AudioMixer::Track,。。。。。);//不关注
mAudioMixer->setParameter(name,param,AudioMixer::VOLUME0,(void*)vl);//左声道
mAudioMixer->setParameter(name,param,AudioMixer::VOLUME1,(void*)vr);//右声道
.........//一些其他设置 忽略
看来pause stop start设置mState的状态是在这个地方根据状态设置RAMP,然后在这里调用mixer的setParameter设置的。
。。。。。//后面代码忽略
}
}
}
prepareTracks_l被 threadLoop调用,threadLoop 一直在跑,具体的不清楚
在
AudioFinger::PlaybackThread::threadLoop()
{
mMixerState = prepareTracks_l(....) // 不停的调用,只要mState有改变,应该就能调到
}
仔细分析stop的过程
PlaybackThread::Track::stop()
{
ALOG() ;// 打log,显示调用stop的pid
if (thread !=0) // thread还在
{
Mutex::Autolock _l(thread->mLock);
track_state state = mState ; //获取stop之前的状态
if (state == RESUMING || state == ACTIVE || STATE == PAUSING ||state == PAUSED) {
PlaybackThread *playbackThread = (P;aybackThrad*) thread.get();
if (playbackThread->mActiveTracks.indexof(this) < 0 ) {
reset (); //如果该播放线程不是active的,就reset下
}
else if (!isFastTrack()) {
mStage = STOPPED; //不是fasttrack 就将状态改为stopped
}
else {
mState = STOPPING_1;
}
ALOGV("not stopping /stopped -> stopping /stopped");
}
if (!isOutputTrack() && (state == ACTIVE) && (state == RESUMING)) {
... mLock.unlock();
AudioSystem::stopOutput(thread->id(), mStreamType,mSessionId) ;
...mLock.lock();
}
}
}
阅读(2969) | 评论(0) | 转发(0) |