iOS的音频体系是围绕AVAudioSession设计的,它相当于一个全局的音频资源调度器,决定了应用能否与其他应用的音频共存、能否在锁屏后继续发声、能否使用麦克风等。当一个应用既要后台播放音频,又要通过麦克风做实时监听(比如K歌、语音伴奏、实时降噪类场景)时,就会触碰这套体系中最容易出问题的几个配置点。本文结合实际踩坑经验,详细讲解如何正确组合AVAudioSessionCategoryOptionAllowBluetooth选项与麦克风权限,让播放与录音稳定共存。

理解AVAudioSession的Category与Mode机制
AVAudioSession提供了多个Category,每个Category决定了音频的输入输出能力。AVAudioSessionCategoryPlayback只允许输出,激活麦克风会直接失败;而需要边播边录的场景必须使用AVAudioSessionCategoryPlayAndRecord,它同时打开扬声器和麦克风的通路。
但PlayAndRecord有一个隐藏的坑:默认情况下它会把音频路由切到受话器(听筒),音量会变得非常小,很多人以为是Bug,其实是Mode没配置。将Mode设为AVAudioSessionModeVideoChat或AVAudioSessionModeDefault并配合defaultToSpeaker选项,才能把声音路由回扬声器或蓝牙设备。
另外要注意Category只是声明意图,真正生效需要调用setActive(true)。激活时机也有讲究:在后台状态下首次激活PlayAndRecord会失败,必须在前台完成首次激活,之后进入后台才能继续工作。
AllowBluetooth选项的作用与蓝牙协议陷阱
在PlayAndRecord模式下,如果不加AVAudioSessionCategoryOptionAllowBluetooth选项,系统会认为蓝牙设备不支持录音而直接禁用蓝牙音频,播放声音会突然从蓝牙耳机跳回手机扬声器。加上这个选项后,系统会使用蓝牙的HFP(免提协议)profile来同时支持录音和播放。
这里的关键陷阱是:HFP协议的采样率通常只有16kHz或24kHz(取决于蓝牙芯片版本),远低于A2DP协议的44.1kHz。纯播放时走A2DP音质很好,一旦开启麦克风切换到HFP,用户会明显感觉音质下降。如果使用的是较新的蓝牙耳机,可以尝试AVAudioSessionCategoryOptionAllowBluetoothA2DP,它允许在PlayAndRecord下继续走A2DP输出,录音则由手机自带麦克风承担,音质和体验都会更好。
采样率的变化还会触发运行时问题:从A2DP切换到HFP时,正在运行的AudioUnit或AVAudioEngine可能因为硬件格式变化而中断。正确的做法是监听AVAudioSessionRouteChangeNotification,在回调中重建音频处理链,示例代码如下:
- (void)setupAudioSession {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
// 使用边播边录的Category
[session setCategory:AVAudioSessionCategoryPlayAndRecord
mode:AVAudioSessionModeDefault
options:AVAudioSessionCategoryOptionAllowBluetooth |
AVAudioSessionCategoryOptionDefaultToSpeaker
error:&error];
if (error) {
NSLog(@"Category设置失败: %@", error.localizedDescription);
}
// 前台完成首次激活
[session setActive:YES error:&error];
}
- (void)observeRouteChange {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRouteChange:)
name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)handleRouteChange:(NSNotification *)note {
AVAudioSessionRouteChangeReason reason = [note.userInfo[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
if (reason == AVAudioSessionRouteChangeReasonNewDeviceAvailable) {
// 蓝牙设备接入,采样率可能变化,需要重建AVAudioEngine
[self rebuildAudioEngine];
}
}
麦克风权限申请与后台模式的正确配置
即便Category配置正确,麦克风权限没到位录音依然会静默失败。iOS要求在Info.plist中添加NSMicrophoneUsageDescription键,并填写清晰的用途说明,否则应用在调用录音相关API时会直接崩溃。权限申请本身是异步的,要在requestRecordPermission的回调中确认状态后再启动音频引擎,避免在未授权状态下激活会话。
后台播放还需要在Xcode的Signing & Capabilities中勾选Audio、AirPlay and Picture in Picture后台模式,对应Info.plist中的UIBackgroundModes包含audio值。注意后台模式只是允许音频继续,不能保证应用不被系统挂起,如果音频链路完全停止输出超过几秒,系统仍可能回收资源。因此实时监听场景通常要保持一个持续的音频IO在运行。
还有一个容易被忽略的权限细节:iOS 14之后蓝牙权限独立出来了,需要NSBluetoothAlwaysUsageDescription。如果应用要连接蓝牙音频设备却没声明这个权限,即便AllowBluetooth选项写了,蓝牙路由也不会生效。
常见冲突场景的排查与解决方案
场景一:进入后台后播放立即停止。排查顺序是先确认后台模式勾选、再确认Category不是Ambient系列、最后检查是否在后台才首次激活Session。场景二:开启麦克风后蓝牙没声音。这基本就是缺少AllowBluetooth选项,或者蓝牙耳机本身只支持A2DP不支持HFP,此时改用AllowBluetoothA2DP即可。
场景三:录音全是回声。PlayAndRecord默认开启了系统回声消除,但如果自己用AVAudioEngine处理音频时误关了相关设置,或使用了Measurement模式,回声消除会被禁用。保持AVAudioSessionModeVideoChat可以获得较好的回声抑制效果。
最后建议在开发阶段打开音频会话的日志观察:通过NSLog输出当前Route描述和采样率,能够快速定位路由切换问题。整体方案的要点可以归纳为:PlayAndRecord作为Category基础,AllowBluetooth或AllowBluetoothA2DP保障蓝牙通路,DefaultToSpeaker保证外放,麦克风与蓝牙权限双声明,配合路由变化通知动态重建音频链路。按这套组合配置,后台播放与实时监听的冲突基本可以彻底解决。
AVAudioSession后台音频播放iOS麦克风权限修改时间:2026-09-12 18:08:31