目录
1. 日志类型
2. 日志级别 priority:
3. 查看日志常用函数:
3.1 播放相关
3.2 设备选择相关
3.3 音量相关
3.4 常用的日志 关键字
4. CallAudioState \ CallAudioManager
5. 音频流类型获取音频的路由策略
6. 通过streamType得到audio_io_handle
6.1 APM(AudioPolicyManager)
6.2 Engine: getOutputDevicesForStream
6.2.1 getAttributesForStreamType
6.2.2 getOutputDevicesForAttributes
6.2.3 getOutputsForDevices(devices, mOutputs);
6.2.4 selectOutput
1. 日志类型
Logger日志驱动程序内部使用一个环形缓冲区保存日志,缓冲区满了之后新日志会覆盖旧日志。因此要按照日志类型和输出量对日志进行分类,避免不重要日志覆盖重要日志,数据量大的日志覆盖数据量小的日志。
日志类型 | 作用 | Java接口 | 备注 |
main | 应用程序级别 | ||
system | 系统级别 | 重要 | |
event | 诊断系统问题 | 应用程序开发者不应该 使用此类型的日志 |
|
radio | 无线设备相关 | 数据量大 |
如果使用和接口写入的日志标签值是以“RIL”开头或者等于“HTC_RIL”、“AT”、“GSM”、“STK”、“CDMA”、“PHONE”和“SMS”时,他们就会被转换为radio类型的日志写入到Logger日志驱动程序中。
2. 日志级别 priority:
- V 最小级别日志,Verbose级
- D 调试信息,Debug级
- I 打印重要数据,Info级
- W 打印警告信息,Warn级
- E 打印错误信息,Error级
- F 非常严重的错误信息,Fatal级
一般查看日志都是查看Error级
3. 查看日志常用函数:
3.1 播放相关
1、startOutput() output %d, stream %d, session %d, portId %d, phoneState %d, communiCf %d, mediaCf %d
该函数表示一段音频的开始
stream为音频的类型,常见类型有0(通话);1(系统音);2(铃声);3(媒体音);4(闹钟);5(通知音);6(通话音蓝牙SCO);7(强制音);8(DTMF拨号音);9(TTS智慧语音);10(辅助功能提示音);
session:标识一个实例,可以通过这个找到播放的应用
phoneState:显示的是通话状态
后面两个表示是否强制用于通话或者媒体
2、stopOutput() output %d, stream %d, session %d, portId %d
该函数表示一段音频的结束。
参数与相对应的startOutput相对应
3、asd_out : L = [0], R = [0], continus 20 times
hal层输出,如果存在就说明hal层有声音,但不一定准确
4、asd_out_fwk: L = [0], R = [0], continus 20 times, Device = 0x80
asd_out_fwk: L = -33.742146db, R = -33.591274db, Device = 0x80, TimeStampKernel = 908640, TimeStampServer = 923520
fwk最终的声音
3.2 设备选择相关
一般在播放一段音频之后紧跟的就是输出设备的选择,很多时候无声问题往往就是因为播放设备选错引起的
1、setDeviceConnectionStateInt() device: 0x%X, state %d, name %s format 0x%X
该函数用来确定设备的连接与断开,但是由于fwk属于中间层,所以即使我们打印了这句话,
也不能确保设备确实连接上或者断开了,尤其是对于蓝牙,可能出现打印了已断开但断开失败的问题。
device为设备的类型。
state为状态,1表示连接,0表示断开。
name为设备名称。
format为蓝牙音频解码器(具体哪些不太清楚)。
/* Formats for A2DP codecs, must match system/ audio_format_t */
public static final int AUDIO_FORMAT_INVALID = 0xFFFFFFFF;
public static final int AUDIO_FORMAT_DEFAULT = 0;
public static final int AUDIO_FORMAT_AAC = 0x04000000;
public static final int AUDIO_FORMAT_SBC = 0x1F000000;
public static final int AUDIO_FORMAT_APTX = 0x20000000;
public static final int AUDIO_FORMAT_APTX_HD = 0x21000000;
public static final int AUDIO_FORMAT_LDAC = 0x23000000;
2、changing device to %s
打印出这句话表示设备已经切换,如果没有这句而有setOutputDevice则未发生切换,虽然是切换函数但是切换是有条件的。
device,也就是%s位置的值为设备类型与上面的device相对应。
3、setForceUse() usage %d, config %d, mPhoneState %d mA2dpSuspended 0
该函数用来选择设备的切换
(是setOutputDevices之所以选择某个设备的原因,也就是先执行了setForceUse,然后才是setOutputDevices),往往在设备切换出错时使用。
usage是场景,也就是用来播什么,比如是响铃,通话,或是媒体,具体类型如下。
//usage for setForceUse, must match audio_policy_force_use_t
public static final int FOR_COMMUNICATION = 0;
public static final int FOR_MEDIA = 1;
public static final int FOR_RECORD = 2;
public static final int FOR_DOCK = 3;
public static final int FOR_SYSTEM = 4;
public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
public static final int FOR_ENCODED_SURROUND = 6;
public static final int FOR_VIBRATE_RINGING = 7;
public static final int FOR_DESKTOP_MODE = 8;
public static final int FOR_EXTEND_MEDIA = 9;
private static final int NUM_FORCE_USE = 10;
config是设备,如下
//device categories config for setForceUse, must match audio_policy_forced_cfg_t
public static final int FORCE_NONE = 0;
public static final int FORCE_SPEAKER = 1;
public static final int FORCE_HEADPHONES = 2;
public static final int FORCE_BT_SCO = 3;
public static final int FORCE_BT_A2DP = 4;
public static final int FORCE_WIRED_ACCESSORY = 5;
public static final int FORCE_BT_CAR_DOCK = 6;
public static final int FORCE_BT_DESK_DOCK = 7;
public static final int FORCE_ANALOG_DOCK = 8;
public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_NO_BT_A2DP = 10;
public static final int FORCE_SYSTEM_ENFORCED = 11;
public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
public static final int FORCE_ENCODED_SURROUND_MANUAL = 15;
public static final int FORCE_DESKTOP_HDMI = 16;
public static final int FORCE_DESKTOP_NO_HDMI = 17;
public static final int FORCE_EXTEND_EARPIECE = 18;
public static final int FORCE_EXTEND_SPEAKER = 19;
public static final int FORCE_EXTEND_A2DP = 20;
public static final int FORCE_EXTEND_SCO = 21;
public static final int FORCE_EXTEND_HEADSET = 22;
public static final int FORCE_EXTEND_TYPEC = 23;
public static final int FORCE_EXTEND_USB = 24;
public static final int FORCE_EXTEND_OTHER = 25;
public static final int FORCE_EXTEND_MSDP = 26;
public static final int NUM_FORCE_CONFIG = 27;
public static final int FORCE_DEFAULT = FORCE_NONE;
mPhoneState是手机状态,常用的也就 0(一般),1(响铃),2(通话*真),3(通话*虚拟,比如微信语音通话)
mA2dpSuspended表示蓝牙A2DP是否被抑制,如果为1则需要查看下蓝牙SCO是否打开,这两不能同时启用
4、getOutputsForDevices
getOutputsForDevices, openOutputs size is 2, outputs size is 2
openOutputs size表示当前获取到的设备总数
outputs size表示正在使用的设备总数
3.3 音量相关
1、InputEvent: %d-%d
第一个参数是按键码,一般我们常看的是24(音量增加),25(音量减少)。
第二个参数是按下或松开,0是按下,1是松开。
2、adjustStreamVolume() stream=3, dir=1, flags=4113, caller=android
stream:流类型
dir:direction音量调节,-1为减,1为加,0为不变
caller:那个应用修改的,一般都是android
3、setStreamVolume stream=3; value=0.000000; output=13
该函数为设置音量的函数,如果有此打印表示音量已被改变
stream:流类型
value:音量值
output:设备描述符,13为主输出设备
4、 checkAndSetVolume volumeSource 6, index 6, device 00000080, volumeDb -34.000000, output 389
该函数只是检测音量大小的函数
volumeSource:类型同stream,但不对齐,比如volumeSource 6 = stream 3,如下
index:音量级
普通音量分为16级 0-15,0最小,15最大,蓝牙耳机不一定满足此音量级分布。
查看eventlogcat,搜索volume_changed可见到如下
volume_changed: [6,11,7,15,]
6:stream类型;11:音量设置前的音量级;7为音量设置后的音量级;15为最大音量级;最后一个为调用的包名
device:设备标识
volumeDb:经过computeVolume函数计算过的,数据类型为double,数越小音量越小,-758.000000为无声,0为最大。
output:同上
注意:checkAndSetVolume的index和volumeDb冲突时以index为准
checkAndSetVolume :
1 AUDIO_STREAM_ACCESSIBILITY
2 AUDIO_STREAM_ALARM
3 AUDIO_STREAM_BLUETOOTH_SCO
4 AUDIO_STREAM_DTMF
5 AUDIO_STREAM_ENFORCED_AUDIBLE
6 AUDIO_STREAM_MUSIC
7 AUDIO_STREAM_NOTIFICATION
8 AUDIO_STREAM_PATCH
9 AUDIO_STREAM_REROUTING
10 AUDIO_STREAM_RING
11 AUDIO_STREAM_SYSTEM
12 AUDIO_STREAM_TTS
13 AUDIO_STREAM_VOICE_CALL
5、setStreamVolumeIndexAS: stream=3 dev=80 idx=15
该函数用于调节音量级
stream:流类型
dev:设备类型
idx:音量级同index
6、setStreamVolumeIndex() stream 3, device 0x0080, index 15
执行调节音量级,有此打印表示音量级已被修改
3.4 常用的日志 关键字
- startOutput: 开始播放
- stopOutput: 停止播放
- setDeviceConnectionStateInt: 选择播放设备连接状态(state=1连接,state=0断开)
- setOutputDevices: 设置播放设备
- setStreamVolume: 设置音量
- final_volume: 实际的音量 0最小 1最大
- setRingerMode: 0静音 1震动 2正常
- setVolume: 软件设置音量
- setModeInt: 改变手机状态,也会影响到设备的选择 0一般 1响铃 2通话 3voip网络电话
- setPhoneState: 手机通话状态改变 一般是通话状态改变0->2
- setSpeakerphoneOn: 打开或关闭扬声器(免提状态),一般通话时候用
- asd_out: 外放或有线耳机调用的函数
- AudioFlinger: 播放信息
- startBluetoothSco:打开蓝牙SCO
- stopBluetoothSco:关闭蓝牙SCO
- setBluetoothSco: SCO状态,为start/stop的回调
- abandonAudioFocus:遗弃焦点
- requestAudioFocus:获得焦点
- audio focus pkg:焦点所在位置的包名
- dispatchVolumeKeyEvent:接收到按键事件
- adjustSuggestedStreamVolume:正在执行调音量的步骤
- getInputForAttr: 录音入口 一个代表一次启动
- startInput | stopInput | closeInput: 录音 参数对应PCM
- setClientActive: 录音(状态)
- computevolume
- Start_output_stream: 定义在hal层的audio_hw.h中:0是普通,1是低时延,2是高清,3是offload,4是aaudio,8是通话状态
设备,流等信息查询
/frameworks/base/media/java/android/media/Stream 流的信息:
AUDIO_STREAM_VOICE_CALL = 0, 通话音
AUDIO_STREAM_SYSTEM = 1, 系统音
AUDIO_STREAM_RING = 2, 铃声
AUDIO_STREAM_MUSIC = 3, 媒体音
AUDIO_STREAM_ALARM = 4, 闹钟
AUDIO_STREAM_NOTIFICATION = 5, 通知音
AUDIO_STREAM_BLUETOOTH_SCO = 6, 蓝牙SCO通道 (电话)
AUDIO_STREAM_ENFORCED_AUDIBLE = 7, 强制音频
AUDIO_STREAM_DTMF = 8, 按键音一类的
AUDIO_STREAM_TTS = 9, 智慧语音的语音播报 (属于9,其他只能设备也有可能)
AUDIO_STREAM_ACCESSIBILITY = 10,辅助提示音
volumeSource,与stream对应但不对齐:
AUDIO_STREAM_ACCESSIBILITY = 1 = stream 10
AUDIO_STREAM_ALARM = 2 = stream 4
AUDIO_STREAM_BLUETOOTH_SCO = 3 = stream 6
AUDIO_STREAM_DTMF= 4 = stream 8
AUDIO_STREAM_ENFORCED_AUDIBLE = 5 = stream 7
AUDIO_STREAM_MUSIC = 6 = stream 3
AUDIO_STREAM_NOTIFICATION = 7 = stream 5
AUDIO_STREAM_PATCH = 8
AUDIO_STREAM_REROUTING = 9
AUDIO_STREAM_RING = 10 = stream 2
AUDIO_STREAM_SYSTEM = 11 = stream 1AUDIO_STREAM_TTS = 12 = stream 9
AUDIO_STREAM_VOICE_CALL = 13 = stream 0
手机状态mode:
MODE_INVALID = -2;
MODE_CURRENT = -1;
MODE_NORMAL = 0; //普通状态,一般情况下使用
MODE_RINGTONE = 1; //响铃状态,来电响铃状态下使用
MODE_IN_CALL = 2; //通话状态,打电话呼叫建立时使用
MODE_IN_COMMUNICATION = 3; //communication状态,建立一个音/视频呼叫或VoIP呼叫
NUM_MODES = 4;
设备信息:
AUDIO_DEVICE_OUT_EARPIECE //0x1 听筒 AUDIO_DEVICE_OUT_SPEAKER //0x2 扬声器 AUDIO_DEVICE_OUT_WIRED_HEADSET //0x4 有线耳机HEADSET AUDIO_DEVICE_OUT_WIRED_HEADPHONE //0x8 有线耳机HEADPHONE AUDIO_DEVICE_OUT_BLUETOOTH_SCO //0x10 蓝牙 SCO AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET //0x20 蓝牙 SCO AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT //0x40 蓝牙 SCO 车机 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP //0x80 蓝牙 A2DP AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES //0x100 蓝牙 A2DP 耳机 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER //0x200 蓝牙 A2PD 扬声器
蓝牙电话会选择0x10 SCO
蓝牙听歌会选择0x80 A2DP
0x3 就是 0x1 + 0x2 (听筒加扬声器)
语音播报通道选择
1,当前有A2DP连接----使用music通道。
2,当前有SCO连接----使用Call通道。
3,除1,2外的其他场景----使用TTS通道。
// 常见设备定义(全)
enum {
AUDIO_DEVICE_NONE = 0x0u,
AUDIO_DEVICE_BIT_IN = 0x80000000u,
AUDIO_DEVICE_BIT_DEFAULT = 0x40000000u,
AUDIO_DEVICE_OUT_EARPIECE = 0x1u,
AUDIO_DEVICE_OUT_SPEAKER = 0x2u,
AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4u,
AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8u,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10u,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20u,
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40u,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80u,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100u,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200u,
AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400u,
AUDIO_DEVICE_OUT_HDMI = 0x400u, // OUT_AUX_DIGITAL
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800u,
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000u,
AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000u,
AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000u,
AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000u,
AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000u,
AUDIO_DEVICE_OUT_LINE = 0x20000u,
AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000u,
AUDIO_DEVICE_OUT_SPDIF = 0x80000u,
AUDIO_DEVICE_OUT_FM = 0x100000u,
AUDIO_DEVICE_OUT_AUX_LINE = 0x200000u,
AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000u,
AUDIO_DEVICE_OUT_IP = 0x800000u,
AUDIO_DEVICE_OUT_BUS = 0x1000000u,
AUDIO_DEVICE_OUT_PROXY = 0x2000000u,
AUDIO_DEVICE_OUT_USB_HEADSET = 0x4000000u,
AUDIO_DEVICE_OUT_HEARING_AID = 0x8000000u,
AUDIO_DEVICE_OUT_ECHO_CANCELLER = 0x10000000u,
AUDIO_DEVICE_OUT_DEFAULT = 0x40000000u, // BIT_DEFAULT
AUDIO_DEVICE_IN_COMMUNICATION = 0x80000001u, // BIT_IN | 0x1
AUDIO_DEVICE_IN_AMBIENT = 0x80000002u, // BIT_IN | 0x2
AUDIO_DEVICE_IN_BUILTIN_MIC = 0x80000004u, // BIT_IN | 0x4
AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000008u, // BIT_IN | 0x8
AUDIO_DEVICE_IN_WIRED_HEADSET = 0x80000010u, // BIT_IN | 0x10
AUDIO_DEVICE_IN_AUX_DIGITAL = 0x80000020u, // BIT_IN | 0x20
AUDIO_DEVICE_IN_HDMI = 0x80000020u, // IN_AUX_DIGITAL
AUDIO_DEVICE_IN_VOICE_CALL = 0x80000040u, // BIT_IN | 0x40
AUDIO_DEVICE_IN_TELEPHONY_RX = 0x80000040u, // IN_VOICE_CALL
AUDIO_DEVICE_IN_BACK_MIC = 0x80000080u, // BIT_IN | 0x80
AUDIO_DEVICE_IN_REMOTE_SUBMIX = 0x80000100u, // BIT_IN | 0x100
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = 0x80000200u, // BIT_IN | 0x200
AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = 0x80000400u, // BIT_IN | 0x400
AUDIO_DEVICE_IN_USB_ACCESSORY = 0x80000800u, // BIT_IN | 0x800
AUDIO_DEVICE_IN_USB_DEVICE = 0x80001000u, // BIT_IN | 0x1000
AUDIO_DEVICE_IN_FM_TUNER = 0x80002000u, // BIT_IN | 0x2000
AUDIO_DEVICE_IN_TV_TUNER = 0x80004000u, // BIT_IN | 0x4000
AUDIO_DEVICE_IN_LINE = 0x80008000u, // BIT_IN | 0x8000
AUDIO_DEVICE_IN_SPDIF = 0x80010000u, // BIT_IN | 0x10000
AUDIO_DEVICE_IN_BLUETOOTH_A2DP = 0x80020000u, // BIT_IN | 0x20000
AUDIO_DEVICE_IN_LOOPBACK = 0x80040000u, // BIT_IN | 0x40000
AUDIO_DEVICE_IN_IP = 0x80080000u, // BIT_IN | 0x80000
AUDIO_DEVICE_IN_BUS = 0x80100000u, // BIT_IN | 0x100000
AUDIO_DEVICE_IN_PROXY = 0x81000000u, // BIT_IN | 0x1000000
AUDIO_DEVICE_IN_USB_HEADSET = 0x82000000u, // BIT_IN | 0x2000000
AUDIO_DEVICE_IN_BLUETOOTH_BLE = 0x84000000u, // BIT_IN | 0x4000000
AUDIO_DEVICE_IN_DEFAULT = 0xC0000000u, // BIT_IN | BIT_DEFAULT
};
AudioManager(音频管理器)
1. adjustVolume(int direction, int flags)
作用:控制手机音量,调大或者调小一个单位,根据第一个参数进行判断 。
(int streamType, int direction, int flags):
作用:同上,不过可以选择调节的声音类型
(int streamType, int index, intflags)
作用:直接设置音量大小。
( )
作用:返回当前的音频模式。
5. 方法:setMode( )
作用:设置声音模式。
返回值:有下述几种模式:
MODE_NORMAL(普通), MODE_RINGTONE(铃声)
MODE_IN_CALL(打电话),MODE_IN_COMMUNICATION(通话)
6. getRingerMode( )
作用:返回当前的铃声模式。
7.方法:setRingerMode(int streamType)
作用:设置铃声模式 。
返回值:有下述几种模式:
如RINGER_MODE_NORMAL(普通)
RINGER_MODE_SILENT(静音)
RINGER_MODE_VIBRATE(震动)
(int streamType)
作用:获得手机的当前音量,最大值为7,最小值为0,当设置为0的时候,会自动调整为震动模式。
9. getStreamMaxVolume(int streamType)
作用:获得手机某个声音类型的最大音量值。
(int streamType,boolean state)
作用:将手机某个声音类型设置为静音。
11. setSpeakerphoneOn(boolean on)
作用:设置是否打开扩音器。
12. setMicrophoneMute(boolean on)作用:设置是否让麦克风静音。
13. isMicrophoneMute()作用:判断麦克风是否静音或是否打开。
14. isMusicActive()作用:判断是否有音乐处于活跃状态。
15. isWiredHeadsetOn()作用:判断是否插入了耳机。
16. abandonAudioFocus()作用:放弃音频的焦点。
17. adjustSuggestedStreamVolume(int,int suggestedStreamType intflags)作用:调整最相关的流的音量,或者给定的回退流。
18. getParameters(String keys)作用:给音频硬件设置一个varaible数量的参数值。
19. getVibrateSetting(int vibrateType)作用:返回是否该用户的振动设置为振动类型。
20. isBluetoothA2dpOn()作用:检查是否A2DP蓝牙耳机音频路由是打开或关闭。
21. isBluetoothScoAvailableOffCall()作用:显示当前平台是否支持使用SCO的关闭调用用例。
22. isBluetoothScoOn()作用:检查通信是否使用蓝牙SCO。
23. loadSoundEffects()作用:加载声音效果。
24. playSoundEffect((int effectType, float volume)作用:播放声音效果。
25. egisterMediaButtonEventReceiver(ComponentName eventReceiver)作用:注册一个组件MEDIA_BUTTON意图的唯一接收机。
26. requestAudioFocus( l,int streamType,int durationHint)作用:请求音频的焦点。
27. setBluetoothScoOn(boolean on)作用:要求使用蓝牙SCO耳机进行通讯。
28. startBluetoothSco/stopBluetoothSco()作用:启动/停止蓝牙SCO音频连接。
29. unloadSoundEffects()作用:卸载音效。
4. CallAudioState \ CallAudioManager
CallAudioState
用来封装通话过程中的音频播放状态
属性
public static final int ROUTE_EARPIECE = 0x00000001;//听筒 public static final int ROUTE_BLUETOOTH = 0x00000002;//蓝牙 public static final int ROUTE_WIRED_HEADSET = 0x00000004;//有线耳机 public static final int ROUTE_SPEAKER = 0x00000008;//扬声器 public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;//听筒或者耳机 public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET | ROUTE_SPEAKER;//全部状态
重要方法:
//是否静音 public boolean isMuted() { return isMuted; } //返回音频状态 public int getRoute() { return route; }
CallAudioManager
CallAudioManager可以类比于AudioManager,负责通话过程中音频播放状态的逻辑;
CallAudioManager是在CallsManager被初始化的;
CallsManager(......){ mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine, this,new CallAudioModeStateMachine((AudioManager) (Context.AUDIO_SERVICE)), playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer); }
CallAudioRouteStateMachine
它是处理通话过程中的音频模式的,如语音模式,通话模式等
//音频状态 private final BaseState mUnfocusedState = new UnfocusedState();//待机 private final BaseState mRingingFocusState = new RingingFocusState();//响铃 private final BaseState mSimCallFocusState = new SimCallFocusState();//Call private final BaseState mVoipCallFocusState = new VoipCallFocusState();//COMMUNICATION private final BaseState mOtherFocusState = new OtherFocusState(); private final AudioManager mAudioManager; private CallAudioManager mCallAudioManager; private int mMostRecentMode; private boolean mIsInitialized = false; public CallAudioModeStateMachine(AudioManager audioManager) { super(()); mAudioManager = audioManager; mMostRecentMode = AudioManager.MODE_NORMAL; //将这些状态添加到mStateInfo中 addState(mUnfocusedState); addState(mRingingFocusState); addState(mSimCallFocusState); addState(mVoipCallFocusState); addState(mOtherFocusState); //待机状态是默认状态 setInitialState(mUnfocusedState); //完成CallAudioModeStateMachine的构造 start(); sendMessage(INITIALIZE, new MessageArgs()); }
5. 音频流类型获取音频的路由策略
routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
{
// stream to strategy mapping
switch (stream) {
case AUDIO_STREAM_VOICE_CALL:
case AUDIO_STREAM_BLUETOOTH_SCO:
return STRATEGY_PHONE;
case AUDIO_STREAM_RING:
case AUDIO_STREAM_ALARM:
return STRATEGY_SONIFICATION;
case AUDIO_STREAM_NOTIFICATION:
return STRATEGY_SONIFICATION_RESPECTFUL;
case AUDIO_STREAM_DTMF:
return STRATEGY_DTMF;
default:
ALOGE("unknown stream type %d", stream);
case AUDIO_STREAM_SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
case AUDIO_STREAM_MUSIC:
return STRATEGY_MEDIA;
case AUDIO_STREAM_ENFORCED_AUDIBLE:
return STRATEGY_ENFORCED_AUDIBLE;
case AUDIO_STREAM_TTS:
return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
case AUDIO_STREAM_ACCESSIBILITY:
return STRATEGY_ACCESSIBILITY;
case AUDIO_STREAM_REROUTING:
return STRATEGY_REROUTING;
}
}
//音频策略枚举
enum routing_strategy {
STRATEGY_MEDIA, // 媒体策略
STRATEGY_PHONE, // 电话策略
STRATEGY_SONIFICATION, // 通知策略
STRATEGY_SONIFICATION_RESPECTFUL,
STRATEGY_DTMF, // DTMF 策略
STRATEGY_ENFORCED_AUDIBLE, // 强制输出策略
STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
STRATEGY_REROUTING,
NUM_STRATEGIES
};
6. 通过streamType得到audio_io_handle
根据streamType找到合适的设备对应的 audio_io_handle的过程, audioPolicyService -> APM->Engine(具体的策略[配置文件]) 找到合适的设备
大概过程是:
- streamType -(getAttributesForStreamType) -> attributes (streamType对应的多个attributes)
- getOutputDevicesForAttributes-> DeviceVector (attributes 找到对应的devices)
- getOutputsForDevices -> SortedVector<audio_io_handle_t> (多个devicess对应多个handles)
- selectOutput(audio_io_handles, output_flag, audio_format, channel_flag, samplintRate) -> audio_io_handle (从多handle中根据out flag, format, channel, SR,得到最合适的audio_io_handle)
audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return 0;
return aps->getOutput(stream);
}
6.1 APM(AudioPolicyManager)
frameworks/av/services/audiopolicy/managerdefault/
audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
{
DeviceVector devices = mEngine->getOutputDevicesForStream(stream, false /*fromCache*/);
// Note that related method getOutputForAttr() uses getOutputForDevice() not selectOutput().
// We use selectOutput() here since we don't have the desired AudioTrack sample rate,
// format, flags, etc. This may result in some discrepancy for functions that utilize
// getOutput() solely on audio_stream_type such as AudioSystem::getOutputFrameCount()
// and AudioSystem::getOutputSamplingRate().
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
audio_io_handle_t output;
if (stream == AUDIO_STREAM_MUSIC &&
property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
// use DEEP_BUFFER as default output for music stream type
output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_DEEP_BUFFER, AUDIO_FORMAT_INVALID);
}
else{
output = selectOutput(outputs);
}
ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
().c_str(), output);
return output;
}
6.2 Engine: getOutputDevicesForStream
frameworks/av/services/audiopolicy/enginedefault/src/
//通过stream_type得到attribute, 由attribute得到Device
DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
{
auto attributes = getAttributesForStreamType(stream);
return getOutputDevicesForAttributes(attributes, nullptr, fromCache);
}
6.2.1 getAttributesForStreamType
frameworks/av/services/audiopolicy/engine/common/src/
audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const /*one stream type 得到多个属性*/
{
const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
[&streamType](const auto &supportedAttr) {
return == streamType; });
return iter != end(mAttributesVector) ? iter->mAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
}
// mAttributesVector 怎么生成的?
frameworks/av/services/audiopolicy/engine/common/src/
engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{
auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
for (const auto &attr : ) {
strategy->addAttributes({, volumeGroup->getId(), attr});
volumeGroup->addSupportedAttributes(attr);
}
};
}
audio_policy_engine_product_strategies.xml
<ProductStrategy name="STRATEGY_MEDIA">
<AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
<Attributes>
<ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
<Usage value="AUDIO_USAGE_ASSISTANT"/>
</Attributes>
</AttributesGroup>
<AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music"> // 解析这个配置文件里,一个streamType得到过得attributes
<Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
<Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
<Attributes></Attributes>
</AttributesGroup>
<AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
<Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
6.2.2 getOutputDevicesForAttributes
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
const sp<DeviceDescriptor> &preferredDevice,
bool fromCache) const
{
// First check for explict routing device
if (preferredDevice != nullptr) {
ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
return DeviceVector(preferredDevice);
} // 由 attribute -> product_strategy
product_strategy_t strategy = getProductStrategyForAttributes(attributes);
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
//
// @TODO: what is the priority of explicit routing? Shall it be considered first as it used to
// be by APM?
//
// Honor explicit routing requests only if all active clients have a preferred route in which
// case the last active client route is used
sp<DeviceDescriptor> device = findPreferredDevice(outputs, strategy, availableOutputDevices); // 输出设备,可用的输出设备和策略通过这些参数得到Preferred
if (device != nullptr) {
return DeviceVector(device);
}
return fromCache? (strategy) : getDevicesForProductStrategy(strategy);
}
6.2.3 getOutputsForDevices(devices, mOutputs);
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
const DeviceVector &devices,
const SwAudioOutputCollection& openOutputs)
{
SortedVector<audio_io_handle_t> outputs;
ALOGVV("%s() devices %s", __func__, ().c_str());
for (size_t i = 0; i < (); i++) {
ALOGVV("output %zu isDuplicated=%d device=%s",
i, (i)->isDuplicated(),
(i)->supportedDevices().toString().c_str());
if ((i)->supportsAllDevices(devices)
&& (i)->devicesSupportEncodedFormats(())) {
ALOGVV("%s() found output %d", __func__, (i));
((i));
}
}
return outputs;
}
6.2.4 selectOutput
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
audio_format_t format = AUDIO_FORMAT_INVALID,
audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE,
uint32_t samplingRate = 0);
audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags,
audio_format_t format,
audio_channel_mask_t channelMask,
uint32_t samplingRate)
{
audio_io_handle_t primary_output = 0;
bool isCts = getAppMaskByName(callingAppName) & APP_TYPE_CTS_AUDIOPRO ? true : false;
LOG_ALWAYS_FATAL_IF(!(format == AUDIO_FORMAT_INVALID || audio_is_linear_pcm(format)),
"%s called with format %#x", __func__, format);
// Flags disqualifying an output: the match must happen before calling selectOutput()
static const audio_output_flags_t kExcludedFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
// Flags expressing a functional request: must be honored in priority over
// other criteria
static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM | AUDIO_OUTPUT_FLAG_VIRTUAL_DEEP_BUFFER);
// Flags expressing a performance request: have lower priority than serving
// requested sampling rate or channel mask
static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER |
AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_SYNC);
const audio_output_flags_t functionalFlags =
(audio_output_flags_t)(flags & kFunctionalFlags);
const audio_output_flags_t performanceFlags =
(audio_output_flags_t)(flags & kPerformanceFlags);
audio_io_handle_t bestOutput = (() == 0) ? AUDIO_IO_HANDLE_NONE : outputs[0];
// select one output among several that provide a path to a particular device or set of
// devices (the list was previously build by getOutputsForDevices()).
// The priority is as follows:
// 1: the output supporting haptic playback when requesting haptic playback
// 2: the output with the highest number of requested functional flags
// 3: the output supporting the exact channel mask
// 4: the output with a higher channel count than requested
// 5: the output with a higher sampling rate than requested
// 6: the output with the highest number of requested performance flags
// 7: the output with the bit depth the closest to the requested one
// 8: the primary output
// 9: the first output in the list
// matching criteria values in priority order for best matching output so far
std::vector<uint32_t> bestMatchCriteria(8, 0);
const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
for (audio_io_handle_t output : outputs) {
sp<SwAudioOutputDescriptor> outputDesc = (output);
// matching criteria values in priority order for current output
std::vector<uint32_t> currentMatchCriteria(8, 0);
if (outputDesc->isDuplicated()) {
continue;
}
if ((kExcludedFlags & outputDesc->mFlags) != 0) {
continue;
}
// If haptic channel is specified, use the haptic output if present.
// When using haptic output, same audio format and sample rate are required.
const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
continue;
}
if (outputHapticChannelCount >= hapticChannelCount
&& format == outputDesc->getFormat()
&& samplingRate == outputDesc->getSamplingRate()) {
currentMatchCriteria[0] = outputHapticChannelCount;
}
// functional flags match
currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
// channel mask and channel count match
uint32_t outputChannelCount = audio_channel_count_from_out_mask(
outputDesc->getChannelMask());
if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
channelCount <= outputChannelCount) {
if ((audio_channel_mask_get_representation(channelMask) ==
audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
((channelMask & outputDesc->getChannelMask()) == channelMask)) {
currentMatchCriteria[2] = outputChannelCount;
}
currentMatchCriteria[3] = outputChannelCount;
}
// sampling rate match
if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
samplingRate <= outputDesc->getSamplingRate()) {
currentMatchCriteria[4] = outputDesc->getSamplingRate();
}
// performance flags match
currentMatchCriteria[5] = popcount(outputDesc->mFlags & performanceFlags);
// format match
if (format != AUDIO_FORMAT_INVALID) {
currentMatchCriteria[6] =
PolicyAudioPort::kFormatDistanceMax -
PolicyAudioPort::formatDistance(format, outputDesc->getFormat());
}
// primary output match
currentMatchCriteria[7] = outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY;
if (currentMatchCriteria[7])
primary_output = output;
// compare match criteria by priority then value
if (std::lexicographical_compare((), (),
(), ())) {
bestMatchCriteria = currentMatchCriteria;
bestOutput = output;
std::stringstream result;
std::copy((), (),
std::ostream_iterator<int>(result, " "));
ALOGV("%s new bestOutput %d criteria %s",
__func__, bestOutput, ().c_str());
}
}
{
//only cts use ull, the others use primary output
//if do not have ull profile(audio_policy_configuration.xml), cannot create ull desc.
//so it must create ull output first
sp<SwAudioOutputDescriptor> outputDescPrimary = (bestOutput);
if (outputDescPrimary != nullptr && (outputDescPrimary->mFlags == (AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_RAW))
&& !isCts && primary_output != 0) {
bestOutput = primary_output;
}
}
return bestOutput;
}