Android 音频子系统--02:音频系统框架

1,407 阅读6分钟

本文转载自:Android Framework 音频子系统(02)音频系统框架

1.概述

本章节主要关注以上思维导图即可。主要是对音频系统框架 有一个基本的认识。

2.Android 音频框架简介

  Android音频系统有两大服务:一是AudioFlinger,二是AudioPolicyService。AudioFlinger负责向下访问AudioHardwareInterface,实现音频PCM数据的混音/输入/输出,实现音量调节;AudioPolicyService负责音频输入输出设备的连接状态,音频策略调度即音频设备(如本地CODEC、Bluetooth A2DP、Headset)的切换策略(注意它只是负责策略,真正的切换操作是在AudioFlinger中的openOutput,毕竟 AudioFlinger负责操作底层音频硬件)。

2.1 音频系统整体框架

image.png

针对这张框架图。对几个关键的音频类进行说明:

  • 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)