音频输入通常来自内置麦克风、外部麦克风或连接到设备的音频接口。音频输入也可以来自电话通话。
有时两个或多个应用可能都想“捕获”相同的音频输入。它们可能正在执行不同的任务。例如,某些接收音频的应用可能正在“录制”,就像简单的录音机一样,而另一些应用可能正在“监听”,例如 Google 助理或响应语音命令的无障碍服务。
无论哪种情况,这些应用都希望接收音频输入。在本页中,无论应用是录制还是仅监听,我们都使用术语“捕获”。
如果两个或更多应用想同时捕获音频,可能会出现将来自同一源的音频信号传递给所有应用的问题。本页介绍了 Android 系统如何在捕获音频的多个应用之间共享音频输入。
Android 10 之前的行为
在 Android 10 之前,输入音频流一次只能由一个应用捕获。如果某个应用正在录制或监听音频,您的应用可以创建一个 AudioRecord
对象,但当您调用 AudioRecord.startRecording()
时会返回错误,并且录制不会开始。
此规则的一个例外是,当特权应用(如 Google 助理或无障碍服务)拥有 android.permission.CAPTURE_AUDIO_HOTWORD
权限并使用类型为 HOTWORD
的音频源时。在这种情况下,另一个应用可以开始录制。当这种情况发生时,特权应用会终止,新应用会捕获输入。
Android 9 中增加了另一个变化:只有在前台运行的应用(或前台服务)才能捕获音频输入。当没有前台服务或前台 UI 组件的应用开始捕获时,该应用会继续运行,但会接收到静音,即使它是当时唯一捕获音频的应用。
Android 10 行为
Android 10 之前的行为是“先到先得”。一旦一个应用开始捕获音频,其他应用就无法访问音频输入,直到正在捕获音频的应用停止。
Android 10 引入了一种优先级方案,可以在应用运行时在应用之间切换输入音频流。在大多数情况下,如果新应用获取了音频输入,之前捕获音频的应用会继续运行,但会接收到静音。在某些情况下,系统可以继续向两个应用都提供音频。下面解释了各种共享场景。
此方案类似于音频焦点处理多个应用争夺音频输出使用权的方式。然而,音频焦点是通过编程请求来获取和释放焦点来管理的,而此处描述的输入切换方案基于优先级策略,该策略在新应用开始捕获音频时自动应用。
为了捕获音频,Android 区分两种类型的应用
- “普通”应用由用户安装。
- “特权”应用预装在设备上。这包括 Google 助理和所有无障碍服务。
此外,如果应用使用“隐私敏感”的音频源,则会区别对待:CAMCORDER
或 VOICE_COMMUNICATION
。
使用和共享音频输入的优先级规则如下
- 特权应用的优先级高于普通应用。
- 具有可见前台 UI 的应用的优先级高于后台应用。
- 从隐私敏感源捕获音频的应用的优先级高于非隐私敏感源的应用。
- 两个普通应用绝不能同时捕获音频。
- 在某些情况下,特权应用可以与其他应用共享音频输入。
- 如果两个优先级相同的后台应用正在捕获音频,则最后启动的应用具有更高优先级。
共享场景
当两个应用尝试捕获音频时,它们可能都能接收输入信号,或者其中一个可能接收到静音。
有四种主要场景
- 助理 + 普通应用
- 无障碍服务 + 普通应用
- 两个普通应用
- 语音通话 + 普通应用
助理 + 普通应用
助理是一个特权应用,因为它预装在设备上并拥有 RoleManager.ROLE_ASSISTANT
角色。任何其他具有此角色的预装应用都将受到类似对待。
Android 根据以下规则共享输入音频
助理可以接收音频(无论是在前台还是后台),除非另一个正在使用隐私敏感音频源的应用已经捕获。
应用接收音频,除非助理在屏幕顶部有可见的 UI 组件。
请注意,只有当助理在后台且其他应用未从隐私敏感音频源捕获时,两个应用才能同时接收音频。
无障碍服务 + 普通应用
一个 AccessibilityService
需要严格的声明。
Android 根据以下规则共享输入音频
如果服务的 UI 位于顶部,服务和应用都将接收音频输入。此行为提供了使用语音命令控制语音通话或视频捕获等功能。
如果服务不在顶部,则此情况将按照下面的普通双应用场景进行处理。
两个普通应用
当两个应用同时捕获时,只有一个应用接收音频,另一个接收静音。
Android 根据以下规则共享输入音频
- 如果两个应用都不是隐私敏感的,具有顶部 UI 的应用接收音频。如果两个应用都没有 UI,则最近开始捕获的应用接收音频。
- 如果其中一个应用是隐私敏感的,它接收音频,而另一个应用接收静音,即使它具有顶部 UI 或最近才开始捕获。
- 如果两个应用都是隐私敏感的,则最近开始捕获的应用接收音频,另一个接收静音。
语音通话 + 普通应用
如果 AudioManager.getMode()
返回的音频模式为 MODE_IN_CALL
或 MODE_IN_COMMUNICATION
,则语音通话处于活动状态。
Android 根据以下规则共享输入音频
- 通话始终接收音频。
- 如果应用是无障碍服务,则可以捕获音频。
如果应用是具有
CAPTURE_AUDIO_OUTPUT
权限的特权(预装)应用,则可以捕获语音通话。为了捕获语音通话的上行链路 (TX)、下行链路 (RX) 或两者,应用必须指定音频源
MediaRecorder.AudioSource.VOICE_UPLINK
或MediaRecorder.AudioSource.VOICE_DOWNLINK
,和/或设备AudioDeviceInfo.TYPE_TELEPHONY
。
Android 11 行为
Android 11(API 级别 30)遵循上述 Android 10 优先级方案。它还在 AudioRecord
、MediaRecorder
和 AAudioStream
中提供了新方法,无论所选用例如何,都可以启用和禁用同时捕获音频的功能。
新方法如下
AudioRecord.Builder.setPrivacySensitive()
AudioRecord.isPrivacySensitive()
MediaRecorder.setPrivacySensitive()
MediaRecorder.isPrivacySensitive()
AAudioStreamBuilder_setPrivacySensitive()
AAudioStream_isPrivacySensitive()
当 setPrivacySensitive()
为 true
时,捕获用例是私密的,即使特权助理也无法同时捕获。此设置会覆盖取决于音频源的默认行为。例如,VOICE_COMMUNICATION
默认为私密,但 UNPROCESSED
不是。
配置更改
当多个应用同时捕获音频时,只有一两个是“活动”的(接收音频);其他应用则静音(接收静音)。当活动应用发生变化时,音频框架可能会根据这些规则重新配置音频路径
- 每个活动应用的音频输入设备可能会更改(例如,从内置麦克风更改为连接的蓝牙耳机)。
- 与最高优先级活动应用关联的预处理已启用。所有其他预处理均被忽略。
由于当更高优先级的应用变为活动状态时,活动应用可能会被静音,您可以在 AudioRecord
或 MediaRecorder
对象上注册 AudioManager.AudioRecordingCallback,以便在配置更改时收到通知。可能的更改包括
- 捕获静音或取消静音
- 设备已更改
- 预处理已更改
- 流属性已更改(采样率、通道掩码、样本格式)
您必须在捕获开始之前调用 AudioRecord.registerAudioRecordingCallback()
。回调仅在应用接收音频且发生更改时执行。
方法 onRecordingConfigChanged()
返回一个 AudioRecordingConfiguration
,其中包含当前的音频捕获状态。使用以下方法了解更改
isClientSilenced()
- 如果由于捕获策略导致返回给客户端的音频当前被静音,则返回 true。
getAudioDevice()
- 返回活动音频设备。
getEffects()
- 返回活动的预处理效果。请注意,如果客户端不是最高优先级的活动应用,则活动效果可能与
getClientEffects()
返回的效果不同。 getFormat()
- 返回流属性。请注意,客户端接收到的实际音频数据始终符合
getClientFormat()
返回的所需格式。框架会自动执行必要的重采样、通道和格式转换,将硬件接口使用的格式转换为客户端指定的格式。 AudioRecord.getActiveRecordingConfiguration()
.- 返回活动的录制配置。
您可以通过调用 AudioManager.getActiveRecordingConfigurations()
获取设备上所有活动录音的概览。