组合音频设备路由

组合音频设备路由功能增加了对同时向多个音频设备流式传输音频的支持。借助此功能,特许应用可以通过系统 API 为特定的 策略 选择多个首选设备。应用可以通过使用此功能提供的公开 API 更精确地发现音频设备的功能。对于 Android 11 及更低版本,音频框架实现对同时连接的同一类型的多个音频设备(例如,2 个蓝牙 A2DP 耳机)的支持有限。默认音频路由规则也不允许用户为给定的用例选择同一类型的多个设备。

从 Android 12 开始,移除了这些限制,以便支持新的用例,例如音频广播、向一组 BLE 音频耳机进行多播或同时选择多个 USB 声卡。不支持同时路由到多个 USB 设备。

从 Android 14 开始,USB 框架支持路由到多个 USB 设备,前提是这些 USB 设备属于不同的音频设备类型,并且内核和供应商支持同时连接多个 USB 设备。

本页介绍了如何实现对流式传输音频到多个音频设备的支持,以及如何验证此功能的实现。

支持流式传输音频到多个音频设备

Android 12 中有两组 API 支持此功能

  • 系统 API 处理策略的多个首选设备。
  • HIDL 接口由供应商作为音频 HAL 的一部分实现,用于报告设备功能。

以下各节将更详细地讨论这些 API 中的每一个。

处理策略的多个首选设备

音频策略管理器提供了系统 API,以更好地支持同时将音频流式传输到多个音频设备。这些系统 API 允许为给定策略设置、获取和移除多个首选设备。在 Android 12 之前,此功能仅支持单个设备。

音频策略管理器引入了活动媒体设备的概念,用于描述最有可能被选择用于媒体播放的设备。当连接可拆卸设备时,可能需要打开可以路由到此设备的音频 HAL 输出流,并探测其支持的属性。

打开输出流时必须指定音频设备。活动媒体设备是在此上下文中打开输出流时使用的设备。

活动媒体设备的选择可能会根据实际连接或断开连接的设备而变化。音频策略管理器使用以下一系列规则来选择活动媒体设备

  1. 如果媒体的所有首选设备都可用,则它们都会被选为活动设备。
  2. 否则,将选择最后连接的可移动设备。
  3. 如果没有可移动设备连接,则应用用于选择输出设备的默认音频策略规则来选择活动设备。

输出流必须满足以下条件才能重新打开并路由到活动设备,以便为播放选择最佳配置

  • 输出流必须支持活动设备。
  • 输出流必须支持动态配置文件。
  • 输出流当前不得路由到活动设备。

为了应用新的设备选择,如果输出流处于空闲状态,音频策略管理器会在设备连接时关闭并重新打开输出流,或者将其推迟到输出流置于待机状态时重新打开。

音频策略管理器提供了以下系统 API 列表(如 AudioManager.java 中所定义)

  • setPreferredDeviceForStrategy

    为给定策略的音频路由设置首选设备。请注意,设备在设置首选设备时可能不可用,但一旦可用,就会使用该设备。

  • removePreferredDeviceForStrategy

    移除先前使用 setPreferredDeviceForStrategysetPreferredDevicesForStrategy 设置的首选音频设备。

  • getPreferredDeviceForStrategy

    返回先前使用 setPreferredDeviceForStrategysetPreferredDevicesForStrategy 设置的音频策略的首选设备。

  • setPreferredDevicesForStrategy

    为给定策略设置首选设备。

  • getPreferredDevicesForStrategy

    返回先前使用 setPreferredDeviceForStrategysetPreferredDevicesForStrategy 设置的音频策略的首选设备。

  • OnPreferredDevicesForStrategyChangedListener

    定义一个接口,用于通知为给定音频策略设置的首选音频设备中的更改。

  • addOnPreferredDevicesForStrategyChangedListener

    添加一个监听器,以获取策略首选音频设备更改的通知。

  • removeOnPreferredDevicesForStrategyChangedListener

    移除先前添加的策略首选音频设备更改的监听器。

报告设备功能

作为音频 HAL 实现的一部分,供应商实现了支持报告设备功能的 API。本节介绍了用于报告设备功能的数据类型和方法,并列出音频 HIDL HAL V7 中为支持多个设备所做的一些更改。

数据类型

在音频 HIDL HAL V7 中,设备功能使用 AudioProfileAudioTransport 结构报告。AudioTransport 结构使用 AudioProfile 描述音频端口对于已知音频格式的功能,或者使用原始硬件描述符描述平台未知的格式。AudioProfile 结构包含音频格式、配置文件支持的采样率以及通道掩码列表,如以下来自 types.hal 的代码块所示

