IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【初学音频】Android的Audio系统之AudioFlinger -> 正文阅读

[移动开发]【初学音频】Android的Audio系统之AudioFlinger

前言

AudioPolicyService 与 AudioFlinger 是 Android 音频系统的两大基本服务。前者是音频系统策略的制定者,负责音频设备切换的策略抉择、音量调节策略等;后者是音频系统策略的执行者,负责音频流设备的管理及音频流数据的处理传输,所以 AudioFlinger 也被认为是 Android 音频系统的引擎。

AudioFlinger 服务启动

从 Android 7.0 开始,AudioFlinger 在系统启动时由 audioserver 加载(之前版本由 mediaserver 加载),详见 frameworks/av/media/audioserver/main_audioserver.cpp:

int main(int argc, char** argv)
{
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager>sm = defaultServiceManager();
    ALOGI("ServiceManager:%p",sm.get());
    AudioFlinger::instantiate();
    AudioPolicyService::instantiate();
    RadioService::instantiate();
    SoundTriggerHwService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

可见 audioserver 把音频相关的服务都加载了,包括 AudioFlinger、AudioPolicyService、RadioService、SoundTriggerHwService。

AudioFlinger 服务启动后,其他进程可以通过 ServiceManager 来获取其代理对象 IAudioFlinger,通过 IAudioFlinger 可以向 AudioFlinger 发出各种服务请求,从而完成自己的音频业务。

AudioFlinger 服务接口

[-->AudioHardwareInterface.h::AudioHardwareInterface声明]

class AudioHardwareInterface
{
public:
    virtual ~AudioHardwareInterface() {}

    //用于检查硬件是否初始化成功,返回的错误码定义在include/utils/Errors.h
    virtual status_t    initCheck() =0;

    //设置通话音量,范围从0到1.0
    virtual status_t   setVoiceVolume(float volume) = 0;

    /*
       设置除通话音量外的其他所有音频流类型的音量,范围从0到1.0,如果硬件不支持的话,
       这个功能会由软件层的混音器完成
    */
    virtual status_t   setMasterVolume(float volume) = 0;

    /*
       设置模式,NORMAL的状态为普通模式,RINGTONE表示来电模式(这时听到的声音是来电铃声)
       IN_CALL表示通话模式(这时听到的声音是手机通话过程中的语音)
    */
    virtual status_t    setMode(intmode) = 0; 

    // 和麦克相关
    virtual status_t   setMicMute(bool state) = 0;
    virtual status_t   getMicMute(bool* state) = 0;

    // 设置/获取配置参数,采用key/value的组织方式
    virtual status_t   setParameters(const String8& keyValuePairs) = 0;
    virtual String8    getParameters(const String8& keys) = 0;

    // 根据传入的参数得到输入缓冲的大小,返回0表示其中某个参数的值Audio HAL不支持
    virtualsize_t    getInputBufferSize(uint32_tsampleRate, int format, int channelCount) = 0;

                            /*下面这几个函数非常重要 */
    /*
       openOutputStream:创建音频输出流对象(相当于打开音频输出设备)
       AF可以往其中write数据,指针型参数将返回该音频输出流支持的类型、声道数、采样率等
    */
    virtual AudioStreamOut* openOutputStream(
                                uint32_tdevices,
                                int *format=0,
                                uint32_t*channels=0,
                                uint32_t*sampleRate=0,
                                status_t*status=0) = 0;
    // 关闭音频输出流
    virtual    void       closeOutputStream(AudioStreamOut* out) = 0;

    // 创建音频输入流对象(相当于打开音频输入设备),AF可以read数据
    virtual AudioStreamIn* openInputStream(
                                uint32_tdevices,
                                int *format,
                                uint32_t*channels,
                                uint32_t *sampleRate,
                                status_t*status,
                               AudioSystem::audio_in_acoustics acoustics) = 0;
 
    virtual    void        closeInputStream(AudioStreamIn* in) =0;
    //关闭音频输入流
    virtual status_t dumpState(int fd, const Vector<String16>&args) = 0;
    //静态create函数,使用设计模式中的工厂模式,具体返回的对象由厂商根据硬件的情况决定
    staticAudioHardwareInterface* create();
    ......
};

根据上面的代码,可以得出以下结论:

  • AudioHardwareInterface管理音频输出设备对象(AudioStreamOut)和音频输入设备对象(AudioStreamIn)的创建。
  • 通过AudioHardwareInterface可设置音频系统的一些参数。

AudioFlinger 对外提供的主要的服务接口如下:

InterfaceDescription
sampleRate获取硬件设备的采样率
format获取硬件设备的音频格式
frameCount获取硬件设备的周期帧数
latency获取硬件设备的传输延迟
setMasterVolume调节主输出设备的音量
setMasterMute静音主输出设备
setStreamVolume调节指定类型的音频流的音量,这种调节不影响其他类型的音频流的音量
setStreamMute静音指定类型的音频流
setVoiceVolume调节通话音量
setMicMute静音麦克风输入
setMode切换音频模式:音频模式有 4 种,分别是 Normal、Ringtone、Call、Communicatoin
setParameters设置音频参数:往下调用 HAL 层相应接口,常用于切换音频通道
getParameters获取音频参数:往下调用 HAL 层相应接口
openOutput打开输出流:打开输出流设备,并创建 PlaybackThread 对象
closeOutput关闭输出流:移除并销毁 PlaybackThread 上面挂着的所有的 Track,退出 PlaybackThread,关闭输出流设备
openInput打开输入流:打开输入流设备,并创建 RecordThread 对象
closeInput关闭输入流:退出 RecordThread,关闭输入流设备
createTrack新建输出流管理对象: 找到对应的 PlaybackThread,创建输出流管理对象 Track,然后创建并返回该 Track 的代理对象 TrackHandle
openRecord新建输入流管理对象:找到 RecordThread,创建输入流管理对象 RecordTrack,然后创建并返回该 RecordTrack 的代理对象 RecordHandle

可以归纳出 AudioFlinger 响应的服务请求主要有:

  1. 获取硬件设备的配置信息
  2. 音量调节
  3. 静音操作
  4. 音频模式切换
  5. 音频参数设置
  6. 输入输出流设备管理
  7. 音频流管理

其中,openOutput() 和 createTrack() 这两个接口涉及最多。

AudioFlinger 回放录制线程

AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,我们简单看看回放线程和录制线程类关系:

  • ThreadBase:PlaybackThread 和 RecordThread 的基类;
  • RecordThread:录制线程类,由 ThreadBase 派生;
  • PlaybackThread:回放线程基类,同由 ThreadBase 派生;
  • MixerThread:混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 可以把多个音轨的数据混音后再输出;
  • DirectOutputThread:直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可;
  • DuplicatingThread:复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其他输出设备,使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出;
  • OffloadThread:硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(一般是 MP3、AAC 等格式的数据),需要输出到硬件解码器,由硬件解码器解码成 PCM 数据。

从 Audio HAL 中,我们通常看到如下 4 种输出流设备,分别对应着不同的播放场景:

  • primary_out:主输出流设备,用于铃声类声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_PRIMARY 的音频流和一个 MixerThread 回放线程实例;
  • low_latency:低延迟输出流设备,用于按键音、游戏背景音等对时延要求高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_FAST 的音频流和一个 MixerThread 回放线程实例;
  • deep_buffer:音乐音轨输出流设备,用于音乐等对时延要求不高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流和一个 MixerThread 回放线程实例;
  • compress_offload:硬解输出流设备,用于需要硬件解码的数据输出,对应着标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流和一个 OffloadThread 回放线程实例。

下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:

?

AT和AF交互的流程

  • AT调用createTrack,得到一个IAudioTrack对象。
  • AT调用IAudioTrack对象的start,表示准备写数据了。
  • AT通过write写数据,这个过程和audio_track_cblk_t有着密切关系。
  • 最后AT调用IAudioTrack的stop或delete IAudioTrack结束工作。

AudioTrack 构造过程

当我们构造一个 AudioTrack 实例时(以 MODE_STREAM/TRANSFER_SYNC 模式为例,这也是最常用的模式了,此时 sharedBuffer 为空),系统都发生了什么事?阐述下大致流程:

1. 如果 cbf(audioCallback 回调函数)非空,那么创建 AudioTrackThread 线程处理 audioCallback 回调函数(MODE_STREAM 模式时,cbf 为空);

2. 根据 streamType(流类型)、flags(输出标识)等参数调用 AudioSystem::getOutputForAttr();经过一系列的调用,进入 AudioPolicyManager::getOutputForDevice():

  • 如果输出标识置了 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 或 AUDIO_OUTPUT_FLAG_DIRECT,那么最终调用 AudioFlinger::openOutput() 打开输出标识对应的输出流设备并创建相应的 PlaybackThread,保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;
  • 如果输出标识是其他类型,那么根据策略选择一个输出流设备和 PlaybackThread,并保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;别忘了在 3.4. AudioFlinger 回放录制线程 小节中提到:系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 PlaybackThread 了;

3. 通过 Binder 机制调用 AudioFlinger::createTrack()(注意 step2 中 AudioTrack 已经拿到一个 audio_io_handle_t 了,此时把这个 audio_io_handle_t 传入给 createTrack()):

  • 根据传入的 audio_io_handle_t 找到它对应的 PlaybackThread;
  • PlaybackThread 新建一个音频流管理对象 Track;Track 构造时会分配一块匿名共享内存用于 AudioFlinger 与 AudioTrack 的数据交换缓冲区(FIFO)及其控制块(audio_track_cblk_t),并创建一个 AudioTrackServerProxy 对象(PlaybackThread 将使用它从 FIFO 上取得可读数据的位置);
  • 最后新建一个 Track 的通讯代理 TrackHandle,并以 IAudioTrack 作为返回值给 AudioTrack(TrackHandle、BnAudioTrack、BpAudioTrack、IAudioTrack 的关系见上一个小节);

4. 通过 IAudioTrack 接口,取得 AudioFlinger 中的 FIFO 控制块(audio_track_cblk_t),由此再计算得到 FIFO 的首地址;

5. 创建一个 AudioTrackClientProxy 对象(AudioTrack 将使用它从 FIFO 上取得可用空间的位置);

AudioTrack 由此建立了和 AudioFlinger 的全部联系工作:

  • 通过 IAudioTrack 接口可以控制该音轨的状态,例如 start、stop、pause;
  • 持续写入数据到 FIFO 上,实现音频连续播放;
  • 通过 audio_io_handle_t,可以找到它对应的 PlaybackThread,从而查询该 PlaybackThread 的相关信息,如所设置的采样率、格式等等。

构造 1 个 AudioTrack 实例时,AudioFlinger 会有 1 个 PlaybackThread 实例、1 个 Track 实例、1 个 TrackHandle 实例、1 个 AudioTrackServerProxy 实例、1 块 FIFO 与之对应。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:07:57  更:2022-09-15 02:09:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:44:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码