音频输入通常来自内置麦克风、外接麦克风或连接到设备的音频接口。音频输入也可以来自电话对话。
有时,两个或更多应用都可能想要“捕获”相同的音频输入。它们可能执行不同的任务。 例如,某些接收音频的应用可能会“录音”,就像简单的语音录音机一样,而其他应用可能会“监听”,例如 Google 助理或响应语音指令的无障碍服务。
无论是哪种情况,这些应用都希望接收音频输入。在本页中,无论应用是录制还是仅监听,我们都使用“捕获”一词。
如果两个或更多应用想要同时捕获音频,则可能会遇到将音频信号从同一来源传递给所有应用的问题。本页介绍了 Android 系统如何在多个捕获音频的应用之间共享音频输入。
Android 10 之前的行为
在 Android 10 之前,一次只能有一个应用捕获输入音频流。如果某个应用已在录制或监听音频,您的应用可以创建 AudioRecord
对象,但在您调用 AudioRecord.startRecording()
时会返回错误,并且录制不会开始。
这条规则有一个例外情况,即特权应用(例如 Google 助理或无障碍服务)具有 android.permission.CAPTURE_AUDIO_HOTWORD
权限并使用类型为 HOTWORD
的音频源。在这种情况下,其他应用可以开始录制。出现这种情况时,特权应用终止,新应用捕获输入。
Android 9 中还添加了另一项变更:只有在前台运行的应用(或前台服务)才能捕获音频输入。当没有前台服务或前台界面组件的应用开始捕获音频时,该应用会继续运行,但会收到静音,即使它是当时唯一捕获音频的应用也是如此。
Android 10 行为
Android 10 之前的行为是“先到先得”。 一旦某个应用开始捕获音频,除非正在捕获音频的应用停止,否则任何其他应用都无法访问音频输入。
Android 10 采用了一种优先级方案,可在应用运行时在应用之间切换输入音频流。在大多数情况下,如果新应用获取音频输入,之前捕获音频的应用会继续运行,但会收到静音。在某些情况下,系统可以继续向这两个应用传送音频。下面介绍了各种共享场景。
此方案类似于音频焦点处理多个应用争用音频输出的方式。不过,音频焦点由程序化请求来管理,以获取和释放焦点,而此处所述的输入切换方案基于优先级政策,每当有新应用开始捕获音频时,系统都会自动应用该政策。
为了捕获音频,Android 会区分两种类型的应用:
- “普通”应用由用户安装。
- “特权”应用已预安装在设备上。其中包括 Google 助理以及所有无障碍服务。
此外,如果应用使用“对隐私敏感”的音频源(CAMCORDER
或 VOICE_COMMUNICATION
),则其会受到区别对待。
使用和共享音频输入的优先级规则如下:
- 特权应用的优先级高于普通应用。
- 具有可见前台界面的应用比后台应用具有更高的优先级。
- 相较于从非隐私敏感源捕获音频的应用,从隐私敏感源捕获音频的应用有着更高的优先级。
- 两个普通应用永远无法同时捕获音频。
- 在某些情况下,特权应用可以与其他应用共享音频输入。
- 如果两个优先级相同的后台应用都在捕获音频,则后开始的那个优先级更高。
共享方案
当两个应用尝试捕获音频时,它们都可能会收到输入信号,或者其中一个应用可能会收到静音。
四种主要方案如下:
- Google 助理 + 普通应用
- 无障碍服务 + 普通应用
- 两个普通应用
- 语音通话 + 普通应用
Google 助理 + 普通应用
Google 助理是一款特权应用,因为它是预安装的,并且具有角色 RoleManager.ROLE_ASSISTANT
。拥有此角色的任何其他预安装应用都会受到类似处理。
Android 根据以下规则共享输入音频:
除非其他使用对隐私敏感的音频源的应用已在捕获音频,否则 Google 助理可以接收音频(无论是在前台还是后台)。
除非 Google 助理在屏幕顶部显示可见的界面组件,否则应用会接收音频。
请注意,只有当 Google 助理在后台运行且另一应用未从对隐私敏感的音频源捕获音频时,这两个应用才能接收音频。
无障碍服务 + 普通应用
AccessibilityService
需要严格的声明。
Android 根据以下规则共享输入音频:
如果服务的界面位于顶部,则服务和应用都会接收音频输入。此行为提供使用语音指令控制语音通话或视频捕获等功能。
如果该服务不在顶部,则此情况的处理方式与下述两个普通应用的情况一样。
两个普通应用
当两个应用同时进行捕获时,只有一个应用接收音频,另一个应用会受到静默处理。
Android 根据以下规则共享输入音频:
- 如果这两个应用都不是隐私敏感应用,则顶部有界面的应用会接收音频。如果两个应用都没有界面,则较晚开始者接收音频。
- 如果其中一个应用是隐私敏感应用,则该应用会接收音频,而另一个应用则会静音,即使该应用顶部有界面或最近开始捕获音频也是如此。
- 如果这两个应用都对隐私敏感,则最近开始捕获的应用会接收音频,而另一个应用会收到静音。
语音通话 + 普通应用
如果 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()
来大致了解设备上所有正在进行的录音。