AudioFlinger分析(4)

2020-02-20 14:13

这个TrackHandle实际上是对真正干活的PlaybackThread::Track的一个跨进程支持的封装。 什么意思?本来PlaybackThread::Track是真正在AF中干活的东西,不过为了支持跨进程的话,我们用TrackHandle对其进行了一下包转。这样在AudioTrack调用TrackHandle的功能,实际都由TrackHandle调用PlaybackThread::Track来完成了。可以认为是一种Proxy模式吧。 这个就是AudioFlinger异常复杂的一个原因!!! class TrackHandle : public android::BnAudioTrack { public:

TrackHandle(const sp& track);

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 getCblk() const; sp mTrack; }; 4 线程类

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 = mThread.promote();

//这个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;


AudioFlinger分析(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:华理工 宏观经济学 - 201606 - 模拟卷2

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: