音频类AVAudioSession全解

180 阅读10分钟

1. AVAudioSession 核心概念

AVAudioSession 是 Apple AVFoundation 框架中的一个核心类,用于管理 iOS、iPadOS 和 macOS 应用中的音频会话。它充当应用与操作系统(以及底层音频硬件)之间的中介,帮助应用声明其音频使用意图,从而允许系统协调多个应用的音频行为。例如,当应用播放声音时,它需要考虑其他应用(如音乐播放器)的音频输出、设备的静音开关、屏幕锁定状态等。

AVAudioSession 的主要目的是:

  • 定义音频类别(Category),以指定应用的音频行为(如播放、录制或两者兼顾)。
  • 配置模式(Mode)和选项(Options),以细化音频处理方式。
  • 处理音频路由(Route),如切换到扬声器、耳机或蓝牙设备。
  • 管理激活和中断(如来电中断音频播放)。

自 iOS 3.0 引入以来,AVAudioSession 不断演进。到 2025 年,它支持更多功能,如空间音频(Spatial Audio)、立体声录制和蓝牙 A2DP 支持的更新(例如,allowBluetooth 选项在 Xcode 26 中被标记为弃用)。

应用在使用 AVAudioSession 时,必须导入 AVFoundation 框架:

import AVFoundation

AVAudioSession 是单例设计,通过 AVAudioSession.sharedInstance() 获取实例。所有配置都应在主线程或适当的上下文中进行,以避免并发问题。

2. 使用方法概述

2.1 初始化和获取实例

AVAudioSession 是单例,无需手动初始化:

let audioSession = AVAudioSession.sharedInstance()

2.2 配置音频会话

配置主要通过设置类别、模式和选项完成。这些设置定义了应用的音频行为,例如是否允许与其他应用混合播放、是否忽略静音开关等。

  • 设置类别(Category):使用 setCategory(_:mode:options:) 方法。这是一个抛出异常的方法,因此需在 do-try-catch 块中使用。 示例:

    do {
        try audioSession.setCategory(.playback, mode: .default, options: [])
    } catch {
        print("设置类别失败: \(error)")
    }
    

    类别定义了音频的基本行为(如播放或录制)。从 Swift 4.2 开始,类别是结构体 AVAudioSession.Category,而非字符串常量。

  • 设置模式(Mode):进一步细化类别,例如语音聊天模式。 示例:

    try audioSession.setMode(.voiceChat)
    
  • 选项(Options):附加标志,如允许蓝牙或默认到扬声器。 示例:添加 .mixWithOthers 以允许与其他应用混合音频。

2.3 激活和停用会话

激活会话以开始使用音频硬件:

do {
    try audioSession.setActive(true)
} catch {
    print("激活失败: \(error)")
}
  • 使用 setActive(false) 停用会话,以释放资源。
  • 可选参数:setActive(_:with:),如 .notifyOthersOnDeactivation 以通知其他应用。

激活失败常见原因包括权限不足或硬件冲突。应用应在需要音频时激活,并在完成后停用,以节省电池和资源。

2.4 处理权限

对于录制音频,需要请求麦克风权限:

audioSession.requestRecordPermission { granted in
    if granted {
        // 开始录制
    } else {
        // 处理拒绝
    }
}

2.5 处理中断和路由变化

注册通知:

  • AVAudioSession.interruptionNotification:处理来电等中断。
  • AVAudioSession.routeChangeNotification:处理耳机插入等路由变化。

示例:

NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: AVAudioSession.interruptionNotification, object: nil)

2.6 示例:播放音频忽略静音开关

do {
    let session = AVAudioSession.sharedInstance()
    try session.setCategory(.playback, mode: .default, options: [])
    try session.setActive(true)
    // 现在播放音频
} catch {
    print(error)
}

3. 所有属性的意义

AVAudioSession 提供了众多只读和可设置属性,用于查询和配置音频状态。以下是完整列表,按功能分组。属性类型为 Swift 类型。

