这个TrackHandle实际上是对真正干活的PlaybackThread::Track的一个跨进程支持的封装。 什么意思?本来PlaybackThread::Track是真正在AF中干活的东西,不过为了支持跨进程的话,我们用TrackHandle对其进行了一下包转。这样在AudioTrack调用TrackHandle的功能,实际都由TrackHandle调用PlaybackThread::Track来完成了。可以认为是一种Proxy模式吧。 这个就是AudioFlinger异常复杂的一个原因!!! class TrackHandle : public android::BnAudioTrack { public:
TrackHandle(const sp
virtual ~TrackHandle(); virtual status_t start(); virtual void stop(); virtual void flush(); virtual void mute(bool); virtual void pause();
virtual void setVolume(float left, float right); virtual sp
AF中有好几种不同类型的线程,分别有对应的线程类型:
? RecordThread:
RecordThread : public ThreadBase, public AudioBufferProvider 用于录音的线程。
? PlaybackThread:
class PlaybackThread : public ThreadBase 用于播放的线程
? MixerThread
MixerThread : public PlaybackThread
用于混音的线程,注意他是从PlaybackThread派生下来的。
? DirectoutputThread
DirectOutputThread : public PlaybackThread
直接输出线程,我们之前在代码里老看到DIRECT_OUTPUT之类的判断,看来最终和这个线程有关。
? DuplicatingThread:
DuplicatingThread : public MixerThread 复制线程?而且从混音线程中派生?暂时不知道有什么用
这么多线程,都有一个共同的父类ThreadBase,这个是AF对Audio系统单独定义的一个以Thread为基类的类。------》FT,真的很麻烦。
ThreadBase我们不说了,反正里边封装了一些有用的函数。 我们看看PlayingThread吧,里边由定义了内部类:
5 PlayingThread的内部类Track
我们知道,TrackHandle构造用的那个Track是PlayingThread的createTrack_l得到的。 class Track : public TrackBase 晕喔,又来一个TrackBase。 TrackBase是ThreadBase定义的内部类
class TrackBase : public AudioBufferProvider, public RefBase
基类AudioBufferProvider是一个对Buffer的封装,以后在AF读共享缓冲,写数据到硬件HAL中用得到。
个人感觉:上面这些东西,其实完完全全可以独立到不同的文件中,然后加一些注释说明。 写这样的代码,要是我是BOSS的话,一定会很不爽。有什么意义吗?有什么好处吗?
2.5 AF流程继续
好了,这里终于在AF中的createTrack返回了TrackHandle。这个时候系统处于什么状态?
? AF中的几个Thread我们之前说了,在AF启动的某个时间就已经起来了。我们就假设AT调用AF服务前,这个线程就已经启动了。
这个可以看代码就知道了:
void AudioFlinger::PlaybackThread::onFirstRef() {
const size_t SIZE = 256; char buffer[SIZE];
snprintf(buffer, SIZE, \
//onFirstRef,实际是RefBase的一个方法,在构造sp的时候就会被调用 //下面的run就真正创建了线程并开始执行threadLoop了 run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); }
到底执行哪个线程的threadLoop?我记得我们是根据output句柄来查找线程的。 看看openOutput的实行,真正的线程对象创建是在那儿。 nt AudioFlinger::openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, uint32_t *pLatencyMs, uint32_t flags) {
if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || (format != AudioSystem::PCM_16_BIT) ||
(channels != AudioSystem::CHANNEL_OUT_STEREO)) {
thread = new DirectOutputThread(this, output, ++mNextThreadId); //如果flags没有设置直接输出标准,或者format不是16bit,或者声道数不是2立体声
//则创建DirectOutputThread。 } else {
//可惜啊,我们创建的是最复杂的MixerThread
thread = new MixerThread(this, output, ++mNextThreadId); 1. MixerThread
非常重要的工作线程,我们看看它的构造函数。
AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, AudioStreamOut* output, int id)
: PlaybackThread(audioFlinger, output, id), mAudioMixer(0) {
mType = PlaybackThread::MIXER;
//混音器对象,传进去的两个参数时基类ThreadBase的,都为0 //这个对象巨复杂,最终混音的数据都由它生成,以后再说... mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); } 2. AT调用start
此时,AT得到IAudioTrack对象后,调用start函数。 status_t AudioFlinger::TrackHandle::start() { return mTrack->start();
} //果然,自己又不干活,交给mTrack了,这个是PlayintThread createTrack_l得到的Track对象
status_t AudioFlinger::PlaybackThread::Track::start() {
status_t status = NO_ERROR;
sp
//这个Thread就是调用createTrack_l的那个thread对象,这里是MixerThread if (thread != 0) {
Mutex::Autolock _l(thread->mLock); int state = mState; if (mState == PAUSED) { mState = TrackBase::RESUMING; } else {
mState = TrackBase::ACTIVE; }
//把自己由加到addTrack_l了
//奇怪,我们之前在看createTrack_l的时候,不是已经有个map保存创建的track了 //这里怎么又出现了一个类似的操作?
PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); playbackThread->addTrack_l(this); return status; }
看看这个addTrack_l函数
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp& track) {
status_t status = ALREADY_EXISTS;
// set retry count for buffer fill
track->mRetryCount = kMaxTrackStartupRetries; if (mActiveTracks.indexOf(track) < 0) {
mActiveTracks.add(track);//啊,原来是加入到活跃Track的数组啊 status = NO_ERROR; }
//我靠,有戏啊!看到这个broadcast,一定要想到:恩,在不远处有那么一个线程正
//等着这个CV呢。 mWaitWorkCV.broadcast(); return status; }
让我们想想吧。start是把某个track加入到PlayingThread的活跃Track队列,然后触发一个信号事件。由于这个事件是PlayingThread的内部成员变量,而PlayingThread又创建了一个线程,那么难道是那个线程在等待这个事件吗?这时候有一个活跃track,那个线程应该可以干活了吧? 这个线程是MixerThread。我们去看看它的线程函数threadLoop吧。 bool AudioFlinger::MixerThread::threadLoop() {
int16_t* curBuf = mMixBuffer; Vector< sp > tracksToRemove; while (!exitPending()) {
processConfigEvents(); //Mixer进到这个循环中来 mixerStatus = MIXER_IDLE; { // scope for mLock Mutex::Autolock _l(mLock);
const SortedVector< wp >& activeTracks = mActiveTracks; //每次都取当前最新的活跃Track数组
//下面是预备操作,返回状态看看是否有数据需要获取
mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
}
//LIKELY,是GCC的一个东西,可以优化编译后的代码 //就当做是TRUE吧
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { // mix buffers...
//调用混音器,把buf传进去,估计得到了混音后的数据了
//curBuf是mMixBuffer,PlayingThread的内部buffer,在某个地方已经创建好了, //缓存足够大
mAudioMixer->process(curBuf); sleepTime = 0;