音乐还在放,突然来了个语音播报,两个声音混在一起——这就是没做音频焦点。

做音频应用的时候,最开始思路很简单:要播放就创建 AudioRenderer,要录音就创建 AudioCapturer,完事了。
直到用户反馈:听歌的时候,应用里的提示音响起来,两个声音混在一起,根本听不清。更离谱的是,接了个电话,电话挂了,音乐自己又开始放了——用户都没点播放。
这时候才意识到:音频不是"想放就放",有个系统层面的仲裁机制,就是音频焦点和 AudioSession。
一、为什么会有音频冲突
先把场景想清楚:
| 场景 | 冲突情况 |
|---|---|
| 音乐播放 + 提示音 | 两个声音叠在一起 |
| 录音 + 播放 | 两个都占着音频通道 |
| 来电 + 音乐 | 电话应该打断音乐 |
| 导航播报 + 音乐 | 播报的时候音乐应该压低 |
如果没有系统仲裁,所有音频流想放就放,那声音就全乱了。系统需要知道:现在谁在播放?谁优先级更高?谁应该被打断?谁应该混音?
这就是音频焦点机制要解决的问题。
二、AudioSession 是什么角色
可以把 AudioSession 想成"播放许可证":
- 每个要播放音频的应用,都要先申请一个 Session;
- 系统根据 Session 的类型和优先级,决定谁能播;
- 高优先级的 Session 来了,低优先级的就要被打断;
- 释放了 Session,系统才能把音频通道给别人。
| Session 类型 | 典型场景 |
|---|---|
| 音乐播放 | 长时长、用户主动播放 |
| 语音播报 | 短时长、临时提示 |
| 通话 | 最高优先级 |
| 录音 | 独占输入通道 |
不同类型的 Session,系统的仲裁策略不一样。音乐是默认低优先级的,通话是最高优先级的。
三、获取和释放焦点
这段代码解决什么问题: 申请和释放音频焦点。
文件: audio/AudioPlayer.ets
用途: 音频焦点管理
接入位置: 播放器初始化和销毁
import audio from '@ohos.multimedia.audio';
class MusicPlayer {
private audioSession: audio.AudioSessionManager;
async init() {
this.audioSession = audio.getAudioSessionManager();
// 申请播放焦点
await this.audioSession.activateAudioInterrupt({
mode: audio.InterruptMode.SHARE
});
}
async release() {
// 释放焦点
await this.audioSession.deactivateAudioInterrupt();
}
}
这里最容易踩的坑就是:暂停播放了,但是没释放焦点。结果就是你暂停了,但焦点还在你手里,其他应用的提示音播不了。
正确的做法是:暂停或者退出页面的时候,一定要释放焦点。
四、打断和恢复
高优先级音频来了,你的播放会被打断。系统会通过事件通知你:现在要被打断了。
| 打断类型 | 你的处理 |
|---|---|
| 短暂打断(导航播报) | 压低音量,播报完恢复 |
| 永久打断(来电) | 暂停播放,不要自动恢复 |
| 焦点丢失 | 暂停,等待焦点回来 |
很多人写代码的时候,打断事件来了,直接就暂停。等焦点回来了,又自动继续播放。这不对——如果是来电这种永久打断,用户没点继续,你不能自己又开始放了。
正确的做法是:根据打断类型决定要不要自动恢复。短暂打断可以恢复,永久打断就停在那里,等用户操作。
五、混音和独占
有些场景是可以混音的,比如音乐和提示音,两个可以一起放。有些场景是独占的,比如通话,其他都不能出声。
| 模式 | 行为 |
|---|---|
| 独占 | 我播的时候别人都不能播 |
| 混音 | 可以和别人同时播 |
不是所有音频流都要抢独占。提示音这种短的,可以混音,不影响别人。音乐这种长的,要根据场景决定是独占还是混音。

六、录音和播放的冲突
还有个容易忘的点:录音和播放也会抢资源。
录音的时候,麦克风是被占用的。如果你同时还要播放,就要考虑是不是要做回声消除,是不是要把播放声音压下去。
很多人做录音应用的时候,只创建了 AudioCapturer,不管焦点。结果就是录音的时候,别的应用还在放音乐,录出来的音全是杂音。
七、几个容易踩的坑
第一个坑:播放器暂停后不释放焦点。占着茅坑不拉屎,其他应用播不了。
第二个坑:电话打断后直接自动播放。电话挂了,音乐自己又开始放,用户根本没点。
第三个坑:多个 AudioRenderer 状态互相冲突。创建了好几个播放实例,各自管各自的,焦点都乱了。
第四个坑:录音和播放抢焦点。录音的时候不管系统,别的声音还在响。
第五个坑:页面销毁后监听未释放。页面都退了,打断监听还在,内存泄漏。

这次做音频功能最大的体会是:音频不是"创建个播放器就完事了"。系统有一整套仲裁机制,谁能播、谁要被打断、谁能混音,都是系统说了算。你只负责在该停的时候停、该放的时候放、该释放的时候释放,别自己抢资源。

845

被折叠的 条评论
为什么被折叠?