3.1 会话配置属性

  • category: AVAudioSession.Category
    当前音频会话类别。只读,反映 setCategory 设置的值。意义:定义音频的基本用途,如 .playback(播放音乐,忽略静音开关)或 .record(仅录制)。

  • mode: AVAudioSession.Mode
    当前模式。只读。意义:细化类别,例如 .voiceChat 用于 VoIP,支持回声消除。

  • categoryOptions: AVAudioSession.CategoryOptions
    当前选项。只读。意义:附加行为,如 .allowBluetooth(允许蓝牙 A2DP,但已弃用)或 .mixWithOthers(允许与其他应用混合音频)。

  • availableCategories: [AVAudioSession.Category]
    设备支持的类别列表。只读。意义:查询设备能力,例如某些设备不支持 .multiRoute。

  • availableModes: [AVAudioSession.Mode]
    设备支持的模式列表。只读。意义:检查可用模式,如 .spatialAudio 用于空间音频。

3.2 路由和端口属性

  • currentRoute: AVAudioSession.RouteDescription
    当前音频路由。只读。意义:描述输入/输出端口,如内置扬声器或耳机。包含 inputs 和 outputs 数组。

  • preferredInput: AVAudioSession.PortDescription?
    首选输入端口。可设置。意义:指定首选麦克风,如外部设备。

  • availableInputs: [AVAudioSession.PortDescription]?
    可用输入端口列表。只读。意义:列出所有麦克风端口,如内置麦克风或蓝牙。

  • inputDataSources: [AVAudioSession.DataSourceDescription]?
    输入数据源列表。只读。意义:详细输入选项,如麦克风方向模式(.cardioid 用于定向拾音)。

  • inputDataSource: AVAudioSession.DataSourceDescription?
    当前输入数据源。可设置。意义:选择特定数据源,如立体声录制。

  • outputDataSources: [AVAudioSession.DataSourceDescription]?
    输出数据源列表。只读。意义:类似输入,但用于输出设备。

  • outputDataSource: AVAudioSession.DataSourceDescription?
    当前输出数据源。可设置。意义:配置输出,如扬声器模式。

3.3 音频质量和性能属性

  • sampleRate: Double
    当前采样率(Hz)。只读。意义:音频处理的采样频率,通常 44100 Hz。

  • preferredSampleRate: Double
    首选采样率。可设置。意义:尝试设置自定义采样率,用于高质量录制。

  • inputNumberOfChannels: Int
    输入通道数。只读。意义:如 1(单声道)或 2(立体声)。

  • outputNumberOfChannels: Int
    输出通道数。只读。意义:类似输入,支持多通道音频。

  • preferredInputNumberOfChannels: Int
    首选输入通道数。可设置。意义:请求立体声录制等。

  • preferredOutputNumberOfChannels: Int
    首选输出通道数。可设置。意义:用于多通道播放。

  • inputGain: Float
    当前输入增益(0.0-1.0)。只读。意义:麦克风灵敏度。

  • isInputGainSettable: Bool
    是否可设置输入增益。只读。意义:检查硬件支持。

  • outputVolume: Float
    当前输出音量(0.0-1.0)。只读。意义:系统音量级别。

  • inputLatency: TimeInterval
    输入延迟(秒)。只读。意义:从麦克风到应用的延迟,用于实时音频。

  • outputLatency: TimeInterval
    输出延迟(秒)。只读。意义:从应用到扬声器的延迟。

  • ioBufferDuration: TimeInterval
    I/O 缓冲区持续时间(秒)。只读。意义:缓冲区大小,影响延迟。

  • preferredIOBufferDuration: TimeInterval
    首选 I/O 缓冲区持续时间。可设置。意义:优化低延迟应用,如游戏。

