7.5.1 DuplicatingThread破解
最后更新于:2022-04-02 05:51:50
DuplicatingThread需要与蓝牙结合起来使用,它的存在与Audio硬件结构息息相关。读者可参考图7-12“智能手机硬件架构图”来理解。当一份数据同时需要发送给DSP和蓝牙A2DP设备时,DuplicatingThread就派上用场了。在分析DuplicatingThread前,还是应该了解一下它的来龙去脉。
1. DuplicatingThread的来历
DuplicatingThread和蓝牙的A2DP设备有关系。可先假设有一个蓝牙立体声耳机已经连接上了,接着从setDeviceConnectionState开始分析,代码如下所示:
**AudioPolicyManagerBase.cpp**
~~~
status_t AudioPolicyManagerBase::setDeviceConnectionState(
AudioSystem::audio_devicesdevice,
AudioSystem::device_connection_state state,
const char *device_address)
{
......
switch (state)
{
case AudioSystem::DEVICE_STATE_AVAILABLE:
mAvailableOutputDevices |= device;
#ifdef WITH_A2DP
if (AudioSystem::isA2dpDevice(device)) {
//专门处理A2DP设备的连接
status_t status = handleA2dpConnection(device, device_address);
}
#endif
......
~~~
对于A2DP设备,有专门的函数handleA2dpConnection处理,代码如下所示:
**AudioPolicyManagerBase.cpp**
~~~
status_tAudioPolicyManagerBase::handleA2dpConnection(
AudioSystem::audio_devicesdevice,
const char*device_address)
{
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
outputDesc->mDevice= device;
//先为mA2dpOutput创建一个MixerThread,这个和mHardwareOutput一样
mA2dpOutput =mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
if (mA2dpOutput) {
/*
a2dpUsedForSonification永远返回true,表示属于SONIFCATION策略的音频流声音需要
同时从蓝牙和DSP中传出。属于SONIFCATION策略的音频流类型可查看前面关于getStrategy的
分析,来电铃声、短信通知等属于这一类
*/
if(a2dpUsedForSonification()) {
/*
创建一个DuplicateOutput,注意它的参数,第一个是蓝牙MixerThread
第二个是DSPMixerThread
*/
mDuplicatedOutput = mpClientInterface->openDuplicateOutput(
mA2dpOutput, mHardwareOutput);
}
if(mDuplicatedOutput != 0 ||
!a2dpUsedForSonification()) {
if (a2dpUsedForSonification()) {
//创建一个AudioOutputDescriptor对象
AudioOutputDescriptor *dupOutputDesc = new
AudioOutputDescriptor();
dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput);
dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput);
......
//保存mDuplicatedOutput和dupOutputDesc键值对
addOutput(mDuplicatedOutput, dupOutputDesc);
......
}
}
}
......
~~~
这里,最重要的函数是openDuplicateOutput。它和openOutput一样,最终的处理都是在AF中。去那里看看,代码如下所示:
**AudioFlinger.cpp**
~~~
int AudioFlinger::openDuplicateOutput(intoutput1, int output2)
{
Mutex::Autolock_l(mLock);
//output1对应蓝牙的MixerThread
MixerThread*thread1 = checkMixerThread_l(output1);
//output2对应DSP的MixerThread
MixerThread *thread2 = checkMixerThread_l(output2);
//①创建DuplicatingThread,注意它第二个参数使用的,是代表蓝牙的MixerThread
DuplicatingThread *thread = new DuplicatingThread(this,
thread1,++mNextThreadId);
//②加入代表DSP的MixerThread
thread->addOutputTrack(thread2);
mPlaybackThreads.add(mNextThreadId, thread);
returnmNextThreadId;//返回DuplicatingThread的索引
}
~~~
从现在起,MixerThread要简写为MT,而DuplicatingThread则简写为DT。
OK,这里面有两个重要的函数调用,一起来看。
2. DuplicatingThread和OutputTrack
先看DT的构造函数,代码如下所示:
**AudioFlinger.cpp**
~~~
AudioFlinger::DuplicatingThread::DuplicatingThread(constsp&
audioFlinger, AudioFlinger::MixerThread*mainThread,int id)
: MixerThread(audioFlinger,mainThread->getOutput(), id),
mWaitTimeMs(UINT_MAX)
{
//DT是MT的派生类,所以先要完成基类的构造,还记得MT的构造吗?它会创建一个AudioMixer对象
mType =PlaybackThread::DUPLICATING;
//把代表DSP的MT加入进来,咱们看看
addOutputTrack(mainThread);
}
~~~
**AudioFlinger.cpp**
~~~
voidAudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
intframeCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
//构造一个OutputTrack,它的第一个参数是MT
OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
this, mSampleRate, mFormat,
mChannelCount,frameCount);
if(outputTrack->cblk() != NULL) {
thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
//把这个outputTrack加入到mOutputTracks数组保存
mOutputTracks.add(outputTrack);
updateWaitTime();
}
}
~~~
此时,当下面两句代码执行完:
~~~
DuplicatingThread *thread = newDuplicatingThread(this,
thread1,++mNextThreadId);
thread->addOutputTrack(thread2);
~~~
DT分别构造了两个OutputTrack,一个对应蓝牙的MT,一个对应DSP的MT。现在来看OutputTrack为何方神圣,代码如下所示:
**AudioFlinger.cpp**
~~~
AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
const wp& thread, DuplicatingThread*sourceThread,
uint32_t sampleRate, int format,int channelCount,int frameCount)
:Track(thread,NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate,
format, channelCount, frameCount, NULL),//最后这个参数为NULL
mActive(false),mSourceThread(sourceThread)
{
/*
OutputTrack从Track派生,所以需要先调用基类的构造,还记得Track构造函数
中的事情吗?它会创建一块内存,至于是不是共享内存,由Track构造函数的最后一个参数决定。
如果该值为NULL,表示没有客户端参与,则会在本进程内创建一块内存,这块内存的结构如
图7-4所示,前边为CB对象,后边为数据缓冲
*/
//下面的这个thread对象为MT
PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
if(mCblk != NULL) {
mCblk->out = 1;//表示DT将往MT中写数据
//和前面所分析的AT、AF中的处理何其相似!
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
mOutBuffer.frameCount = 0;
//把这个Track加到MT的Track中
playbackThread->mTracks.add(this);
}
~~~
明白了吗?图7-16表示的是openDuplicateOutput的结果:
:-: ![](http://img.blog.csdn.net/20150802161026784?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图7-16 openDuplicateOutput的结果示意图
图7-16说明(以蓝牙MT为例):
- 蓝牙MT的Track中有一个成员为OutputTrack0。
- DT的mOutputTracks也有一个成员指向OutputTrack0。这就好像DT是MT的客户端一样,它和前面分析的AT是AF的客户端类似。
- 红色部分代表数据传递用的缓冲。
3. DT的客户端AT
DT是从MT中派生的,根据AP和AT的交互流程,当AT创建的流类型对应策略为SONIFACATION时,它会从AP中得到代表DT的线程索引号。由于DT没有重载createTrack_l,所以这个过程也会创建一个Track对象(和MT创建Track对象一样)。此时的结果,将导致图7-16变成图7-17。
:-: ![](http://img.blog.csdn.net/20150802160934318?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图7-17 有AT的DT全景图
图7-17把DT的工作方式表达得非常清晰了。一个DT配合两个OutputTrack中的进程内缓冲,把来自AT的数据原封不动地发给蓝牙MT和DSP MT,这简直就是个数据中继器!。不过俗话说得好,道理虽简单,实现却复杂。来看DT是如何完成这一复杂而艰巨的任务的吧。
4. DT的线程函数
DT的线程函数代码如下所示:
**AudioFlinger.cpp**
~~~
boolAudioFlinger::DuplicatingThread::threadLoop()
{
int16_t* curBuf = mMixBuffer;
Vector< sp
';