Chinaunix首页 | 论坛 | 博客
  • 博客访问: 93111
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-07 15:39
个人简介

好好学习 ,天天向上

文章分类

全部博文(27)

文章存档

2013年(27)

我的朋友

分类: Android平台

2013-04-15 15:49:40

对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();            
      }    


     }


}



阅读(2960) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~