组合音频设备路由

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

从 Android 12 开始,这些限制被移除,以便允许新的用例,例如音频广播、多播到一组 BLE 音频耳机或同时使用多个 USB 声卡。

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

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

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

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

以下部分将更详细地讨论这些 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测试。