3.4 状态和提示属性

  • isInputAvailable: Bool
    是否有输入设备可用。只读。意义:检查麦克风存在。

  • promptStyle: AVAudioSession.PromptStyle
    提示样式。只读。意义:如 .none 或 .short,用于系统提示音。

  • recordPermission: AVAudioSession.RecordPermission
    录制权限状态。只读。意义:.granted、.denied 或 .undetermined。

  • secondaryAudioShouldBeSilencedHint: Bool
    是否应静音次要音频。只读。意义:提示系统静音背景音频。

  • allowHapticsAndSystemSoundsDuringRecording: Bool
    录制时允许触觉和系统声音。可设置。意义:允许录制期间的振动和系统音(iOS 13+)。

  • renderingMode: AVAudioSession.RenderingMode
    渲染模式。只读。意义:如 .stereo 或 .spatialAudio,用于多通道或空间音频。

  • ioType: AVAudioSession.IOType
    I/O 类型。只读。意义:.aggregated 或 .nonAggregated,用于 Live Photos 等(iOS 10+)。

4. 所有方法详解

以下是主要方法,按类别分组。所有抛出方法需 try-catch 处理。

4.1 配置方法

  • setCategory(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode, options: AVAudioSession.CategoryOptions) throws
    设置类别、模式和选项。意义:核心配置方法,用于定义音频行为。

  • setMode(_ mode: AVAudioSession.Mode) throws
    单独设置模式。

  • setCategory(_ category: AVAudioSession.Category) throws
    简化版本,仅设置类别(旧 API 兼容)。

4.2 激活方法

  • setActive(_ flag: Bool) throws
    激活或停用会话。

  • setActive(_ flag: Bool, with options: AVAudioSession.SetActiveOptions) throws
    带选项,如通知其他应用。

4.3 权限方法

  • requestRecordPermission(_ response: @escaping (Bool) -> Void)
    请求录制权限,异步回调。

4.4 首选设置方法

  • setPreferredSampleRate(_ sampleRate: Double) throws
    设置首选采样率。

  • setPreferredIOBufferDuration(_ duration: TimeInterval) throws
    设置首选缓冲区时长。

  • setPreferredInputNumberOfChannels(_ count: Int) throws
    设置首选输入通道数。

  • setPreferredOutputNumberOfChannels(_ count: Int) throws
    设置首选输出通道数。

  • setPreferredInput(_ inPort: AVAudioSession.PortDescription?) throws
    设置首选输入端口。

  • setInputGain(_ gain: Float) throws
    设置输入增益。

  • setInputDataSource(_ dataSource: AVAudioSession.DataSourceDescription?) throws
    设置输入数据源。

  • setOutputDataSource(_ dataSource: AVAudioSession.DataSourceDescription?) throws
    设置输出数据源。

4.5 路由控制方法

  • overrideOutputAudioPort(_ portOverride: AVAudioSession.PortOverride) throws
    覆盖输出端口,如强制到扬声器。

4.6 其他方法

  • setAllowHapticsAndSystemSoundsDuringRecording(_ flag: Bool) throws
    允许录制时触觉和系统音。

5. 相关常量、枚举和通知

  • AVAudioSession.Category:枚举,如 .ambient(环境音,可混合)、.soloAmbient(独占环境音)、.playback(播放)、.record(录制)、.playAndRecord(播放和录制)、.multiRoute(多路由)。

  • AVAudioSession.Mode:如 .default、.voiceChat、.videoRecording、.measurement(测量)。

  • AVAudioSession.CategoryOptions:位掩码,如 .duckOthers(降低其他音频)、.interruptSpokenAudioAndMixWithOthers、.allowAirPlay 等。

  • AVAudioSession.Port:端口类型,如 .builtInMic、.headphones、.bluetoothA2DP。

  • 通知

    • AVAudioSession.interruptionNotification:音频中断。
    • AVAudioSession.routeChangeNotification:路由变化。
    • AVAudioSession.mediaServicesWereLostNotification:媒体服务丢失。
    • AVAudioSession.mediaServicesWereResetNotification:媒体服务重置。
    • AVAudioSession.silenceSecondaryAudioHintNotification:次要音频静音提示。

6. 最佳实践

  • 最佳实践
    • 在应用启动或需要音频时尽早配置会话。
    • 处理异常:激活失败可能由于权限或冲突,使用日志记录错误。
    • 监听通知:始终处理中断和路由变化,以恢复音频。
    • 优化延迟:对于实时应用,设置较低的 preferredIOBufferDuration。
    • 权限管理:在使用录制前检查 recordPermission。
    • 后台音频:为播放添加 UIBackgroundModes 中的 audio 键。
    • 测试不同设备:路由行为在 iPhone、iPad 和带蓝牙设备上不同。

