Android 14 通过持续监控声音剂量测量结果并向用户发出有关有害暴露水平的警告,在音频框架和音频 HAL 中为声音剂量提供支持。
声音剂量是在一段时间内的声压级测量值。通过监测声音剂量,我们可以帮助用户免受过度暴露或长时间暴露声音带来的破坏性影响,从而在便携式 Android 设备上使用耳机时提供更好的听力保护,并最大限度地减少听力受损的可能性。
安全收听设备的新标准符合 IEC62368-1 第 3 版(需要登录)和 EN50332-3(仅限订户访问)中听力保护的监管要求,其中引入了声音剂量的概念。
音效检测功能让原始设备制造商 (OEM) 能够遵守新的听力安全法规。为了支持声音剂量,OEM 必须遵循接口规范和法规,实现所有自定义和认证。自定义 OEM 实现可以绕过或修改声音音量的默认 AOSP 实现。不过,强烈建议您使用 AOSP 实现。
声音剂量计算
通过计算计算得出的声音剂量 (CSD),IEC62368-1 第 3 版和 EN50332-3 中的标准提高了测量声音暴露的准确性。计算 CSD 的方法是随着时间的推移累积短暂的曝光水平 (MEL)。为计算声音剂量,要保留连续 7 天的累积 CSD 值。
根据 IEC62368-1 第 3 版第 10.6.3.2 节,如果 CSD 值达到 100%,系统会在每次增加 100% 时提醒用户。如果用户未确认警告,音量会调低为 IEC62368-1 表 39 中预定义的辐射能量等级 1 (RS1) 值。
如 IEC62368-1 第 3 版第 10.6.3.3 节所述,每次 MEL 值超过 IEC62368 表 39 的辐射能源 2 类 (RS2) 值时,除了声音剂量警告之外,系统还必须启动基于暴露的警告 -1。
若要根据这些法规进行认证并提高 CSD 值的相关性,系统必须使用用户感知的准确输出值(例如媒体播放输出值)。对 CSD 计算而言,使用的值要与用户实际接触到的声压级值相近。
架构
根据帧的捕获位置,变频器的硬件特性和影响会影响所渲染帧的功耗级别。为获得精确的输出声压级测量结果,我们扩展了 HAL 以直接从底层硬件获取 MEL 值,并考虑到数字信号处理器 (DSP) 或扬声器属性,例如阻抗、灵敏度和频率响应。
如果 HAL 无法提供 MEL 值,则音频框架会分析和计算 CSD。音频框架中的此计算基于从 HAL 报告的渲染输出以及发送到音频 DSP 的帧的相关信息。
声音剂量引入了 SoundDoseHelper
和 SoundDoseManager,
两个组件,如图 1 所示:
图 1. 声音剂量功能的架构组件。
SoundDoseHelper
位于 systemserver
进程中的 SoundDoseHelper
类是所有相关声音剂量数据的主要收集点。AudioService
类用于管理 SoundDoseHelper
类。
SoundDoseHelper
类负责以下操作:
- 处理新的剂量信息
- 持续记录声音剂量值
- 在
audioserver
崩溃时恢复状态 - 触发系统界面通知
- 调低音量
SoundDoseManager
位于 audioserver
进程中的 SoundDoseManager
类是 AudioFlinger
类的一部分,用于从 HAL 收集声音剂量数据,或在发送到 HAL 的帧内部计算这些数据(作为后备选项)。SoundDoseManager
类会将声音剂量数据发送到 SoundDoseHelper
类。
MelProcessor 和 MelAggregator
如果 HAL 无法提供 MEL 值,则应使用 libaudioutils
中的 MelProcessor
和 MelAggregator
实用程序用于内部声音剂量计算。
在 MelProcessor
类中,通过调用 MelProcessor::process(const void* buffer, size_t bytes)
,在具有音频样本的缓冲区上执行主计算。
OEM 可以根据需要在 HAL 实现中使用 MelProcessor
。
MelAggregator
类从不同的音频端口接收 MEL 值,并使用 7 天滚动时间计算 CSD 值。方法 MelAggregator::aggregateAndAddNewMelRecord_l(MelRecord mel)
会执行该逻辑。系统会将结果发送到 SoundDoseManager
类,以便与 AudioService
进行通信。
实现
从 Android 14 开始,HIDL 接口扩展已废弃,因此 AIDL 音频 HAL 中定义了名为 ISoundDose
的新 HAL 接口用于检索计算的 MEL 值和发出曝光警告。不过,对于需要更多时间来集成 AIDL 音频 HAL 的实现者,我们提供了独立的声音剂量 AIDL HAL,该 API 提供了 ISoundDoseFactory
界面。将来会将其废弃。
以下代码示例展示了 HAL 如何支持声音剂量:
/**
* This interface provides functions related to sound exposure control required for compliance to
* EN/IEC 62368-1 3rd edition. Implementing this interface is mandatory for devices for which
* compliance to this standard is mandated and implementing audio offload decoding or other direct
* playback paths where volume control happens below the audio HAL.
*/
@VintfStability
interface ISoundDose {
/**
* Max value in dBA used for momentary exposure warnings as defined by IEC62368-1
* 3rd edition. This value represents the default RS2 upper bound.
*/
const int DEFAULT_MAX_RS2 = 100;
/** Min value of the RS2 threshold in dBA as defined by IEC62368-1 3rd edition. */
const int MIN_RS2 = 80;
/**
* Sets the RS2 upper bound used for momentary exposure warnings. Default value is
* DEFAULT_MAX_RS2 as specified in IEC62368-1 3rd edition.
*
* @param rs2ValueDbA custom RS2 upper bound to use
* @throws EX_ILLEGAL_ARGUMENT if rs2ValueDbA is greater than DEFAULT_MAX_RS2 or lower
* than MIN_RS2
*/
void setOutputRs2UpperBound(float rs2ValueDbA);
/**
* Gets the RS2 upper bound used for momentary exposure warnings.
*
* @return the RS2 upper bound in dBA
*/
float getOutputRs2UpperBound();
/**
* Registers the HAL callback for sound dose computation. If sound dose is supported
* the MEL values and exposure notifications will be received through this callback
* only. The internal framework MEL computation will be disabled.
* It is not possible to unregister the callback. The HAL is responsible to provide
* the MEL values throughout its lifecycle.
*
* @param callback to use when new updates are available for sound dose
*/
void registerSoundDoseCallback(in IHalSoundDoseCallback callback);
@VintfStability
oneway interface IHalSoundDoseCallback {
/**
* Called whenever the current MEL value exceeds the set RS2 upper bound.
*
* @param currentDbA the current MEL value which exceeds the RS2 upper bound
* @param audioDevice the audio device where the MEL exposure warning was recorded
*/
void onMomentaryExposureWarning(float currentDbA, in AudioDevice audioDevice);
@VintfStability
parcelable MelRecord {
/**
* Array of continuously recorded MEL values >= MIN_RS2 (1 per second).
* First value in the array was recorded at 'timestamp'.
*/
float[] melValues;
/**
* Corresponds to the time in seconds, as reported by CLOCK_MONOTONIC, when
* the first MEL entry in melValues was recorded. The timestamp values have
* to be consistent throughout all audio ports, equal timestamp values will
* be aggregated.
*/
long timestamp;
}
/**
* Provides a MelRecord containing continuous MEL values sorted by timestamp.
* Note that all the MEL values originate from the audio device specified by audioDevice.
* In case values from multiple devices need to be reported, the caller should execute
* this callback once for every device.
*
* @param melRecord contains the MEL values used for CSD
* @param audioDevice the audio device where the MEL values were recorded
*/
void onNewMelValues(in MelRecord melRecord, in AudioDevice audioDevice);
}
}
新的 HAL 接口会实现回调,用于告知框架瞬时曝光,并在输出级别超过 RS1 时提供 MEL 值。实现这些接口后,框架使用它们进行 CSD 报告。如果没有此回调实现,系统会使用 AudioFlinger
上的回退实现来计算 CSD 值的估算值。
声音剂量独立 AIDL 支持
在 OEM 能够在 AIDL 音频 HAL 中集成声音剂数之前,他们可以使用独立的 AIDL API ISoundDoseFactory
来解决此问题。ISoundDoseFactory
使用 ISoundDose
接口,如以下代码示例所示:
@VintfStability
interface ISoundDoseFactory {
/**
* Retrieve the sound dose interface for a given audio HAL module name.
*
* If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
* implementing audio offload decoding or other direct playback paths where volume control
* happens below the audio HAL, it must return an instance of the ISoundDose interface.
* The same instance must be returned during the lifetime of the HAL module.
* If the HAL module does not support sound dose, null must be returned, without throwing
* any errors.
*
* @param module for which we trigger sound dose updates.
* @return An instance of the ISoundDose interface implementation.
* @throws EX_ILLEGAL_STATE If there was an error creating an instance.
*/
@nullable ISoundDose getSoundDose(in @utf8InCpp String module);
}
声音剂量 AIDL 音频 HAL 支持
长期以来,在 AIDL 音频 HAL 中,可通过扩展 IModule
接口支持声音剂量接口,如以下代码示例所示:
@VintfStability
interface IModule {
…
/**
* Retrieve the sound dose interface.
*
* If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
* implementing audio offload decoding or other direct playback paths where volume control
* happens below the audio HAL, it must return an instance of the ISoundDose interface.
* The same instance must be returned during the lifetime of the HAL module.
* If the HAL module does not support sound dose, null must be returned, without throwing
* any errors.
*
* @return An instance of the ISoundDose interface implementation.
* @throws EX_ILLEGAL_STATE If there was an error creating an instance.
*/
@nullable ISoundDose getSoundDose();
}
此功能是 IEC62368-1 第 3 版和 EN50332-3 中所述的新法规的实现方式,因此没有任何面向外部的 API。
OEM 可以通过以下方式实现设备认证:实现新的 HAL 接口,为音频框架提供准确的 CSD 数据(推荐),或者通过提供自定义的声音剂量实现来实现。
启用声音剂量计算
默认情况下,AOSP 支持助听安全逻辑,以确保符合现有的 EN50332-2 和 IEC62368-1 10.6.5 标准。
在 Android 14 中,系统会默认停用声音剂量计算。
从 Android 14-QPR1 开始,请按照以下准则计算声音剂量。
如果您所在的国家/地区强制执行声音剂量法规,请检查
config.xml
中的config_safe_media_volume_enabled
是否已设置为true
。为了符合 EN50332-3 和 IEC62368-1 10.6.3 要求,供应商必须将
config.xml
中的config_safe_sound_dosage_enabled
标志叠加到true
。对于支持分流解码且未实现声音剂量 HAL 接口的设备,不得将config_safe_sound_dosage_enabled
设置为true
。在这种情况下,将config_safe_sound_dosage_enabled
设置为true
可能会导致 CSD 值不准确以及不符合安全听力标准的认证问题。
下面的决策图描述了根据国家/地区限制和标志值确定计算 CSD 还是旧版听力安全等级(在 Android 14 之前实现)的逻辑。
图 2. 启用声音剂量计算(在 Android 14-QPR1 中添加了该逻辑)。
验证
在实现声音剂量的 HAL 接口时,OEM 必须针对 IModule AIDL 音频 HAL 实现的 VtsHalAudioCoreTargetTest
定义的 VTS 测试用例进行验证,或者针对独立声音剂量 AIDL HAL 实现的 VtsHalSoundDoseFactoryTargetTest
定义的 VTS 测试用例进行验证。