/**
* Configurations supported for a certain audio format.
*/
struct AudioProfile {
   AudioFormat format;
   /** List of the sample rates (in Hz) supported by the profile. */
   vec<uint32_t> sampleRates;
   /** List of channel masks supported by the profile. */
   vec<AudioChannelMask> channelMasks;
};

在音频 HIDL HAL V7 中,AudioPort 数据类型使用 AudioTransportAudioProfile 结构定义,以描述设备的功能。

音频 HAL 方法

音频策略管理器使用以下方法来查询设备的功能

  • getParameters:一种通用方法,用于检索供应商特定的参数值,例如支持的音频格式及其各自的采样率。
  • getAudioPort:返回给定音频端口支持的属性列表(例如采样率、格式、通道掩码、增益控制器)。

以下来自 IDevice.hal 的代码显示了 getAudioPort 方法的接口

   /**
    * Returns the list of supported attributes for a given audio port.
    *
    * As input, 'port' contains the information (type, role, address etc...)
    * needed by the HAL to identify the port.
    *
    * As output, 'resultPort' contains possible attributes (sampling rates,
    * formats, channel masks, gain controllers...) for this port.
    *
    * @param port port identifier.
    * @return retval operation completion status.
    * @return resultPort port descriptor with all parameters filled up.
    */
   getAudioPort(AudioPort port)
           generates (Result retval, AudioPort resultPort);

对旧版 API 的更改

为了支持多个音频配置文件,旧版 API 的 3.2 版本添加了一个名为 audio_port_v7 的新结构。有关更多详细信息,请参阅源代码

由于添加了 audio_port_v7,旧版 API 的 3.2 版本添加了一个名为 get_audio_port_v7 的新 API,用于使用 audio_port_v7 结构查询设备的功能。

以下来自 audio.h 的代码显示了 get_audio_port_v7 API 的定义

/**
 * Fills the list of supported attributes for a given audio port.
 * As input, "port" contains the information (type, role, address etc...)
 * needed by the HAL to identify the port.
 * As output, "port" contains possible attributes (sampling rates,
 * formats, channel masks, gain controllers...) for this port. The
 * possible attributes are saved as audio profiles, which contains audio
 * format and the supported sampling rates and channel masks.
 */
 int (*get_audio_port_v7)(struct audio_hw_device *dev,
                          struct audio_port_v7 *port);

当旧版 API 版本低于 3.2 且 HIDL HAL 版本为 7 或更高版本时,来自旧版 get_audio_port API 的数据必须填充到新的 AudioPort 格式中。在这种情况下,来自 get_audio_port 的所有报告的采样率和通道掩码都被假定为所有返回的格式都支持,从而可以实现从 get_audio_port 值到新的 AudioPort 结构的直接映射。

API 实现示例

本节介绍了一些测试套件,其中包含使用前面章节中介绍的 API 的方法。有关如何实现和使用这些 API 的一些示例,请参阅这些方法。

有关 setPreferredDevicesForStrategygetPreferredDevicesForStrategyremovePreferredDeviceForStrategyOnPreferredDevicesForStrategyChangedListener 系统 API 的用法的示例,请参见 GTS 中的 PreferredDeviceRoutingTest 方法。

要查看 AudioDeviceInfo 中新结构的用法的示例,请参阅 CTS 中的 AudioManagerTest#testGetDevices 方法。

有关 get_audio_port_v7 的实现的示例,请参见 audio_hal.c,它显示了如何查询多个设备的功能。

验证

本节提供有关 CTS 和 GTS(Google 移动服务测试套件)对音频管理器进行验证的信息。

CTS 测试

CTS 测试位于 android.media.cts.AudioManagerTest 中。

以下是可用的音频管理器测试列表

  • AudioManagerTest#testGetDevices

    验证音频设备的精确功能。它还验证 AudioDeviceInfo 结构中返回的音频配置文件是否保留了旧的扁平化数组格式中的内容,但采用新的 AudioProfile 格式。

  • AudioManagerTest#testPreferredDevicesForStrategyAudioManagerTest#testPreferredDeviceForCapturePreset

    验证与策略和捕获预设相关的首选设备的 API 测试是否成功完成。

GTS 测试

GTS 测试位于 com.google.android.gts.audioservice.AudioServiceHostTest 中。

要验证用于策略和捕获预设的首选设备的 API 是否正常工作,请运行 AudioServiceHostTest#testPreferredDeviceRoutingAudioServiceHostTest#testPreferredDeviceRoutingForCapturePreset 测试。