减少延迟的设计

Android 4.1 版本更改了内部框架,缩短了音频输出路径的延迟时间。该版本还对公开客户端 API 或 HAL API 进行了细微更改。本文档介绍了初始设计,此设计也在不断发展。充分了解这一设计应该有助于设备的原始设备制造商 (OEM) 和 SoC 供应商在其特定设备和芯片组上正确地实施此设计。本文不适用于应用开发者。

创建音轨

客户端可以选择性地在 AudioTrack C++ 构造函数或 AudioTrack::set()audio_output_flags_t 参数中设置位 AUDIO_OUTPUT_FLAG_FAST。目前能执行此操作的客户端仅包括:

AudioTrack C++ 实现会审核 AUDIO_OUTPUT_FLAG_FAST 请求,并且可以选择性地拒绝客户端级别的请求。如果它决定传递该请求,则会使用 IAudioTrack 工厂方法 IAudioFlinger::createTrack()track_flags_t 参数的 TRACK_FAST 位来实现。

AudioFlinger 音频服务器会审核 TRACK_FAST 请求,并且可以选择性地拒绝服务器级别的请求。它通过共享存储器控制块的位 CBLK_FAST 通知客户端是否已接受该请求。

影响决定的因素包括:

  • 此输出的快速混音器线程分布(见下文)
  • 音轨采样率
  • 为音轨执行回调处理程序的客户端线程分布
  • 音轨缓冲区的大小
  • 可用的快速音轨槽(见下文)

如果客户端的请求被接受,则称为“快速音轨”,否则称为“常规音轨”。

混音器线程

AudioFlinger 在创建常规混音器线程时,会决定是否也要创建快速混音器线程。常规混音器和快速混音器都不与特定的音轨相关联,而是与一组音轨相关联。一直都会存在一个常规混音器线程。快速混音器线程(如果存在)的运行优先级低于常规混音器线程并在其控制下运行。

快速混音器

功能

快速混音器线程具备以下功能:

  • 对常规混音器的子混音和最多 7 个客户端快速音轨进行混音
  • 每条音轨的衰减

删减的功能:

  • 每条音轨的采样率转换
  • 每条音轨的效果
  • 每次混音的效果

周期

快速混音器按周期运行,推荐周期为 2 到 3 毫秒 (ms),但如果有调度稳定性需求,则可采用略久的 5 毫秒为周期。之所以选择这个数字,是为了确保在考虑完整的缓冲区流水线的情况下,总延迟时间大约为 10 毫秒。可以采用更小的值,但这样可能导致功耗增加以及出现异常,具体取决于 CPU 调度的可预测性。也可以采用更大的值(最高 20 毫秒),但这样会导致总延迟时间降级,因此应避免采用。

调度

快速混音器以较高的 SCHED_FIFO 优先级运行。它只需要很短的 CPU 时间,但必须经常运行并且具有低调度抖动。 抖动表示周期时间的变化:它是实际周期时间与预计周期时间之间的差值。运行太迟会因欠载而导致异常。运行过早则会因从快速音轨中提取数据时音轨尚未提供数据而导致异常。

屏蔽

在理想情况下,除了在 HAL write() 时,快速混音器线程不会屏蔽。快速混音器内的其他屏蔽事件将被视为错误。尤其要避免互斥情况。相反,应使用非屏蔽算法(也称为无锁算法)。有关此主题的更多信息,请参阅避免优先级反转

与其他组件的关系

快速混音器几乎不与客户端直接交互。尤其是,快速混音器看不到 Binder 级别的操作,但它确实会访问客户端的共享存储器控制块。

快速混音器通过状态队列接收来自常规混音器的命令。

除了提取音轨数据,快速混音器通过常规混音器与客户端进行交互。

快速混音器的主接收器是音频 HAL。

常规混音器

功能

已启用所有功能:

  • 最多 32 条音轨
  • 每条音轨的衰减
  • 每条音轨的采样率转换
  • 效果处理

周期

该周期被计算为快速混音器周期(大于等于 20 毫秒)的第一个整数倍数。

调度

常规混音器以较高的 SCHED_OTHER 优先级运行。

屏蔽

允许常规混音器屏蔽,并且通常在各种互斥体以及屏蔽管中发生屏蔽,以写入其子混音。

与其他组件的关系

常规混音器与外界广泛互动,包括 Binder 线程、音频策略管理器、快速混音器线程和客户端音轨。

常规混音器的接收器是快速混音器音轨 0 的屏蔽管。

标记

AUDIO_OUTPUT_FLAG_FAST 位是一个提示。无法保证满足要求。

AUDIO_OUTPUT_FLAG_FAST 是一个客户端级别的概念。它不会出现在服务器中。

TRACK_FAST 是一个客户端到服务器的概念。