iOS的音频体系设计得相当精巧,但也正因为精巧,配置稍有不妥就会出现各种奇怪的表现:应用切到后台后声音停了、用户正在听歌结果被应用的提示音打断、或者反过来,应用的音频被系统的各种声音压得几乎听不见。这些问题的根源大多指向同一个类——AVAudioSession。本文重点讨论两个容易被忽视的细节:一是AVAudioSessionCategoryOptionMixWithOthers这个混音选项的正确用法,二是开启混音之后如何通过音量标准化让自己的内容在多路音频并存时依然清晰。

一、先弄清楚AVAudioSession的类别与选项机制
AVAudioSession是iOS提供的单例对象,它负责管理应用与系统中其他音频之间的交互关系。开发者不能直接控制其他应用的音量,能做的只是通过设置会话类别(Category)和选项(Options)来声明自己的音频行为,系统再据此决定混音策略、是否响应静音键、是否占用音频焦点等。
后台播放音频最常见的组合是AVAudioSessionCategoryPlayback配合后台模式。默认情况下,playback类别是一个“独占”类别——激活会话时,系统会暂停其他所有应用的音频,比如用户正在用音乐App听歌,你的应用一激活会话,音乐就停了。这种体验在很多场景下是很粗暴的。而AVAudioSessionCategoryOptionMixWithOthers这个选项的作用,就是告诉系统:我的音频愿意和其他应用的音频混合播放,我不需要独占音频焦点。
NSError *error = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
// 设置类别为playback,并附带混音选项
[session setCategory:AVAudioSessionCategoryPlayback
options:AVAudioSessionCategoryOptionMixWithOthers
error:&error];
if (error) {
NSLog(@"设置音频会话失败: %@", error.localizedDescription);
}
// 激活会话
[session setActive:YES error:&error];
如果用Swift,写法更简洁一些:
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, options: .mixWithOthers)
try session.setActive(true)
} catch {
print("音频会话配置出错: \(error)")
}
有一个细节值得注意:如果开启了混音选项,锁屏界面和控制中心的播放控件默认不会显示你的应用信息。这是系统的设计逻辑——控制中心展示的是“音频焦点持有者”,而混音应用主动放弃了这个焦点。如果你的应用确实需要在控制中心露出控件,可以改用AVAudioSessionCategoryOptionDuckOthers(压低其他音频)或者干脆不混音,但这就回到了独占模式,需要根据产品形态权衡。
二、后台播放的完整配置:混音只是其中一环
很多开发者以为设置了playback类别就能后台播放,实际还差几步。完整的后台音频播放链路包括:Xcode工程中开启Background Modes的Audio能力、Info.plist中的相应声明、播放器层的配置,以及对于混音模式下的特殊处理。
首先在Xcode的Signing & Capabilities里勾选Audio, AirPlay, and Picture in Picture,这会在Info.plist中生成UIBackgroundModes数组,其中包含audio字符串。然后在代码中,AVAudioPlayer或AVPlayer创建后要设置AVAudioSessionCategoryPlayback类别,否则应用进入后台约几秒后音频就会被系统挂起。
// 完整的后台播放配置示例
func setupAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(
.playback,
mode: .default,
options: [.mixWithOthers] // 与其他应用混音
)
try session.setActive(true)
// 接收音频中断通知(来电、闹钟等)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleInterruption),
name: AVAudioSession.interruptionNotification,
object: session
)
} catch {
print("音频配置失败: \(error)")
}
}
中断处理也是容易被漏掉的部分。即使开启了混音,来电、Siri唤起等系统级事件仍可能打断你的播放。正确做法是监听AVAudioSessionInterruptionNotification,在中断开始时暂停播放、记录进度,中断结束时根据通知里的选项判断是否应该恢复播放。另外,拔出耳机触发的路由变化通知也要处理,否则声音可能从扬声器突然外放,这在某些场合(比如听书类应用)会非常尴尬。
三、混音带来的音量竞争问题与标准化方案
开启MixWithOthers之后,一个新的问题浮现出来:你的音频不再是“舞台中央唯一的表演者”了。当用户的音乐、播客、导航语音和你应用的音效同时存在时,如果你的音频文件本身录制音量偏小,就会被其他声音淹没;反过来如果文件电平很高,混合后还可能产生削波失真。这就是音量标准化(Normalization)要解决的问题。
音量标准化的核心思路是分析音频的真实响度或峰值,然后施加一个统一的增益,让所有音频内容落在相近的电平区间。业界通行的标准是EBU R128(欧洲广播联盟的响度标准),它以LUFS为单位衡量感知响度,移动端内容通常建议对齐到-16 LUFS左右,峰值不超过-1 dBTP。相比之下,简单的峰值归一化(把最大峰值拉到接近0 dBFS)实现简单但效果粗糙,因为人耳感知的响度和峰值并不成正比。
在客户端层面,可以通过AVAudioEngine挂一个AVAudioUnitEQ或者用kAudioUnitSubType_NewTimePitch之外的增益单元来做运行时增益调节,但更实用的做法是读取averagePower(forChannel:)的实时电平来做动态平衡:
// 使用AVAudioPlayer的计量功能监测电平
player.isMeteringEnabled = true
// 定时器中读取电平并动态调整音量
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
self.player.updateMeters()
let power = self.player.averagePower(forChannel: 0)
// 电平过低时提升player音量,过高时降低
if power < -30.0 {
self.player.volume = min(1.0, self.player.volume + 0.05)
} else if power > -10.0 {
self.player.volume = max(0.3, self.player.volume - 0.05)
}
}
更彻底的方案是在音频资产入库或打包阶段就完成标准化,用ffmpeg等工具离线处理:
# 使用ffmpeg按EBU R128标准做两遍法响度标准化 ffmpeg -i input.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 -ar 44100 output.mp3
这条命令的参数含义是:目标整体响度-16 LUFS,真峰值上限-1.5 dBTP,响度动态范围11 LU。离线标准化一遍到位,客户端不需要做动态增益,播放时只需保证volume属性保持默认值1.0,让用户通过系统音量键控制总音量即可。这是省心且体验最好的方案,特别适合音频内容相对固定的应用。
四、独占与混音的取舍:没有万能选项
最后需要强调的是,MixWithOthers不是“更高级”的配置,而是适合特定场景的配置。判断标准其实很简单:你的音频内容是否是用户主动选择聆听的主体。如果是音乐播放器、播客应用、有声书,用户带着明确目的打开它,就应该用独占模式(不加mixWithOthers),甚至考虑duckOthers来压低背景里的其他声音,同时享受锁屏控件、控制中心展示这些系统级待遇。
而如果你的音频是伴随性质的——跑步应用的语音指导、 meditation应用的背景白噪音、游戏的环境音、语言学习应用的发音示范——混音模式才是正确选择。用户可能一边听歌一边用你的应用,独占模式会强行打断他们的音乐,这种“抢焦点”的行为是应用商店差评的常见来源。值得注意的是,混音模式下应用自身仍然可以用MPRemoteCommandCenter注册远程控制事件,只是控件不会出现在控制中心而已,耳机线控的播放暂停依然可以响应。
总结一下实践要点:混音选项在setCategory时通过options参数传入;后台播放需要Background Modes配合;音频内容提前做响度标准化到-16 LUFS左右;中断和路由变化通知务必处理;产品层面根据音频内容的主次关系决定独占还是混音。把这些细节都照顾到,应用的音频体验才算真正打磨到位。
AVAudioSessioniOS后台音频播放音量标准化修改时间:2026-09-07 14:20:47