//终于找到了,把这个线程加入线程管理组织中
mPlaybackThreads.add(mNextThreadId, thread); return mNextThreadId; } }
明白了,看来AT在调用AF的createTrack的之前,AF已经在某个时候把线程创建好了,而且是一个Mixer类型的线程,看来和混音有关系呀。这个似乎和我们开始设想的AF工作有点联系喔。Lock,读缓存,写Audio硬件,Unlock。可能都是在这个线程里边做的。 2 继续createTrack
AudioFlinger::createTrack( pid_t pid, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags,
const sp
sp
//假设我们找到了对应的线程 Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output); //晕,调用这个线程对象的createTrack_l
track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, &lStatus);
}
trackHandle = new TrackHandle(track);
return trackHandle;----》注意,这个对象是最终返回到AT进程中的。
实在是....太绕了。再进去看看thread->createTrack_l吧。_l的意思是这个函数进入之前已经获得同步锁了。
跟着sourceinsight ctrl+鼠标左键就进入到下面这个函数。 下面这个函数的签名好长啊。这是为何?
原来Android的C++类中大量定义了内部类。说实话,我之前几年的C++的经验中基本没接触过这么频繁使用内部类的东东。--->当然,你可以说STL也大量使用了呀。 我们就把C++的内部类当做普通的类一样看待吧,其实我感觉也没什么特殊的含义,和外部类是一样的,包括函数调用,public/private之类的东西。这个和JAVA的内部类是大不一样的。
sp AudioFlinger::PlaybackThread::createTrack_l( const sp& client, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount,
const sp
sp track; status_t lStatus; { // scope for mLock
Mutex::Autolock _l(mLock); //new 一个track对象
//我有点愤怒了,Android真是层层封装啊,名字取得也非常相似。 //看看这个参数吧,注意sharedBuffer这个,此时的值应是0
track = new Track(this, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer);
mTracks.add(track); //把这个track加入到数组中,是为了管理用的。 }
lStatus = NO_ERROR; return track; }
看到这个数组的存在,我们应该能想到什么吗?这时已经有:
? 一个MixerThread,内部有一个数组保存track的
看来,不管有多少个AudioTrack,最终在AF端都有一个track对象对应,而且这些所有的track对象都会由一个线程对象来处理。----难怪是Mixer啊
再去看看new Track,我们一直还没找到共享内存在哪里创建的!!!
AudioFlinger::PlaybackThread::Track::Track( const wp
const sp
: TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
mMute(false), mSharedBuffer(sharedBuffer), mName(-1) {
// mCblk !=NULL?什么时候创建的??
//只能看基类TrackBase,还是很愤怒,太多继承了。 if (mCblk != NULL) { mVolume[0] = 1.0f; mVolume[1] = 1.0f; mStreamType = streamType;
mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t); } }
看看基类TrackBase干嘛了
AudioFlinger::ThreadBase::TrackBase::TrackBase(
const wp
const sp
mFlags(flags & ~SYSTEM_FLAGS_MASK) {
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = frameCount*channelCount*sizeof(int16_t); if (sharedBuffer == 0) { size += bufferSize; }
//调用client的allocate函数。这个client是什么?就是我们在CreateTrack中创建的 那个Client,我不想再说了。反正这里会创建一块共享内存 mCblkMemory = client->heap()->allocate(size);
有了共享内存,但是还没有里边有同步锁的那个对象audio_track_cblk_t mCblk = static_cast(mCblkMemory->pointer()); 下面这个语法好怪啊。什么意思???
new(mCblk) audio_track_cblk_t();
//各位,这就是C++语法中的placement new。干啥用的啊?new后面的括号中是一块buffer,再
后面是一个类的构造函数。对了,这个placement new的意思就是在这块buffer中构造一个对象。
我们之前的普通new是没法让一个对象在某块指定的内存中创建的。而placement new却可以。
这样不就达到我们的目的了吗?搞一块共享内存,再在这块内存上创建一个对象。这样,这个对象不也就能在两个内存中共享了吗?太牛牛牛牛牛了。怎么想到的? // clear all buffers
mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; mCblk->channels = (uint8_t)channelCount; }
好了,解决一个重大疑惑,跨进程数据共享的重要数据结构audio_track_cblk_t是通过placement new在一块共享内存上来创建的。 回到AF的CreateTrack,有这么一句话: trackHandle = new TrackHandle(track);
return trackHandle;----》注意,这个对象是最终返回到AT进程中的。 trackHandle的构造使用了thread->createTrack_l的返回值。
2.4 到底有少种对象
读到这里的人,一定会被异常多的class类型,内部类,继承关系搞疯掉。说实话,这里废点心血整个或者paste一个大的UML图未尝不可。但是我是不太习惯用图说话,因为图我实在是记不住。那好吧。我们就用最简单的话语争取把目前出现的对象说清楚。 1 AudioFlinger
class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient AudioFlinger类是代表整个AudioFlinger服务的类,其余所有的工作类都是通过内部类的方式在其中定义的。你把它当做一个壳子也行吧。 2 Client
Client是描述C/S结构的C端的代表,也就算是一个AT在AF端的对等物吧。不过可不是Binder机制中的BpXXX喔。因为AF是用不到AT的功能的。 class Client : public RefBase { public:
sp mAudioFlinger;//代表S端的AudioFlinger
sp
Trackhandle是AT端调用AF的CreateTrack得到的一个基于Binder机制的Track。