android声音通道的切换
转载neverbefat 发布于2016-11-30 14:44:01 阅读数 6199 收藏
展开
在进行通道切换时,为什么会在原通道上设置一回在去设置新的通道
一、Application framework
在Application framework层级是app层的code,是通过android.media提供的API来与audio硬件进行交互动作,这部分的代码是通过audio JNI来调用native代码从而达到影响硬件的效果;
二、JNI
JNI部分的代码是位于 frameworks/base/core/jni/和frameworks/base/media/jni 目录下的;
三、Native framework
四、Binder IPC
Binder IPC通信是跨进程通信的手段,audio的这部分代码位于frameworks/av/media/libmedia目录下,并且命名都是以I开头的;
五、Media Server
Audio Service是隶属Media Server的,其代码位于 frameworks/av/services/audioflinger,它是真正的与HAL层的实现进行交互的;
六、HAL
HAL层定义了Audio Service调用的标准接口,不同的硬件必须根据自己的情况来实现这个接口来让硬件在android中正常的工作,所以可以在不影响应用层系统调用的情况下,更换不同的硬件。大大减少了系统耦合性;
七、Kernel Driver
Audio驱动是与硬件进行交互,并且实现HAL层的接口供上层正常调用,这里,厂商可以选择ALSA,OSS以及自定义的音频驱动; (NOTE:如果选择ALSA,android建议使用 external/tinyalsa目录下的实现); 接下来就来说说通话时音频通道的切换,但是往下看之前必须知道,对于Audio Path的切换,android有一策略管理器来帮我们分配好输入输出的设备,比如当手机播放音乐时,从Speaker播放出来,这时候插入耳机的话会从耳机设备输出;但是有时候我们想要自己去指定的话,就是我们接下来要说的了; 我们在通话时,要是开免提,实际上也就是Audio Path切换到了Speaker,也就是外方喇叭;代码中的话调用一个函数即可,这是强制切换audio Path,不遵从系统的分配:
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager.setSpeakerphoneOn(true);
中间过程简单不说,最终是调用到了JNI,android_media_AudioSystem中的android_media_AudioSystem_setForceUse()函数,来看下其具体实现:
android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
{
return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
static_cast <audio_policy_forced_cfg_t>(config)));
}
显而易见,它是调用了AudioSystem.cpp的setForceUse()函数,check_AudioSystem_Command()不说,重点看看audio_policy_force_use_t和audio_policy_forced_cfg_t这两个结构体:
audio_policy_force_use_t 说明