枚举的详细解读

以下是对 AVAudioSession 中所有主要枚举的逐一解读,包括每个案例的意义和使用方法。这些枚举定义了音频会话的各种行为配置。

AVAudioSession.Category

音频类别定义了应用的音频用途和与其他应用的交互方式。使用 setCategory(_:mode:options:) 设置。默认是 .soloAmbient

  • .ambient:背景音频,受静音开关影响,不中断其他应用。意义:用于非关键音频,如游戏背景音。使用方法:适合混音场景,例如在播放音乐时添加音效。示例:try session.setCategory(.ambient)
  • .soloAmbient(默认):独占背景音频,受静音开关影响,中断其他应用。意义:用于独占音频,但仍受设备静音控制。使用方法:适用于需要中断其他音频但尊重静音开关的应用,如简单游戏。
  • .playback:播放音频,不受静音开关影响,支持后台播放。意义:用于媒体播放器,确保音频在静音模式下仍可播放。使用方法:启用后台音频模式,并在 Info.plist 中添加 UIBackgroundModes。示例:音乐 App。
  • .record:仅录制音频。意义:专用于录音,不涉及播放。使用方法:结合 AVAudioRecorder,用于语音备忘录 App。
  • .playAndRecord:同时播放和录制,支持耳机等。意义:用于 VoIP 或视频通话,支持双向音频。使用方法:允许蓝牙设备,示例:视频会议 App。
  • .multiRoute:多路由音频输出。意义:支持多个输出设备,如 AirPlay 和 USB 接口。使用方法:用于专业音频应用,需要自定义路由。

AVAudioSession.Mode

模式进一步细化类别,优化特定场景。使用 setCategory(_:mode:options:) 设置。默认是 .default

  • .default:默认模式,无特殊优化。意义:适用于大多数场景。使用方法:作为通用模式,与任何类别兼容。
  • .voiceChat:用于 VoIP 语音聊天。意义:优化延迟和回声消除。使用方法:结合 .playAndRecord,示例:电话 App。
  • .videoChat:用于视频通话。意义:优化视频同步和音频质量。使用方法:如 FaceTime,支持视频录制。
  • .gameChat:用于游戏语音聊天。意义:低延迟,适合实时游戏。使用方法:Game Kit 集成。
  • .videoRecording:优化视频录制麦克风。意义:选择最佳麦克风(如后置)。使用方法:结合 .record.playAndRecord,示例:相机 App。
  • .measurement:用于音频测量。意义:最小信号处理,确保准确数据。使用方法:音频分析工具。
  • .moviePlayback:优化电影播放。意义:增强信号处理,如动态范围。使用方法:视频播放器。
  • .spokenAudio:用于有声书或播客。意义:允许暂停其他音频。使用方法:结合 .playback
  • .voicePrompt:用于文本到语音提示。意义:如 Siri,响应系统音频。使用方法:语音助手。

AVAudioSession.CategoryOptions

选项是位掩码,用于细化类别行为。使用 setCategory(_:mode:options:) 设置。

  • .mixWithOthers:与他人混音。意义:允许与其他应用音频共存。使用方法:背景音乐 App。
  • .duckOthers:压低他人音量。意义:使其他音频变安静。使用方法:导航 App 语音提示。
  • .interruptSpokenAudioAndMixWithOthers:中断口语音频并混音。意义:暂停其他口语内容。使用方法:语音交互。
  • .allowBluetooth:允许蓝牙设备。意义:支持蓝牙耳机(HFP 协议)。使用方法:VoIP。
  • .allowBluetoothA2DP:允许蓝牙 A2DP(高品质)。意义:支持蓝牙立体声。使用方法:音乐播放。
  • .allowAirPlay:允许 AirPlay。意义:无线投射。使用方法:媒体共享。
  • .defaultToSpeaker:默认使用扬声器。意义:忽略接收器,使用内置扬声器。使用方法:免提通话。