Android音频获取实现指南
在这个成立10周年的节点,某米发布了自己的新手机某米10青春版,同时发布了自己的定制UI系统MIUI 12。
其中有一个有趣的方面
小米闻声是一个语音交互的模组,这对推出了“小爱同学”的某米来说并不算太新鲜,但是这一次小米专门给这个产品做了一个定位:无障碍服务。
为什么要提供无障碍服务?
我之前在知乎上看过一个国内视障人士使用读屏软件来操纵手机的帖子,看过之后深深的感觉,太难了,视障人士用手机实在太难了。
很多对正常人来说一目了然的UI,对视障人士来说就是复杂又麻烦的古怪设计,尤其是那些APP中无处不在的广告,普通人可以视而不见,视障者却不得不听着读屏软件念一遍才能下滑。
听障患者也是一样,在这个短视频的时代,听障患者面对没有字幕的视频只能猜测视频里发生了什么,外卖电话很难接起来,电话可以用来发短信却不能用来发语音。
如何解决?
小米闻声就致力于解决这些问题。对于视障者来说,小米闻声可以用语音交互直接执行操作,省去了摸着手机靠耳朵找APP的时间;对于听障患者,它可以直接把别人的话转换成文字,让听障者多一双耳朵,还能帮语言障碍者将文字转换成语音,应对一些陌生人的电话。
企业的温情背后是技术的支撑。
会关心一个小众市场,帮助这些听障、视障者更方便的使用手机,说明小米是一家有温度的企业。
但是要完成这种有温度的服务,不仅是想法,更要有技术,小米闻声背后的技术,来自科大讯飞。
那Android如何用技术实现捕获音频呢?
相关背景介绍
Android Q 新引入的 AudioPlaybackCapture API 允许应用获取其它应用中的音频。在这个 API 的帮助下,开发者将顺利处理多种业务场景,为用户提供轻松简便的内容分享与无障碍体验。
Android 10 已引入 AudioPlaybackCapture API。应用可以借助此 API 复制其他应用正在播放的音频。此功能类似于屏幕采集,但采集对象是音频。主要用例是视频在线播放应用,这些应用希望捕获游戏正在播放的音频。
请注意,对于其音频正在被捕获的应用,Capture API 不会影响该应用的延迟时间。
部分常见用例包括:
- 实时字幕: 为正在播放的音频文件提供实时字幕和翻译。实际上,今年 I/O 开发者大会上展示的 Live Caption 示例应用就利用了该 API 开发。Live Caption 为用户创造了一种全新的音频交互方式,例如在公共场所没有耳机来收听音频,而这些体验在此之前是无法或者很难实现的。
- 游戏录音与直播: 录制游戏内声音,并将它们直播给线上观众,进而扩大游戏内容的社交影响力。
不过,在某些情况下,开发者可能并不希望自己应用的音频被获取。本文解释了音频获取对用户的影响,并介绍了一些防止获取的具体操作,在必要时,开发者们可以通过这些操作以禁止其它应用获取自己的音频。
用户界面长什么样?
为了获取其它应用的音频,应用必须首先从用户那里获得 RECORD_AUDIO 权限。
△ RECORD_AUDIO 权限对话框
此外,应用还需在获取开始前调用 MediaProjectionManager.createScreenCaptureIntent(),这会向用户显示如下对话框:
△ 屏幕获取 intent 对话框
用户点击 "现在开始" 后,获取会话便会正式启动,届时,设备上的视频和音频均会被获取。
△ 左一红色的是投射图标
在获取过程中,状态栏中的投射图标会一直处于红色状态。
我的应用中的音频会被获取吗?
应用中的音频在默认设置下能否被获取,取决于应用的目标 API 等级,详细行为如下表所示:
如何捕获音频?
播放器的捕获政策必须为 AudioAttributes.ALLOW_CAPTURE_BY_ALL
,此政策允许其他应用捕获播放的音频。该操作可以通过许多方法完成:
- 如要在所有播放器上启用捕获功能,请在应用的
manifest.xml
文件中包含android:allowAudioPlaybackCapture="true"
。- 您还可以通过调用
AudioManager.setAllowedCapturePolicy(AudioAttributes.ALLOW_CAPTURE_BY_ALL)
在所有播放器上启用捕获功能。- 使用
AudioAttributes.Builder.setAllowedCapturePolicy(AudioAttributes.ALLOW_CAPTURE_BY_ALL)
构建政策时,您可以针对单个播放器设置该政策。(如果您使用AAudio
,则调用AAudioStreamBuilder_setAllowedCapturePolicy(AAUDIO_ALLOW_CAPTURE_BY_ALL)
。)
如果满足这些前提条件,则应用可以捕获播放器生成的任何音频。
注意:应用的音频能否被捕获也取决于应用的 targetSdkVersion
。
- 默认情况下,适配 Android 9.0 及之前版本的应用不允许捕获播放的音频。如要启用该功能,请在应用的
manifest.xml
文件中包含android:allowAudioPlaybackCapture="true"
。- 默认情况下,适配 Android 10 (API 级别 29) 或更高版本的应用允许其他应用捕获其音频。如要停用“捕获播放的音频”功能,请在应用的
manifest.xml
文件中包含android:allowAudioPlaybackCapture="false"
。
停用系统捕获
上述允许捕获的保护措施仅适用于应用。默认情况下,Android 系统组件可以捕获播放的音频。其中许多组件由 Android 供应商自定义,并支持无障碍和字幕等功能。因此,我们建议应用允许系统捕获其播放的音频。在极少数情况下,如果您不希望系统捕获应用播放的音频,则可以将该捕获政策设置为 ALLOW_CAPTURE_BY_NONE
。
在运行时设置政策
在应用运行时,您可以调用 AudioManager.setAllowedCapturePolicy()
来更改捕获政策。如果您调用该方法时,MediaPlayer 或 AudioTrack 正在播放音频,则相应音频不受影响。您必须关闭播放器或曲目,然后再重新打开,这样政策变更才会生效。
政策 = 清单 + AudioManager + AudioAttributes
由于可以在多个位置指定捕获政策,因此请务必要了解如何确定有效政策。您应始终应用最严格的捕获政策。例如,即使将
AudioManager#setAllowedCapturePolicy
设置为ALLOW_CAPTURE_BY_ALL
,清单中包含setAllowedCapturePolicy="false"
的应用也决不会允许非系统应用捕获其音频。同样,如果将AudioManager#setAllowedCapturePolicy
设置为ALLOW_CAPTURE_BY_ALL
,将清单设置为setAllowedCapturePolicy="true"
,但媒体播放器的AudioAttributes
采用AudioAttributes.Builder#setAllowedCapturePolicy(ALLOW_CAPTURE_BY_SYSTEM)
构建而成,则非系统应用将无法捕获此媒体播放器播放的音频。
下表总结了清单属性和有效政策的效果:
allowAudioPlaybackCapture | ALLOW_CAPTURE_BY_ALL | ALLOW_CAPTURE_BY_SYSTEM | ALLOW_CAPTURE_BY_NONE |
---|---|---|---|
true | 任何应用 | 仅系统 | 无捕获 |
false | 仅系统 | 仅系统 | 无捕获 |
禁止第三方应用获取音频
有时候,开发者可能并不希望其它应用获取自己的音频,比如说,当音频包含:
- 敏感信息,如私人录音。
- 受版权保护的材料,如版权音乐或从影视作品中截取的音频选段。
应用的音频获取政策有两种:
1.针对所有音频。
2.针对单个音频播放器。
禁止第三方应用获取所有音频
您可以通过以下两种方式,禁止第三方应用获取应用中的所有音频:
- 请将下方代码添加至 AndroidManifest.xml
<application
...
android:allowAudioPlaybackCapture="false"/>
2.通过编程的方式,禁止获取行为: 在播放音频文件前,运行下方代码
AudioManager.setAllowedCapturePolicy(ALLOW_CAPTURE_BY_SYSTEM)
禁止第三方应用通过某个播放器获取音频
如果您想限制某个播放器的获取功能,请在创建它时设置获取政策:
AudioAttributes.Builder.setAllowedCapturePolicy(ALLOW_CAPTURE_BY_SYSTE
该方法适用于播放内容包含多类授权协议的情况,比如说,同时含有受版权保护的内容与免版税的内容。
禁止系统应用及组件获取音频
在默认设置下,系统应用和部件能够获取用途为 MEDIA (媒体), GAME (游戏) 和 UNKNOWN (未知) 的音频文件,这会用于支持实时字幕等重要的无障碍功能。
在极少数情况下,开发者也希望自己能够像管理第三方应用一样,禁止系统应用获取音频。请注意,当您禁止系统获取时,任何第三方应用的获取也将被禁止。
禁止获取所有音频
该操作只能通过程序方式实现,请您在播放音频前运行以下代码:
AudioManager.setAllowedCapturePolicy(ALLOW_CAPTURE_BY_NONE)
针对单个播放器停用获取
如需禁止某个播放器获取音频,请在创建它时设置以下获取政策:
AudioAttributes.Builder.setAllowedCapturePolicy(ALLOW_CAPTURE_BY_NON
下一步
如果应用的目标 API 等级为 28 或以下,而且您希望允许音频获取,请在应用的 manifest.xml 文件中添加 android:allowAudioPlaybackCapture="true"
如果您希望禁止部分或全部音频被获取,请根据上文所示操作更新应用。
更多内容,请前往Android 开发者官方文档查看。