iOS 音频会话 AVAudioSession 完整机制:分类、模式、激活策略
在iOS开发中,只要涉及音频播放、录制(如音乐播放器、语音通话、录音APP),就绕不开 AVAudioSession。它是iOS系统管理音频资源的“总管家”,负责协调APP与系统、其他APP之间的音频抢占、路由切换(扬声器/耳机/蓝牙)、音量控制等核心逻辑。
很多开发者在开发音频相关功能时,常会遇到“播放没声音”“插入耳机不切换路由”“后台播放被中断”“与其他音频APP冲突”等问题,本质上都是对 AVAudioSession 的机制理解不透彻,尤其是分类、模式的选择和激活策略的运用出现了偏差。
本文将从基础概念入手,逐步拆解 AVAudioSession 的完整机制,重点讲解分类、模式的核心作用及选型逻辑,结合激活策略和实战避坑,搭配可直接复用的代码示例,帮你彻底掌握这个iOS音频开发的核心知识点。
一、先搞懂:AVAudioSession 到底是什么?
AVAudioSession 是 Apple 提供的音频会话管理类(隶属于 AVFoundation 框架),它的核心作用是统一管理APP的音频行为,并与系统音频服务进行通信,解决“多个音频APP共存时的资源竞争”“音频硬件(扬声器、耳机等)的路由分配”“音频场景适配”三大核心问题。
简单来说,你的APP想播放或录制音频,必须先通过 AVAudioSession 向系统“报备”自己的音频需求(比如“我要播放音乐,希望能后台播放”“我要录音,需要关闭其他音频”),系统再根据所有APP的“报备”情况,分配音频资源、决定音频路由。
核心特性总结:
- 单例模式:整个APP只有一个 AVAudioSession 实例,通过
[AVAudioSession sharedInstance]获取,全局共享。 - 行为契约:通过“分类+模式”定义APP的音频行为,系统根据这个契约分配资源。
- 路由管理:自动或手动控制音频输出/输入路由(扬声器、耳机、蓝牙音箱、麦克风等)。
- 状态监听:监听音频会话的中断(如来电、闹钟)、路由变化(插入/拔出耳机)等事件,适配场景变化。
基础使用代码(OC/Swift)
无论后续配置分类、模式,第一步都是获取单例并导入头文件,以下是基础模板代码,可直接复用:
// OC 基础模板(需导入 AVFoundation 头文件)
#import <AVFoundation/AVFoundation.h>
// 获取 AVAudioSession 单例
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
// 快速判断当前会话激活状态
BOOL isActive = audioSession.isActive;
NSLog(@"当前音频会话激活状态:%@", isActive ? @"已激活" : @"未激活");
// Swift 基础模板(需导入 AVFoundation 框架)
import AVFoundation
// 获取 AVAudioSession 单例
let audioSession = AVAudioSession.sharedInstance()
// 快速判断当前会话激活状态
let isActive = audioSession.isActive
print("当前音频会话激活状态:isActive ? "已激活" : "未激活")")
二、核心机制1:音频会话分类(Category)—— 定义音频行为的“基础规则”
分类(Category)是 AVAudioSession 最核心的配置,它直接决定了APP的音频行为边界,比如“是否允许后台播放”“是否与其他音频APP共存”“是否需要使用麦克风”。
Apple 提供了7种官方分类(iOS 10+ 稳定支持),每种分类对应特定的音频场景,开发者需根据APP的核心功能选择,不可随意搭配。下面重点讲解常用分类,结合场景说明选型逻辑,并附上对应配置代码。
1. 常用核心分类(必掌握)
(1)AVAudioSessionCategoryPlayback —— 纯播放场景(推荐音乐/视频APP)
核心作用:用于仅播放音频的场景(如音乐播放器、播客APP),是最常用的分类之一。
关键特性:
- 默认不允许与其他音频APP共存(会抢占其他APP的音频资源,比如打开你的音乐APP,其他正在播放的音乐APP会暂停)。
- 支持后台播放(需在 Info.plist 中配置
UIBackgroundModes→audio)。 - 支持静音开关控制(静音模式下,若未连接耳机,音频会静音;连接耳机则正常播放)。
- 不使用麦克风(若需同时播放+录音,不可用此分类)。
配置代码(音乐播放器场景)
// OC 配置:纯音乐播放(支持后台播放)
#import <AVFoundation/AVFoundation.h>
- (void)configurePlaybackCategory {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
// 配置分类为 Playback,模式为默认,允许蓝牙输出
[audioSession setCategory:AVAudioSessionCategoryPlayback
mode:AVAudioSessionModeDefault
options:AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
if (error) {
NSLog(@"Playback 分类配置失败:%@", error.localizedDescription);
return;
}
// 激活会话(后续会详细讲解激活策略)
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
if (error) {
NSLog(@"会话激活失败:%@", error.localizedDescription);
}
}
// Swift 配置:纯音乐播放(支持后台播放)
import AVFoundation
func configurePlaybackCategory() {
let audioSession = AVAudioSession.sharedInstance()
do {
// 配置分类为 Playback,模式为默认,允许蓝牙输出
try audioSession.setCategory(.playback, mode: .default, options: .allowBluetooth)
// 激活会话
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
} catch {
print("Playback 分类配置/激活失败:(error.localizedDescription)")
}
}
备注:配置后台播放时,需在 Info.plist 中添加 UIBackgroundModes 数组,添加 audio 字段,否则退到后台后音频会立即停止。
适用场景:音乐播放器、视频播放器、有声书APP。
(2)AVAudioSessionCategoryRecord —— 纯录音场景(推荐录音/语音APP)
核心作用:用于仅录制音频的场景(如录音APP、语音备忘录)。
关键特性:
- 会强制抢占所有音频资源,其他正在播放的音频APP会立即暂停。
- 不支持后台录音(除非配置后台模式,但需注意隐私权限,且iOS对后台录音有严格限制)。
- 必须请求麦克风权限(Info.plist 配置
NSMicrophoneUsageDescription)。 - 静音开关不影响录音(即使手机静音,麦克风依然可以正常录音)。
配置代码(录音APP场景)
// OC 配置:纯录音(需先请求麦克风权限)
#import <AVFoundation/AVFoundation.h>
- (void)configureRecordCategory {
// 1. 请求麦克风权限
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
if (!granted) {
NSLog(@"麦克风权限未授权,无法录音");
return;
}
// 2. 配置录音分类
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
[audioSession setCategory:AVAudioSessionCategoryRecord
mode:AVAudioSessionModeDefault
options:0
error:&error];
if (error) {
NSLog(@"Record 分类配置失败:%@", error.localizedDescription);
return;
}
// 3. 激活会话
[audioSession setActive:YES error:&error];
if (error) {
NSLog(@"会话激活失败:%@", error.localizedDescription);
}
}];
}
// Swift 配置:纯录音(需先请求麦克风权限)
import AVFoundation
func configureRecordCategory() {
// 1. 请求麦克风权限
AVCaptureDevice.requestAccess(for: .audio) { granted in
guard granted else {
print("麦克风权限未授权,无法录音")
return
}
// 2. 配置录音分类
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.record, mode: .default)
// 3. 激活会话
try audioSession.setActive(true)
} catch {
print("Record 分类配置/激活失败:(error.localizedDescription)")
}
}
}
备注:Info.plist 需添加 NSMicrophoneUsageDescription(描述麦克风使用场景,如“用于录制语音”),否则会崩溃。
适用场景:录音APP、语音备忘录、语音输入功能。
(3)AVAudioSessionCategoryPlayAndRecord —— 播放+录音场景(推荐语音通话/直播APP)
核心作用:用于同时需要播放和录制音频的场景,是语音通话、直播、K歌APP的核心分类。
关键特性:
- 支持同时使用扬声器/耳机(播放)和麦克风(录音)。
- 默认不与其他音频APP共存(会抢占资源),但可通过配置选项允许共存。
- 支持后台播放/录音(需配置后台模式)。
- 必须请求麦克风权限,静音开关不影响录音,但会影响播放(静音模式下扬声器无声音)。
配置代码(语音通话场景,最常用)
// OC 配置:语音通话(支持蓝牙、默认扬声器输出)
#import <AVFoundation/AVFoundation.h>
- (void)configurePlayAndRecordCategory {
// 1. 请求麦克风权限
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
if (!granted) {
NSLog(@"麦克风权限未授权,无法进行语音通话");
return;
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
// 配置分类:PlayAndRecord,模式:VoiceChat(语音通话优化)
// 选项:允许蓝牙、默认扬声器输出、允许与其他音频混音
AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionAllowBluetooth |
AVAudioSessionCategoryOptionDefaultToSpeaker |
AVAudioSessionCategoryOptionMixWithOthers;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
mode:AVAudioSessionModeVoiceChat
options:options
error:&error];
if (error) {
NSLog(@"PlayAndRecord 分类配置失败:%@", error.localizedDescription);
return;
}
// 激活会话,退出时通知其他APP恢复音频
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
if (error) {
NSLog(@"会话激活失败:%@", error.localizedDescription);
}
}];
}
// Swift 配置:语音通话(支持蓝牙、默认扬声器输出)
import AVFoundation
func configurePlayAndRecordCategory() {
// 1. 请求麦克风权限
AVCaptureDevice.requestAccess(for: .audio) { granted in
guard granted else {
print("麦克风权限未授权,无法进行语音通话")
return
}
let audioSession = AVAudioSession.sharedInstance()
do {
// 配置分类:PlayAndRecord,模式:VoiceChat(语音通话优化)
// 选项:允许蓝牙、默认扬声器输出、允许与其他音频混音
let options: AVAudioSession.CategoryOptions = [.allowBluetooth, .defaultToSpeaker, .mixWithOthers]
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: options)
// 激活会话,退出时通知其他APP恢复音频
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
} catch {
print("PlayAndRecord 分类配置/激活失败:(error.localizedDescription)")
}
}
}
补充:该分类可通过 AVAudioSessionCategoryOptionMixWithOthers 选项实现与其他音频APP共存(如语音通话时允许背景音乐播放),适合直播、K歌场景。同时,语音通话场景下搭配 AVAudioSessionModeVoiceChat 模式,可自动开启回声消除、降噪功能,提升通话清晰度。
适用场景:语音通话(微信/QQ电话)、直播APP、K歌APP、语音助手。
(4)AVAudioSessionCategoryAmbient —— 背景音场景(推荐游戏/工具APP)
核心作用:用于非核心的背景音频(如游戏背景音乐、工具APP的提示音),优先级最低。
关键特性:
- 允许与其他音频APP共存(比如用户打开音乐APP播放音乐,你的APP的背景音会混合播放,或被压低音量)。
- 不支持后台播放(APP退到后台后,音频会立即停止)。
- 受静音开关控制(静音模式下,音频会静音)。
配置代码(游戏背景音场景)
// OC 配置:游戏背景音(允许与其他音频共存)
#import <AVFoundation/AVFoundation.h>
- (void)configureAmbientCategory {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
// 配置分类为 Ambient,无需额外选项(默认允许共存)
[audioSession setCategory:AVAudioSessionCategoryAmbient
mode:AVAudioSessionModeDefault
options:0
error:&error];
if (error) {
NSLog(@"Ambient 分类配置失败:%@", error.localizedDescription);
return;
}
// 激活会话(背景音场景可延迟激活,避免过早抢占资源)
[audioSession setActive:YES error:&error];
if (error) {
NSLog(@"会话激活失败:%@", error.localizedDescription);
}
}
// Swift 配置:游戏背景音(允许与其他音频共存)
import AVFoundation
func configureAmbientCategory() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.ambient, mode: .default)
try audioSession.setActive(true)
} catch {
print("Ambient 分类配置/激活失败:(error.localizedDescription)")
}
}
备注:该分类优先级最低,不会抢占其他APP的音频,适合作为“辅助音频”(如游戏音效、APP提示音),用户打开音乐播放器时,背景音会自动混合播放或被压低音量。
适用场景:游戏背景音乐、APP操作提示音、闹钟APP的背景音。
2. 其他补充分类(了解即可)
- AVAudioSessionCategorySoloAmbient(默认分类):与 Ambient 类似,但会抢占其他音频资源(其他APP音频暂停),不支持后台播放,适合简单的提示音场景。
- AVAudioSessionCategoryMultiRoute:多路由输出,允许音频同时输出到多个设备(如同时连接耳机和蓝牙音箱,两者都能播放),适合专业音频场景。
- AVAudioSessionCategoryAudioProcessing:用于音频处理(无播放/录音,仅处理音频数据),适合音频编辑APP。
多路由分类配置代码(专业场景)
// OC 配置:多路由输出(专业音频场景)
- (void)configureMultiRouteCategory {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
[audioSession setCategory:AVAudioSessionCategoryMultiRoute
mode:AVAudioSessionModeDefault
options:0
error:&error];
if (error) {
NSLog(@"MultiRoute 分类配置失败:%@", error.localizedDescription);
}
}
3. 分类选型核心原则
记住一个核心逻辑:根据APP的“核心音频行为”选择分类,不要过度配置。比如:
- 只播放音乐 → 选 Playback,不要选 PlayAndRecord(浪费资源,还需额外请求麦克风权限)。
- 语音通话 → 选 PlayAndRecord,不要选 Playback+Record 组合(分类本身已支持双功能)。
- 游戏背景音 → 选 Ambient,不要选 Playback(避免抢占用户的音乐播放)。
补充:实际开发中,可先通过 audioSession.availableCategories 读取当前设备支持的分类,避免配置不兼容的分类导致失败。
三、核心机制2:音频会话模式(Mode)—— 优化特定场景的“补充规则”
模式(Mode)是对分类的“补充优化”,它不能单独使用,必须搭配分类一起配置,用于适配特定的音频场景(如语音通话、视频通话、录音),让音频行为更贴合场景需求。
简单来说,分类定义了“能做什么”(播放/录音/共存),模式定义了“怎么做更好”(适配特定场景的音频优化)。下面讲解常用模式及搭配逻辑,附上对应搭配代码。
1. 常用模式及搭配场景
(1)AVAudioSessionModeDefault —— 默认模式(通用)
所有分类都可以搭配此模式,无额外优化,适用于大多数通用场景(如普通音乐播放、普通录音)。
搭配示例:Playback + Default(音乐播放器)、Record + Default(普通录音)。
搭配代码(普通音乐播放)
// OC:Playback + Default 搭配(普通音乐播放)
- (void)configurePlaybackWithDefaultMode {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback
mode:AVAudioSessionModeDefault
options:AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
if (error) {
NSLog(@"配置失败:%@", error.localizedDescription);
}
}
(2)AVAudioSessionModeVoiceChat —— 语音通话模式(重点)
核心优化:针对实时语音通话(如微信电话、手机通话),优化音频质量(降低延迟、降噪),并自动适配路由(插入耳机时切换到耳机,拔出时切换到扬声器)。
搭配要求:仅支持 PlayAndRecord 分类(因为语音通话需要同时播放和录音)。
关键特性:自动启用“回声消除”“降噪”功能,提升语音清晰度;支持蓝牙耳机的通话模式。
搭配代码(实时语音通话)
// Swift:PlayAndRecord + VoiceChat 搭配(语音通话)
func configureVoiceChatMode() {
let audioSession = AVAudioSession.sharedInstance()
do {
// 仅能搭配 PlayAndRecord 分类
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.allowBluetooth, .defaultToSpeaker])
try audioSession.setActive(true)
} catch {
print("语音通话模式配置失败:(error.localizedDescription)")
}
}
补充:该模式下,系统会自动优化语音传输延迟,开启回声消除和降噪,适合微信语音、手机通话等实时场景,搭配 AVAudioSessionCategoryOptionAllowBluetooth 可支持蓝牙耳机通话。
(3)AVAudioSessionModeVideoChat —— 视频通话模式
核心优化:针对视频通话(如微信视频、FaceTime),在语音通话优化的基础上,适配视频场景的音频同步(降低音视频延迟)。
搭配要求:仅支持 PlayAndRecord 分类,与 VoiceChat 类似,但更侧重音视频同步。
搭配代码(视频通话)
// OC:PlayAndRecord + VideoChat 搭配(视频通话)
- (void)configureVideoChatMode {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionDefaultToSpeaker;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
mode:AVAudioSessionModeVideoChat
options:options
error:&error];
if (error) {
NSLog(@"视频通话模式配置失败:%@", error.localizedDescription);
}
}
(4)AVAudioSessionModeMeasurement —— 精准录音模式
核心优化:针对精准录音(如音频分析、专业录音),关闭所有音频处理(降噪、回声消除),保留原始音频数据,确保录音的准确性。
搭配要求:支持 PlayAndRecord、Record 分类。
适用场景:音频分析APP、专业录音APP。
搭配代码(专业录音)
// Swift:Record + Measurement 搭配(精准录音)
func configureMeasurementMode() {
let audioSession = AVAudioSession.sharedInstance()
do {
// 搭配 Record 分类,关闭所有音频处理,保留原始数据
try audioSession.setCategory(.record, mode: .measurement)
try audioSession.setActive(true)
} catch {
print("精准录音模式配置失败:(error.localizedDescription)")
}
}
(5)AVAudioSessionModeMoviePlayback —— 视频播放模式
核心优化:针对视频播放,优化音频与视频的同步,提升播放流畅度,支持多声道音频。
搭配要求:仅支持 Playback 分类。
搭配代码(视频播放)
// OC:Playback + MoviePlayback 搭配(视频播放)
- (void)configureMoviePlaybackMode {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback
mode:AVAudioSessionModeMoviePlayback
options:AVAudioSessionCategoryOptionAllowAirPlay
error:&error];
if (error) {
NSLog(@"视频播放模式配置失败:%@", error.localizedDescription);
}
}
补充:该模式优化了音视频同步逻辑,支持多声道音频和AirPlay输出,适合视频播放器、影视APP场景。
2. 模式搭配核心原则
- 模式必须与分类匹配,不可随意搭配(如 VoiceChat 不能搭配 Playback 分类)。
- 无需优化的场景,用 Default 模式即可,不要画蛇添足(如普通音乐播放,无需搭配 MoviePlayback)。
- 特定场景优先用对应模式(如语音通话用 VoiceChat,精准录音用 Measurement),能大幅提升用户体验。
四、核心机制3:激活策略 —— 让音频会话“生效”的关键操作
配置好分类和模式后,必须通过“激活”操作,让音频会话生效。激活(activate)是 AVAudioSession 与系统建立连接的过程,也是音频资源分配的触发点。
很多开发者配置完分类和模式后,发现音频没声音,大概率是没有激活会话,或激活时机、方式错误。下面讲解激活的核心要点、时机和注意事项,附上完整激活代码。
1. 激活的核心API(iOS 10+ 推荐)
// 获取单例
AVAudioSession *session = [AVAudioSession sharedInstance];
// 配置分类和模式(示例:语音通话场景)
NSError *error = nil;
[session setCategory:AVAudioSessionCategoryPlayAndRecord
mode:AVAudioSessionModeVoiceChat
options:AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
if (error) {
NSLog(@"分类模式配置失败:%@", error.localizedDescription);
return;
}
// 核心激活API(iOS 10+),带选项控制
// 选项说明:
// AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation:退出激活时,通知其他APP恢复音频
// AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation:激活时,不中断其他APP音频(需配合分类options)
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
if (error) {
NSLog(@"会话激活失败:%@", error.localizedDescription);
} else {
NSLog(@"会话激活成功,可正常播放/录音");
}
// 取消激活(退出音频场景时调用)
[session setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
// Swift 核心激活API(iOS 10+)
let session = AVAudioSession.sharedInstance()
do {
// 配置分类和模式
try session.setCategory(.playAndRecord, mode: .voiceChat, options: .allowBluetooth)
// 激活会话,退出时通知其他APP恢复音频
try session.setActive(true, options: .notifyOthersOnDeactivation)
print("会话激活成功,可正常播放/录音")
// 取消激活(退出音频场景时调用)
// try session.setActive(false, options: .notifyOthersOnDeactivation)
} catch {
print("会话配置/激活失败:(error.localizedDescription)")
}
2. 激活的核心时机(避坑关键)
激活时机直接影响用户体验和功能稳定性,推荐以下3种核心时机,附上对应代码逻辑:
(1)延迟激活(推荐)
不要在APP启动时就激活会话,避免过早抢占其他APP的音频资源(如用户正在听音乐,打开你的APP就中断音乐,体验极差)。建议在“即将播放/录音”时激活。
// OC:延迟激活(点击播放按钮时激活)
- (IBAction)playButtonClick:(UIButton *)sender {
// 1. 配置分类和模式(提前配置,或首次点击时配置)
[self configurePlaybackCategory];
// 2. 激活会话(即将播放时激活)
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
if (error) {
NSLog(@"激活失败:%@", error.localizedDescription);
return;
}
// 3. 开始播放音频
[self.audioPlayer play];
}
(2)退出场景时取消激活
当APP退出音频场景(如关闭播放页面、退出录音),必须取消激活会话,避免占用音频资源,同时通知其他APP恢复音频。
// Swift:退出页面时取消激活
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let session = AVAudioSession.sharedInstance()
do {
// 取消激活,通知其他APP恢复音频
try session.setActive(false, options: .notifyOthersOnDeactivation)
print("会话已取消激活")
} catch {
print("取消激活失败:(error.localizedDescription)")
}
}
(3)中断后重新激活
当音频会话被系统中断(如来电、闹钟),中断结束后需重新激活会话,恢复音频播放/录音。需先监听中断事件,再执行重新激活。
// OC:监听中断事件,重新激活会话
#import <AVFoundation/AVFoundation.h>
@interface ViewController () <AVAudioSessionDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置代理,监听中断事件
AVAudioSession *session = [AVAudioSession sharedInstance];
session.delegate = self;
}
// 监听音频会话中断(来电、闹钟等)
- (void)audioSessionInterruptionNotification:(NSNotification *)notification {
NSInteger type = [[notification.userInfo objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
// 中断结束,重新激活会话
if (type == AVAudioSessionInterruptionTypeEnded) {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error = nil;
[session setActive:YES error:&error];
if (!error) {
NSLog(@"中断结束,重新激活会话,恢复播放");
// 恢复播放/录音
[self.audioPlayer play];
}
}
}
3. 激活的注意事项(避坑重点)
- 同一时间只能有一个会话处于激活状态,若多个地方调用激活,会导致冲突(报错:AVAudioSessionErrorCodeResourceBusy)。
- 激活前必须先配置分类和模式,否则会激活失败(报错:AVAudioSessionErrorCodeNotConfigured)。
- 录音场景激活前,必须先获取麦克风权限,否则会崩溃或激活失败。
- 取消激活时,建议使用
AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation选项,提升用户体验(如退出APP后,恢复之前的音乐播放)。 - iOS 14+ 需注意:多次频繁激活/取消激活,可能触发系统Bug,建议添加状态判断,避免重复操作。
五、实战避坑:常见问题及解决方案(附代码)
结合实际开发中高频遇到的问题,整理4个核心避坑点,附上解决方案和代码,帮你快速排查问题。
1. 问题1:播放没声音(最常见)
核心原因:未激活会话、分类配置错误、静音开关影响、路由错误。
// Swift:排查播放没声音的核心代码
func checkNoSoundIssue() {
let session = AVAudioSession.sharedInstance()
// 1. 检查会话是否激活
guard session.isActive else {
print("会话未激活,尝试重新激活")
do { try session.setActive(true) } catch { print(error) }
return
}
// 2. 检查分类是否正确(纯播放需用 Playback)
guard session.category == .playback else {
print("分类配置错误,重新配置 Playback 分类")
do { try session.setCategory(.playback, mode: .default) } catch { print(error) }
return
}
// 3. 检查静音开关状态(Playback 分类,静音模式下耳机可正常播放)
let isSilent = session.category == .playback && !session.isOtherAudioPlaying && session.outputVolume == 0
if isSilent {
print("当前处于静音模式,连接耳机可正常播放")
}
// 4. 检查音频路由(是否输出到扬声器/耳机)
print("当前音频输出路由:(session.currentRoute.outputs.first?.portType.rawValue ?? "未知")")
}
2. 问题2:录音失败/无声音
核心原因:未获取麦克风权限、分类错误(未用 Record/PlayAndRecord)、会话未激活。
// OC:录音失败排查代码
- (void)checkRecordIssue {
// 1. 检查麦克风权限
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
if (status != AVAuthorizationStatusAuthorized) {
NSLog(@"麦克风权限未授权,请求权限");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {}];
return;
}
// 2. 检查分类(录音需用 Record 或 PlayAndRecord)
AVAudioSession *session = [AVAudioSession sharedInstance];
if (![session.category isEqualToString:AVAudioSessionCategoryRecord] &&
![session.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
NSLog(@"分类错误,重新配置录音分类");
[self configureRecordCategory];
return;
}
// 3. 检查会话是否激活
if (!session.isActive) {
NSLog(@"会话未激活,重新激活");
[session setActive:YES error:nil];
}
}
3. 问题3:后台播放中断
核心原因:未配置后台模式、退出时未取消激活、分类不支持后台播放。
解决方案:1. Info.plist 配置 UIBackgroundModes → audio;2. 用 Playback/PlayAndRecord 分类;3. 后台播放时保持会话激活。
4. 问题4:与其他音频APP冲突(打开APP,其他APP音频暂停)
核心原因:分类默认不允许混音,未配置 AVAudioSessionCategoryOptionMixWithOthers 选项。
// Swift:允许与其他音频APP共存(混音)
func configureMixWithOthers() {
let session = AVAudioSession.sharedInstance()
do {
// 配置分类时,添加 mixWithOthers 选项
try session.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .allowBluetooth])
try session.setActive(true)
print("已配置混音,可与其他音频APP共存")
} catch {
print("配置混音失败:(error.localizedDescription)")
}
}
补充:该配置适合直播、K歌等需要同时播放背景音乐和录音的场景,需注意部分分类(如 Record)不支持混音选项。
六、总结
AVAudioSession 的核心机制,本质是“分类定义基础行为,模式优化特定场景,激活触发资源分配”。掌握这三者的搭配逻辑,就能解决绝大多数iOS音频开发中的问题。
核心总结:
- 分类:选对场景(纯播放→Playback,录音→Record,通话→PlayAndRecord),不盲目配置。
- 模式:特定场景用对应模式(语音通话→VoiceChat,视频播放→MoviePlayback),通用场景用Default。
- 激活:延迟激活、及时取消、中断后重新激活,避免资源冲突和用户体验问题。
本文所有代码均可直接复制到项目中复用,建议根据自己的APP场景(播放/录音/通话),选择对应的分类、模式和激活策略,同时注意权限配置和避坑点。
最后提醒:音频开发的核心是“贴合用户场景”,不同场景的配置差异较大,建议开发时多测试不同场景(静音模式、后台、耳机切换、来电中断),确保功能稳定。