insert effect 和 aux effect的区别和场景还有部分代码解析

引文

为什么effect会有insert和aux这两种,一直困扰了我很久,后来无意中看到了调音台上面的概念,感觉概念应该是来自于这里,在android里面,insert effect是直接对播放的声音进行添加音效,而aux则是用在混音的场景,aux就相当于干声的另外一股数据,进行另外的数据,但是最终都是要跟原来的声音叠加在一起的。

我在bilibili上看到了个调音台知识的视频,截取了其中的一张图,如下,fx return是接到aux 1和aux2 output。这边的区别是aux模块的接入点跟代码可能有些不同,不够我觉得不影响理解。

正文

先考虑两种场景:

一种是这个track有自己的insert track和一个aux的全局音效

另外一种是这个track没有insert track,但是有一个aux的全局音效

第一种情况:

Thread::track有非全局的insert effect,其inBuffer的独立分配的,outBuffer中externalData指向的是thread::mEffectBuffer,aux同非全局的,其inBuffer也是独立分配的,outBuffer中externalData指向的是thread::mEffectBuffer。

mix结束之后,

aux effect的inbuffer里面存放了aux level以及resample之后的数据,

insert effect的inbuffer里面存放的是mix音量以及resample之后的数据,

接下来是进行effect的process的处理,

aux effect处理完的数据放到了thread::mEffectBuffer

insert effect处理完的数据也放到了thread::mEffectBuffer,这两者的数据是进行叠加的。

第二种情况:

Thread::track有全局的aux effect和没有非全局的insert effect,那在prepareTracks_l的时候,audioMixer会将AudioMixer::track->mainBuffer()指向Thread::mMixerBuffer, 这样mixer出来的数据一份是在mMixerBuffer,一份数据是在auxBuffer。

threadLoop_mix()结束之后,会将数据从Thread::mMixerBuffer拷贝到Thread::mEffectBuffer,而aux effect的InBuffer中存放着mix之后的aux数据,他的outBuffer其实是指向全局音效链的halOutBuffer的,也就是Thread::mEffectBuffer,所以在处理完aux effect的时候,两股数据流已经在这里完成合并了,不同于第一种情况,是在处理完之后才合并的。

buffer相关代码分析

梳理下effect相关的buffer情况:

1. 从AudioFlinger::createEffect()开始:

A. 创建effectchain并且添加到thread中来,在addEffectChain_l中,会申请mEffectBuffer的镜像halInBuffer,里mAudioBuffer是其中申请出来新的空间,这个halInBuffer中的externalData指向的是thread的mEffectBuffer.

如果不是全局音效链,并且不在DIRECT output中,则会重新分配halInBuffer,不过这个时候的externalBuffer则是为null。buffer指向新创建的mAudioBuffer.raw。然后更新该线程下所有这个sessionId相同的track的mainbuffer的指向,指向mAudioBuffer.raw。

接下来是设置chain的inBuffer指向halInBuffer,chain的OutBuffer指向halOutBuffer,在全局音效的情况下halInBuffer等于halOutBuffer,在非全局音效情况下,halInBuffer是指向后来申请的对象的。

接下来是对音效链进行排序,sessionId从大到小排序。从0开始遍历,找到比我小的,占用他的位置,比如说第0个就比我小,那就占用了第0位置。所以是从大到小的排序。

所以从上面可以知道,对于全局音效链的buffer信息差不多如下:

x effects for session 0

In buffer                Out buffer                Active tracks:

0xb400007bbe921000 -> 0x7bbeba2000    0x7bbeba2000 -> 0xb400007bbe921000 0

Thread::mEffectBuffer -> 新申请的空间    新申请的空间 - > Thread::mEffectBuffer

Effect ID 163:

-Input configuration:

Buffer    Frames    Smp rate  Channels  Format

0x7bbeba2000  00960  48000  00000003   5(AUDIO_FORMAT_PCM_FLOAT)

-Output configuration:

Buffer    Frames    Smp rate  Channels  Format

0x7bbeba2000  00960  48000  00000003   5(AUDIO_FORMAT_PCM_FLOAT)

-HAL buffers:

In(0xb400007bbe921000 -> 0x7bbeba2000) InConversion(nullptr) Out(0x7bbeba2000 -> 0xb400007bbe921000) OutConversion(nullptr)

B. 在effectChain中创建effect, chain::createEffect_l

B.1 new EffectModule

B.2 addEffect_ll(effect)

B.2.1 如果这个音效是AUX,则将该音效插入到音效链的第0位置,并且申请halBuffer,externalData为null的,然后effect inBuffer指向新申请的buffer,outBuffer指向chain的inBuffer,这个inBuffer,AUX必须是全局音效,这个inBuffer指向的halInBuffer是带有externalData的。所以对于AUX音效的话,其buffer信息如下:

