Android系统分析之Audio音频流, 音频策略, 输出设备之间的关系
音频流, 音频策略, 输出设备之间的关系
只针对 AudioManager.STREAM_VOICE_CALL 音频流类型进行分析
涉及到的类:
hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
frameworks/base/media/java/android/media/AudioManager.java
frameworks/base/media/java/android/media/AudioService.java
frameworks/base/media/java/android/media/AudioSystem.java
涉及到的方法及执行顺序:
AudioPolicyManagerBase.getStrategy(AudioSystem::stream_type stream);
AudioPolicyManagerBase.getDeviceForStrategy(routing_strategy strategy, bool fromCache);
一. 通过音频流的类型获取对应的音频策略
AudioPolicyManagerBase.cpp:
AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) {
// stream to strategy mapping
switch (stream) {
case AudioSystem::VOICE_CALL:
case AudioSystem::BLUETOOTH_SCO:
return STRATEGY_PHONE;
...
}
}
二. 通过音频策略获取到对应的输出设备
AudioPolicyManagerBase.cpp:
audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) {
uint32_t device = AUDIO_DEVICE_NONE;
... // 省略
switch (strategy) {
... // 省略
case STRATEGY_PHONE:
// for phone strategy, we first consider the forced use and then the available devices by order
// of priority
switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) { // 判断是否有设置在通讯过程中, 强制使用某种输出设备
case AudioSystem::FORCE_BT_SCO: // 强制使用蓝牙, 作为输出设备
if (!isInCall() || strategy != STRATEGY_DTMF) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device) break;
}
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
if (device) break;
// if SCO device is requested but no SCO device is available, fall back to default case
// FALL THROUGH
default: // FORCE_NONE 没有设置通讯过程中, 强制使用某种输出设备
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (mHasA2dp && !isInCall() &&
(mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != 0) && !mA2dpSuspended) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
if (device) break;
}
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
if (device) break;
if (mPhoneState != AudioSystem::MODE_IN_CALL) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
if (device) break;
}
// 没有设置通讯过程中, 音频的输出设备, 则默认使用听筒作为输出设备
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
if (device) break;
device = mDefaultOutputDevice;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
}
break;
case AudioSystem::FORCE_SPEAKER: // 强制使用扬声器, 作为输出设备
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
// A2DP speaker when forcing to speaker output
if (mHasA2dp && !isInCall() &&
(mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != 0) && !mA2dpSuspended) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
}
if (mPhoneState != AudioSystem::MODE_IN_CALL) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if (device) break;
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
if (device) break;
}
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
if (device) break;
device = mDefaultOutputDevice;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
}
break;
}
break;
// 关于上面default位置的问题, 如果每个case选择(包括default)最终都有break语句, 则default的位置不影响执行顺序
// 当每个case选择(包括default)不一定有break语句时, 如果输入不满足其他选择, 最终执行default. 程序会从default处从上向下执行, 直到遇到break语句停止
// 此处的default位置并不影响执行顺序
... // 省略
}
return device;
}
三. 音频流, 音频策略, 输出设备之间的关系
音频的流类型决定音频的策略, 音频的策略决定输出设备. 但是最终的输出设备的确定, 受强制设置输出设备影响.
四. 分析AudioManager.setSpeakerphoneOn(boolean on)方法, 查看强制设置对音频输出设备选择的影响
涉及到的类及方法:
1. AudioManager.setSpeakerphoneOn(boolean on);
2. AudioService.setSpeakerphoneOn(boolean on);
3. AudioService.AudioHandler.setForceUse(int usage, int config);
4. AudioSystem.setForceUse(int usage, int config);
5. AudioPolicyManagerBase.setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
4.1. AudioManager.java:
public void setSpeakerphoneOn(boolean on){
IAudioService service = getService();
service.setSpeakerphoneOn(on);
}
4.2. AudioService.java:
public void setSpeakerphoneOn(boolean on){
if (on) {
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
}
mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
} else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
// 从此处可以看到 setSpeakerphoneOn(boolean on) 只针对 AudioSystem.FOR_COMMUNICATION 有效
// 而 AudioSystem.FOR_COMMUNICATION 最终影响到的是输出设备的选择
sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
}
private class AudioHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_FORCE_USE:
case MSG_SET_FORCE_BT_A2DP_USE:
setForceUse(msg.arg1, msg.arg2);
break;
}
}
private void setForceUse(int usage, int config) {
AudioSystem.setForceUse(usage, config);
}
}
4.3. AudioSystem.java:
public static native int setForceUse(int usage, int config);
4.4. AudioPolicyManagerBase.cpp:
void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) {
bool forceVolumeReeval = false;
switch(usage) {
case AudioSystem::FOR_COMMUNICATION:
if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
config != AudioSystem::FORCE_NONE) {
ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
return;
}
forceVolumeReeval = true;
// 保存设置到数组中, 最终在 getDeviceForStrategy(routing_strategy strategy, bool fromCache) 中被调用
mForceUse[usage] = config;
break;
... // 省略
}
... // 省略
}
Android系统分析之Audio音频流, 音频策略, 输出设备之间的关系的更多相关文章
- Android 中的Activity、Window、View之间的关系
一.概述 Activity 可以说是应用程序的载体(也可以理解为界面的载体,但是不界面),用户能够在上面绘制界面(Activity本身不绘制界面),并提供用户处理事件的API,维护应用程序的生命周 ...
- android 网络编程--socket tcp/ip udp http之间的关系
网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层,一般编程人员接触最多的就是应用层和运输层,再往下的就是所谓的媒体层了,不是我们研究的对象. 下面是应用层.运输层,网络 ...
- Android中的Audio播放:竞争Audio之Audio Focus的应用
from://http://blog.csdn.net/thl789/article/details/7422931 Android是多任务系统,Audio系统是竞争资源.Android2.2之前,没 ...
- 在 Android开发中,性能优化策略十分重要
在 Android开发中,性能优化策略十分重要本文主要讲解性能优化中的布局优化,希望你们会喜欢.目录 示意图 1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如 ...
- h5 audio播放音频文件
h5 audio播放音频文件 注:下面html中样式及不相关的内容去掉了 第一个例子 播放没有防盗链的外网音频文件是可以的 <!doctype html> <html> < ...
- 基于canvas和Web Audio的音频播放器
wavesurfer.js是一款基于HTML5 canvas和Web Audio的音频播放器插件.通过wavesurfer.js你能够使用它来制作各种HTML5音频播放器,它能够在各种支持 Web A ...
- Android开发之控制手机音频
本实例通过MediaPlayer播放一首音乐并通过AudioManager控制手机音频.关于AudioManager的具体解释可參照:Android开发之AudioManager(音频管理器)具体解释 ...
- 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)
Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子. package com.example.loopertest; i ...
- Android进阶笔记08:Android 中Activity、Window和View之间的关系
1. Android 中Activity.Window和View之间的关系(比喻): Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutI ...
随机推荐
- 五、Jmeter中提取JSON响应中数组的长度
json响应如下: { "code":0, "data":{ "data":[ { "amount":50000, &q ...
- dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.7.dylib
dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.7.dylib Table of Contents 1. 启动时报错 ...
- OGG 从Oracle备库同步数据至kafka
OGG 从Oracle备库同步数据至kafka Table of Contents 1. 目的 2. 环境及规划 3. 安装配置JDK 3.1. 安装jdk 3.2. 配置环境变量 4. 安装Data ...
- 代码实现程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印
package com.loaderman.test; import java.util.Comparator; import java.util.Scanner; import java.util. ...
- python安装二进制k8s 1.11.0 一个master、一个node 查看node节点是主机名---apiserver无法启动,后来改了脚本应该可以
一.脚本说明: 本实验中master.node.etcd都是单体. 安装顺序为:先安装test1节点主要组件,然后开始安装test2节点,最后回头把test1节点加入集群中,这样做目的是理解以后扩容都 ...
- H3C 模拟器 pc与sw直连 开启telnet
如图所示 1 在pc上添加虚拟网卡,与上一章节的添加方式相同 配置pc的ip地址 10.17.4.3 255.255.252.0 2 sw设置 <sw1>system-view [sw1] ...
- [转] Maven 从命令行获取项目的版本号
[From]https://blog.soebes.de/blog/2018/06/09/help-plugin/ I bet you have been faced with the situati ...
- springboot 多线程的使用
int pageSize = 10000; int totalCount = doctorDAO.selectDatasByMapCount2(jsonArray, false, null); int ...
- easyui datagrid checkbox复选框取消单击选中事件、初始全选全不选等问题解决
系统业务需要,导入的列表数据默认全部选中,且不可取消选中行.全部店铺优惠券发放过后导入的数据全部清空.如图所示: 一.初始化页面默认全部选中“selectAll”,全部不选中“unselectAll” ...
- Cisco的动态Nat、PAT
Lab_C(config)# interface Ethernet0/0 ip address 192.168.30.2 255.255.255.0 router rip network 172. ...