Android音频系统之AudioFlinger(四)
http://blog.csdn.net/xuesen_lin/article/details/8805096
1.1.1 AudioMixer
每一个MixerThread都有一个唯一对应的AudioMixer(在MixerThread中用mAudioMixer表示),它的作用如其名所表示的,就是为了完成音频的混音操作。

图 13‑14 MixerThread示意图
如上图,MixerThread对外开放的接口主要涉及到Parameter(比如setParameter)、Resampler(比如setResampler)、Volume(比如adjustVolumeRamp)、Buffer(比如setBufferProvider)及Track(比如getTrackName)五个部分。
在内部的实现中,MixerThread的核心是一个mState变量(state_t类型),所有的混音工作都会在这个变量中体现出来——特别是其中的tracks数组,如下所示:
struct state_t {
uint32_t enabledTracks;
uint32_t needsChanged;
size_t frameCount;
void (*hook)(state_t* state, int64_tpts); // one of process__*, never NULL
int32_t *outputTemp;
int32_t *resampleTemp;
int32_t reserved[2];
track_t tracks[MAX_NUM_TRACKS];__attribute__((aligned(32)));
};
MAX_NUM_TRACKS=32,也就是说最多支持32路同时混音,这对于大部分情况肯定是足够了。数据类型track_t是对每个Track的描述,可想而知类似Parameter这种设置,最终影响的就是Track的属性。
struct track_t {
…
union {
int16_t volume[MAX_NUM_CHANNELS];
int32_t volumeRL;
};//音量相关的属性
int32_t prevVolume[MAX_NUM_CHANNELS];
int32_t volumeInc[MAX_NUM_CHANNELS];
…
uint8_t channelCount; //只能是1或2
uint8_t format; // 总是16
uint16_t enabled; // 实际是布尔类型
audio_channel_mask_t channelMask;
AudioBufferProvider* bufferProvider;
mutableAudioBufferProvider::Buffer buffer; // 8 bytes
hook_t hook;
const void* in; //buffer中的当前位置
AudioResampler* resampler;
uint32_t sampleRate;
int32_t* mainBuffer;
int32_t* auxBuffer;
…
bool setResampler(uint32_t sampleRate,uint32_t devSampleRate);
bool doesResample() const { return resampler!= NULL; }
void resetResampler() { if (resampler !=NULL) resampler->reset(); }
void adjustVolumeRamp(bool aux);
size_t getUnreleasedFrames() const { return resampler != NULL ?resampler->getUnreleasedFrames() : 0; };
};
AudioFlinger的threadLoop中,通过不断调用prepareTracks_l来准备数据,而每次prepare实际上都是对所有Track的一次调整。如果属性有变化,就会通过setParamter来告知AudioMixer。
在上一个小节中,threadLoop_mix在内部就是通过AudioMixer来实现混音的,我们这里具体来看下:
void AudioMixer::process(int64_t pts)
{
mState.hook(&mState,pts);
}
“hook”是钩子的意思,为什么取这个名字?一个原因可能是hook指向的实体是变化的,就好像钩子一样,它可以灵活的依附于各种物体之上。从代码层面上看,hook是一个函数指针,它根据当前具体情况会分别指向以下几个函数实现:
process__validate:根据当前具体情况,将hook导向下面的几个实现
process__nop:初始化值
process__OneTrack16BitsStereoNoResampling:只有一路Track,16比特立体声,不重采样
process__genericNoResampling:两路(包含)以上Track,不重采样
process__genericResampling:两路(包含)以上Track,重采样
hook在以下几种情况下会重新赋值
Ø AudioMixer初始化时,hook指向process_nop
Ø 当状态改变或者参数变化时(比如setParameter),调用invalidateState。此时hook指向process__validate
Ø AudioMixer::process是外部调用hook的入口
我们以下面的图来描述一下,大家会看得更清楚些:
图 13‑15 hook的使用
其中process_validate的代码实现如下:
void AudioMixer::process__validate(state_t* state, int64_t pts)
{ …
int countActiveTracks = 0;
boolall16BitsStereoNoResample = true;
bool resampling = false;…
uint32_t en =state->enabledTracks;
while (en) {
const int i = 31 -__builtin_clz(en);
en &= ~(1<<i);
countActiveTracks++;//enabled 状态的Track计数
…
}
state->hook = process__nop;
if (countActiveTracks) {
if (resampling) {
…
state->hook = process__genericResampling;
} else {
…
state->hook = process__genericNoResampling;
if(all16BitsStereoNoResample && !volumeRamp) {
if(countActiveTracks == 1) {
state->hook = process__OneTrack16BitsStereoNoResampling;
}
}
}
}
state->hook(state, pts);
…
}
这个函数先通过while循环逐个分析处于enabled状态的Track,统计其内部各状态位(比如NEEDS_AUX__MASK、NEEDS_RESAMPLE__MASK等等)情况,得出countActiveTracks、resampling、volumeRamp及all16BitsStereoNoResample的合理值,最后根据这几个变量判断选择正确的hook实现,并调用这个hook函数执行具体工作。
关于AudioMixer是如何处理音频数据的,我们将在后续音频流小节做统一分析。
Android音频系统之AudioFlinger(四)的更多相关文章
- Android音频系统之AudioFlinger(一)
1.1 AudioFlinger 在上面的框架图中,我们可以看到AudioFlinger(下面简称AF)是整个音频系统的核心与难点.作为Android系统中的音频中枢,它同时也是一个系统服务,启到承上 ...
- Android音频系统之AudioFlinger(二)
1.1.1 音频设备的管理 虽然AudioFlinger实体已经成功创建并初始化,但到目前为止它还是一块静态的内存空间,没有涉及到具体的工作. 从职能分布上来讲,AudioPolicyService是 ...
- Android音频系统之AudioFlinger(三)
http://blog.csdn.net/xuesen_lin/article/details/8805091 1.1.1 PlaybackThread的循环主体 当一个PlaybackThread进 ...
- Android音频系统之音频框架
1.1 音频框架 转载请注明,From LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492 Android的音频系统在很长一段 ...
- 转:ANDROID音频系统散记之四:4.0音频系统HAL初探
昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...
- Android音频系统之AudioPolicyService
地址:http://blog.csdn.net/edmond999/article/details/18599327 1.1 AudioPolicy Service 在AudioFlinger小节,我 ...
- Android音频系统
1 分析思路 Thread如何创建? AudioPolicyService是策略的制定者,AudioFlinger是策略的执行者, 所以: AudioPolicyService根据配置文件使唤Audi ...
- Android 音频系统得框架
http://www.mamicode.com/info-detail-1790053.html http://blog.csdn.net/lushengchu_luis/article/detail ...
- Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理
Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理 1. 回顾 我们知道Android输入系统是Reader线程通过驱动程序得到上报的输入事件,还要经过处理 ...
随机推荐
- vue.js 2.0开发
创建一个工程文件: css中引用的是bootstrap的css,js中就是vue,index页面: <!DOCTYPE html> <html> <head> &l ...
- 文件_ _android从资源文件中读取文件流并显示的方法
======== 1 android从资源文件中读取文件流并显示的方法. 在android中,假如有的文本文件,比如TXT放在raw下,要直接读取出来,放到屏幕中显示,可以这样: private ...
- 高并发分布式系统中生成全局唯一Id汇总
数据在分片时,典型的是分库分表,就有一个全局ID生成的问题.单纯的生成全局ID并不是什么难题,但是生成的ID通常要满足分片的一些要求: 1 不能有单点故障. 2 以时间为序,或者ID里包含时间 ...
- 12. Binary Tree Postorder Traversal && Binary Tree Preorder Traversal
详见:剑指 Offer 题目汇总索引:第6题 Binary Tree Postorder Traversal Given a binary tree, return the po ...
- win10激活
听了同事忽悠,说x230这款还在保,可以直接装win10,自动激活,结果悲剧.送到联想工作站需要摧毁所有数据,然后还要2.3个小时,遂在网上找了个方法,先用着,只是不知道什么时候又变成黑户: 以管理员 ...
- 构造方法Constructor
构造函数的名称与类名相同,没有返回值类型,主要用于在创建对象的时候进行一些初始化操作,如一个类中没有构造方法,java会默认给一个无参的构造方法
- C# 控制台程序如何能不显示窗口
创建好控制台程序后,选中项目,右键,属性,输出类型选为“windows 应用程序” 这样就没有dos窗口了
- .NET 扩展方法
.NET 的扩展方法是在.NET 3.0引入的,MSDN给出的定义是:扩展方法使你能够向现有类型“添加”方法(包括你自定义的类型和对象噢),而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩 ...
- Linux操作系统奥秘02-系统引导(GRUB)
GRUB的加载流程 GRUB是GNU的一款多重引导软件.GRUB包含了3个重要的文件:stage1 ,e2fsstage1_5,stage2.这三个文件分别代表了GRUB运行的3个阶段. 1.stag ...
- 交换两个数-c++实现
今天看了下交换数值的小程序,网上挺多的,整理了下,,因为参考较多,没一一给出链接,若原作者看到,可以留言,我会添加 // example_1_6_function_swap.cpp : 定义控制台应用 ...