全局音效链

In buffer        Out buffer

0xb400007bbe921000 -> 0x7bbeba2000  0x7bbeba2000 -> 0xb400007bbe921000

AUX音效,放在第一个节点,下面是buffer信息:

HAL buffers:

In(0x7bbeba2000) InConversion(nullptr) Out(0x7bbeba2000 -> 0xb400007bbe921000) OutConversion(nullptr)

In是新申请的空间  Out是Chain的halOutBuffer,即从链申请的buffer到externalData即Thread::mEffectBuffer

其他全局音效的buffer信息:

HAL buffers:

In(0xb400007bbe921000 -> 0x7bbeba2000) InConversion(nullptr) Out(0x7bbeba2000 -> 0xb400007bbe921000) OutConversion(nullptr)

其中的inBuffer和outBuffer都指向全局的hallInBuffer和halOutBuffer,而这两个值相等。

如果这个音效不是AUX,则对这个effect也进行排序,这个音效的inBuffer指向chain的inBuffer,而outBuffer则是看他处在第几个位置,如果是最后一个位置,则指向chain的OutBuffer,如果不是的话,则指向mInBuffer。所以如果是全局音效链的话,那inBuffer跟outBuffer是一样的,不是全局的话,则inBuffer指向的是不带有externalData的halInBuffer。所以如果不是Aux音效的话,其中的buffer信息如下:

非全局的音效的buffer信息则是:

In buffer        Out buffer        Active tracks:

0x76c8e0c000     0x76c8e7b000 -> 0x7641bc91c0

Effect ID 259:

HAL buffers:

In(0x76c8e0c000) InConversion(nullptr) Out(0x76c8e0c000) OutConversion(nullptr)

Effect ID 283:

HAL buffers:

In(0x76c8e0c000) InConversion(nullptr) Out(0x76c8e7b000 -> 0x7641bc91c0) OutConversion(nullptr)

B.2.2 effect->configure() 将配置信息发送到HAL层的effect去,包括inbuffer和outbuffer等信息。

2. 从AudioFlinger::createTrack()开始

-》thread::createTrack_l() 中会通过sessionId获取effectChain,而这个sessionId是不为0(0是全局音效),然后会将chain->inBuffer设置到track的mainBuffer。

所以平时如果该track有非全局的effect的话,那他的main指向的是chain的inBuffer应该是没有externalData的halInBuffer的。那如果没有非全局的effect的话,track的mainBuffer指向的是mSinkBuffer(这个在TrackBase构造函数里面设定的)。不过这个mainBuffer虽然指向sinkBuffer,但是在mixerThread中,最后配置到Mixer中的mainBuffer是Thread::mMixerBuffer

而对于track的auxBuffer是在audioTrack调用attachAuxEffect的时候才会进行设置,是根据effectId进行查找effect,小心不是sessionId,获取到对应的effect之后,会将该effect的InBuffer设置到track的auxBuffer。按照上面auxEffect的inBuffer是自己开辟的一个新的buffer。

总结

到这边,我们对于buffer的部分也比较清晰了,

全局音效链的inBuffer和outBuffer,指向halInBuffer和halOutBuffer,这两个值相等,但是有方向之说。

链里面不管有没有aux存在,其处理结束的数据都是在mEffectBuffer中,其处理前的数据是存放在各自的inBuffer,这部分的数据是mix之后的数据,aux是直接放到自己的空间,而其他音效则是在mEffectBuffer中。

对于非全局音效链的话,则他的InBuffer是自己申请的空间,outBuffer是halOutBuffer也就是external指向mEffectBuffer,链内部的effect的InBuffer和outBuffer都是指向自己创建的空间,最后一个effect的outBuffer才会指向halOutBuffer。mix的数据是送到InBuffer中的。

另外这边备注一段代码:

frameworks/av/services/audioflinger/Effects.h

class EffctModule : public EffectBase {

int16_t     *inBuffer() const {

return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;

}

int16_t     *outBuffer() const {

return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;

}

}

frameworks/av/media/libaudiohal/include/media/audiohal/EffectBufferHalInterface.h

class EffectBufferHalInterface : public RefBase

{

public:

virtual audio_buffer_t* audioBuffer() = 0;

virtual void* externalData() const = 0;

virtual void* ptr() {

return externalData() != nullptr ? externalData() : audioBuffer()->raw;

}

}

原文链接:https://blog.csdn.net/Death__Azreal/article/details/118550791

(0)

相关推荐