Android Framework 音频子系统(02)音频系统框架

该系列文章总纲链接:专题分纲目录 Android Framework 音频子系统​​​​​​​


本章关键点总结 & 说明:

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


1 Android 音频系统框架简介

音频系统的 整个框架图如下所示:

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

  1. AudioFlinger:接收多个APP的数据,合并下发;是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完 成。
  2. AudioPolicyService:决定选择哪个设备输出,接上耳机用耳机,接上蓝牙设备用蓝牙;是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。
  3. AudioTrack:一个代理,APP 通过AudioTrack(binder通信,分Java层和C++层) 来访问AudioFlinger。

接下来从AndioTrack、AudioFlinger、AudioHAL的视角更详细的解读Audio的框架

从该图中我们要了解以下几个基本知识:

  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.conf来描述

@4 profile:配置,用来描述output,本可以支持哪些设备(仅逻辑上支持,不一定有实际硬件,比如耳机 output是插上耳机久支持,不插耳机就不支持,但profile一直支持)。

@5 out flag : 比如对于某个专业APP, 它只从HDMI播放声音, 这时就可以指定out flag为AUDIO_OUTPUT_FLAG_DIRECT,这会导致最终的声音无需混音即直接输出到对应的device。

@6 stream type:app要播放声音, 要指定声音类型,这些声音的类型被称为stream type。它的值在C++层(AudioTrack.cpp)实现如下:

typedef enum {
    /* These values must kept in sync with
     * frameworks/base/media/java/android/media/AudioSystem.java
     */
    AUDIO_STREAM_DEFAULT          = -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, /* Sounds that cannot be muted by user
                                        * and must be routed to speaker
                                        */
    AUDIO_STREAM_DTMF             = 8,//DTMF 键盘拨号音
    AUDIO_STREAM_TTS              = 9,  /* Transmitted Through Speaker.
                                         * Plays over speaker only, silent on other devices.
                                         */
    AUDIO_STREAM_ACCESSIBILITY    = 10, /* For accessibility talk back prompts */
    AUDIO_STREAM_REROUTING        = 11, /* For dynamic policy output mixes */
    AUDIO_STREAM_PATCH            = 12, /* For internal audio flinger tracks. Fixed volume */
    AUDIO_STREAM_PUBLIC_CNT       = AUDIO_STREAM_TTS + 1,
    AUDIO_STREAM_CNT              = AUDIO_STREAM_PATCH + 1,
} audio_stream_type_t;

它的值在Java(AudioTrack.java)层实现如下:

public class 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.
     */
    /* The default audio stream */
    public static final int STREAM_DEFAULT = -1;
    /* The audio stream for phone calls */
    public static final int STREAM_VOICE_CALL = 0;//电话语音
    /* The audio stream for system sounds */
    public static final int STREAM_SYSTEM = 1;//系统声音
    /* The audio stream for the phone ring and message alerts */
    public static final int STREAM_RING = 2;//铃声声音
    /* The audio stream for music playback */
    public static final int STREAM_MUSIC = 3;//音乐声音
    /* The audio stream for alarms */
    public static final int STREAM_ALARM = 4;//警告音
    /* The audio stream for notifications */
    public static final int STREAM_NOTIFICATION = 5;//通知音
    /* @hide The audio stream for phone calls when connected on bluetooth */
    public static final int STREAM_BLUETOOTH_SCO = 6;
    /* @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
    public static final int STREAM_SYSTEM_ENFORCED = 7;
    /* @hide The audio stream for DTMF tones */
    public static final int STREAM_DTMF = 8;//DTMF键盘拨号音
    /* @hide The audio stream for text to speech (TTS) */
    public static final int STREAM_TTS = 9;
    /**
     * @deprecated Use {@link #numStreamTypes() instead}
     */
    public static final int NUM_STREAMS = 5;
	//...
}

@7 strategy:stream type 的类型有很多, 看它属于哪一类(策略)用strategy。同时也要根据strategy确定要用什么设备播放,是 喇叭、耳机还是蓝牙。根据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++部分)

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)

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)

应用程序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)
发布了289 篇原创文章 · 获赞 47 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/105265359