1.概述
本章节主要关注以上思维导图即可。主要是对音频系统框架 有一个基本的认识。
2.Android 音频框架简介
Android音频系统有两大服务:一是AudioFlinger,二是AudioPolicyService。AudioFlinger负责向下访问AudioHardwareInterface,实现音频PCM数据的混音/输入/输出,实现音量调节;AudioPolicyService负责音频输入输出设备的连接状态,音频策略调度即音频设备(如本地CODEC、Bluetooth A2DP、Headset)的切换策略(注意它只是负责策略,真正的切换操作是在AudioFlinger中的openOutput,毕竟 AudioFlinger负责操作底层音频硬件)。
2.1 音频系统整体框架
针对这张框架图。对几个关键的音频类进行说明:
- AudioFlinger:接收多个APP的数据,合并下发;是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完成。
- AudioPolicyService:决定选择哪个设备输出,接上耳机用耳机,接上蓝牙设备用蓝牙;是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。
- AudioTrack:一个代理,APP通过AudioTrack(binder通信,分Java层和C++层) 来访问AudioFlinger。
1.2 AndioTrack、AudioFlinger、AudioHAL视角
从该图中我们要了解以下几个基本知识:
(1)一个声卡对应多个device;(device是指:喇叭、麦克风耳机等)
(2)多个device对应一个设备节点;
(3)多个设备节点(比如:/dev/snd/pcmc0d0p这种节点)对应一个output,output是多个device的组合;这些device属于同一个硬件上的不同端口;这些device支持同样的参数、采样率、通道;
(4)一个output对应一个线程thread;
(5)一个thread中有多个track;播放声音时,声音来源有多个;
(6)一个track对应多个AudioTrack。
2.Audio框架系统基本概念
(1)device
比如声卡上的喇叭、耳机还是蓝牙等等,这些称之为device。输出设备device在Java层 AudioSystem定义如下:
public class AudioSystem
{
//...
public static final int DEVICE_OUT_EARPIECE = 0x1; //听筒
public static final int DEVICE_OUT_SPEAKER = 0x2; //扬声器
public static final int DEVICE_OUT_WIRED_HEADSET = 0x4; //带话筒耳机
public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8; //不带话筒耳机
public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10; //蓝牙,面向 SCO方式,主要用于话音传输
public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20; //蓝牙耳机,带话筒
public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40; //蓝牙车载设备
public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80; //蓝牙立体声
public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100; //蓝牙立体声耳机
public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200; //蓝牙话筒
public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; //HDMI相关
//...
}
(2)output
为了便于管理,把一个设备上具有相同参数的一组device称为output。它描述一些实际支持的设备(有实际硬件)。
(3)module
Android系统里使用hardware module来访问硬件(声卡),module就是一个硬件操作库,一个module能支持哪些output,一个output能支持哪些device,使用配置文件/system/etc/audio_policy_configuration.xml来描述。
(4)profile
配置,用来描述output,本可以支持哪些设备(仅逻辑上支持,不一定有实际硬件,比如耳机 output是插上耳机就支持,不插耳机就不支持,但profile一直支持)。
(5)out flag
比如对于某个专业APP,它只从HDMI播放声音,这时就可以指定out flag为AUDIO_OUTPUT_FLAG_DIRECT,这会导致最终的声音无需混音即直接输出到对应的device。
(6)stream type
app要播放声音,需要指定声音类型,这些声音的类型被称为stream type。它的值在Java(AudioTrack.java)层实现如下:
- AudioSystem.java
public class AudioSystem
{
private static final boolean DEBUG_VOLUME = false;
private static final String TAG = "AudioSystem";
/* These values must be kept in sync with system/audio.h */
/*
* If these are modified, please also update Settings.System.VOLUME_SETTINGS
* and attrs.xml and AudioManager.java.
*/
/** Used to identify the default audio stream volume */
public static final int STREAM_DEFAULT = -1;
/** Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = 0;//电话声音
/** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = 1;//系统声音
/** Used to identify the volume of audio streams for the phone ring and message alerts */
public static final int STREAM_RING = 2;//铃声
/** Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = 3;//音乐声音
/** Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = 4;//警告音
/** Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = 5;//通知声音
/** Used to identify the volume of audio streams for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;//蓝牙电话声音
/** Used to identify the volume of audio streams for enforced system sounds in certain
* countries (e.g camera in Japan) */
@UnsupportedAppUsage
public static final int STREAM_SYSTEM_ENFORCED = 7;//一种强制声音(比如:日本的照相机声音)
/** Used to identify the volume of audio streams for DTMF tones */
public static final int STREAM_DTMF = 8;//DTMF键盘拨号音
/** Used to identify the volume of audio streams exclusively transmitted through the
* speaker (TTS) of the device */
public static final int STREAM_TTS = 9;//语音声音
/** Used to identify the volume of audio streams for accessibility prompts */
public static final int STREAM_ACCESSIBILITY = 10;
/**
* @deprecated Use {@link #numStreamTypes() instead}
*/
public static final int NUM_STREAMS = 5;
它的值在C++层(AudioTrack.cpp)实现如下:
- audio-base.h
typedef enum {
AUDIO_STREAM_DEFAULT = -1, // (-1)
AUDIO_STREAM_MIN = 0,
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,
AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
AUDIO_STREAM_DTMF = 8,
AUDIO_STREAM_TTS = 9,
AUDIO_STREAM_ACCESSIBILITY = 10,
#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
/** For dynamic policy output mixes. Only used by the audio policy */
AUDIO_STREAM_REROUTING = 11,
/** For audio flinger tracks volume. Only used by the audioflinger */
AUDIO_STREAM_PATCH = 12,
#endif // AUDIO_NO_SYSTEM_DECLARATIONS
} audio_stream_type_t;
(7)strategy
stream type 的类型有很多,看它属于哪一类(策略)用strategy。同时也要根据strategy确定要用什么设备(device)播放,是喇叭、耳机还是蓝牙。根据device设置output。strategy的获取方法实现如下:
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;
case AudioSystem::RING:
case AudioSystem::ALARM:
return STRATEGY_SONIFICATION;
case AudioSystem::NOTIFICATION:
return STRATEGY_SONIFICATION_RESPECTFUL;
case AudioSystem::DTMF:
return STRATEGY_DTMF;
default:
ALOGE("unknown stream type");
case AudioSystem::SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
case AudioSystem::TTS:
case AudioSystem::MUSIC:
return STRATEGY_MEDIA;
case AudioSystem::ENFORCED_AUDIBLE:
return STRATEGY_ENFORCED_AUDIBLE;
}
}
(8)policy
一个stream如何最终选择到一个device,这些stream如何互相影响(一个高优先级的声音会使得其他声音静音),等等等,统称为policy (策略)。
(9)音频输出设备中的几个常见术语
- headset:表示既有听筒又有Mic;
- headPhone:表示只有听筒,没有Mic;
- lineOut: 就是输出模拟信号到音箱设备。
3.涉及到的文件简述
上图的代码主要分为3个部分,AudioFlinger、AudioPolicyService、应用部分(Java部分 & C++部分)。
(1)AudioFlinger部分相关文件以及目录位置如下:
-
AudioFlinger.cpp: (frameworks/av/services/audioflinger/AudioFlinger.cpp)
-
Threads.cpp: (frameworks/av/services/audioflinger/Threads.cpp)
-
Tracks.cpp: (frameworks/av/services/audioflinger/Tracks.cpp)
-
audio_hw_hal.cpp: (hardware/libhardware_legacy/audio/Audio_hw_hal.cpp)
-
AudioHardware.cpp: (device/friendly-arm/common/libaudio/AudioHardware.cpp)
(2)AudioPolicyService部分相关文件以及目录位置 如下:
-
AudioPolicyService.cpp: (frameworks/av/services/audiopolicy/AudioPolicyService.cpp)
-
AudioPolicyClientImpl.cpp: (frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp)
-
AudioPolicyInterfaceImpl.cpp: (frameworks/av/services/audiopolicy/AudioPolicyInterfaceImpl.cpp)
-
AudioPolicyManager.cpp: (frameworks/av/services/audiopolicy/AudioPolicyManager.cpp)
(3)应用程序APP相关文件以及目录位置如下:
- AudioTrack.java: (frameworks/base/media/java/android/media/AudioTrack.java)
- android_media_AudioTrack.cpp: (frameworks/base/core/jni/android_media_AudioTrack.cpp)
- AudioTrack.cpp: (frameworks/av/media/libmedia/AudioTrack.cpp)
- AudioSystem.cpp: (frameworks/av/media/libmedia/AudioSystem.cpp)