共享音频输入

音频输入通常来自内置麦克风、外接麦克风或连接到设备的音频接口。音频输入也可以来自电话对话。

有时,两个或更多应用可能都想“捕获”同一音频输入。他们可能在执行不同的任务。例如,某些接收音频的应用可能正在“录音”(如简单的录音机),而其他应用可能正在“监听”(如 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 会根据以下规则共享输入音频:

Android 11 行为

Android 11(API 级别 30)遵循上述 Android 10 优先级方案。它还在 AudioRecord、MediaRecorder 和 AAudioStream 中提供了新方法,用于启用和停用同时捕获音频的功能,无论选择何种用例。

这些新方法包括:

当 setPrivacySensitive() 为 true 时,捕获用例是私有的,即使是特权助理也无法同时捕获。此设置会覆盖取决于音频来源的默认行为。例如,VOICE_COMMUNICATION 默认不公开,但 UNPROCESSED 并非如此。

配置变更

当多个应用同时捕获音频时,只有一两个应用处于“活动”状态(接收音频);其他应用则处于静音状态(接收静音)。当活跃应用发生变化时,音频框架可能会根据以下规则重新配置音频路径:

  • 每个活跃应用的音频输入设备可能会发生变化(例如,从内置麦克风变为连接的蓝牙耳机)。
  • 系统会启用与优先级最高的活跃应用关联的预处理。 所有其他预处理都会被忽略。

由于当优先级较高的应用变为活跃状态时,活跃应用可能会被静音,因此您可以在 AudioRecord 或 MediaRecorder 对象上注册 AudioManager.AudioRecordingCallback,以便在配置发生更改时收到通知。可能的更改包括:

  • 捕获静音或取消静音
  • 设备已更改
  • 预处理已更改
  • 音频流属性已更改(采样率、声道掩码、采样格式)

您必须在开始捕获之前调用 AudioRecord.registerAudioRecordingCallback()。仅当应用正在接收音频且发生更改时,才会执行回调。

onRecordingConfigChanged() 方法会返回一个包含当前音频捕获状态的 AudioRecordingConfiguration。您可以通过以下方法了解相关变更:

isClientSilenced()
如果由于捕获政策而导致返回给客户端的音频当前处于静音状态,则返回 true。
getAudioDevice()
返回活跃的音频设备。
getEffects()
返回有效的预处理效果。请注意,如果客户端不是优先级最高的活跃应用,则活跃效果可能与 getClientEffects() 返回的效果不同。
getFormat()
返回数据流属性。请注意,客户端收到的实际音频数据始终遵循 getClientFormat() 返回的所需格式。框架会自动执行必要的重新采样、声道和格式转换,将硬件接口使用的格式转换为客户端指定的格式。
AudioRecord.getActiveRecordingConfiguration()
返回有效的录制配置。

您可以通过调用 AudioManager.getActiveRecordingConfigurations() 来大致了解设备上的所有活动录制。