文章目录
iOS 通过 AVAudioSession
管理各个 App 对音频硬件 Input
/Ouput
资源的使用。
let audioSession = AVAudioSession.sharedInstance()
do {
// 激活/停用 音频配置
try audioSession.setActive(true)
} catch {
print("Failed to set the audio session configuration")
}
audioSession.otherAudioPlaying // 其他 App 是否在播放音频
1.Categorys
AVAudioSession
将使用音频的场景分成七大类,通过设置 Session
为不同的类别,可以控制:
- 当 App 激活 Session 的时候,是否会打断其他不支持混音的 App 声音
- 当用户触发手机上的“静音”键时或者锁屏时,是否相应静音
- 当前状态是否支持录音
- 当前状态是否支持播放
- 每个 App 启动时都会设置成上面说的默认状态,即其他 App 会被中断同时相应“静音”键的播放模式。
// 获取支持的分类
audioSession.availableCategories
// 设置分类
audioSession.setCategory(.ambient)
audioSession.setCategory(.playback, options: .mixWithOthers)
audioSession.setCategory(.playback, mode: .default)
audioSession.setCategory(.playback, mode: .default, options: .mixWithOthers)
// 当前分类
audioSession.category
有以下7大类别 Categorys
:AVAudioSessionCategory
锁屏/静音 | 不支持混音的App | 录音/播放 | 说明 | 举例 | |
---|---|---|---|---|---|
Ambient | 静音 | 不中断 | 播放 | 可与音乐同时播放 | 游戏背景音乐和QQ音乐共存 |
SoloAmbient | 静音 | 中断 | 播放 | 不希望其他App干扰 | 如:节奏大师 |
Playback | 继续 | 默认中断 | 播放 | 锁屏/静音了还想听音乐 | 如:QQ音乐 |
Record | 继续 | 中断 | YES | 录音时中断其他播放 | 如:微信长按录音 |
PlayAndRecord | 继续 | 默认不中断 | YES | VoIP(通话) | 打电话 |
MultiRoute | 继续 | 中断 | YES | 多种音频输入输出,可将不同音频数据流同时路由到不同输出设备的类别 | 扬声器播放一个音频,耳机播放另一个 |
2.CategoryOptions
// 设置分类和基调
audioSession.setCategory(.playback, options: .mixWithOthers)
// 当前基调
audioSession.categoryOptions
7种基调 Options
: AVAudioSessionCategoryOptions
当前设置的Options, 是多个|(或运算)的结果
作用 | 适用Category | 举例 | |
---|---|---|---|
MixWithOthers | 是否可以和其他后台App进行混音 | PlayAndRecord/Playback/MultiRoute | 实现背景音乐和QQ音乐共存 |
DuckOthers | 是否压低其App声音 | Ambient/PlayAndRecord/Playback/MultiRoute | 实现通话场景, 降低QQ音乐的音量 |
AllowBluetooth | 是否支持蓝牙耳机 | Record/PlayAndRecord | 需要支持蓝牙耳机 |
DefaultToSpeaker | 是否默认用免提声音 | PlayAndRecord | 在VoIP模式下,希望默认打开免提功能 |
InterruptSpokenAudioAndMixWithOthers | iOS9, 播放此应用的音频内容时,是否暂停来自其他应用的连续语音内容 | PlayAndRecord/Playback/MultiRoute | |
AllowBluetoothA2DP | 支持立体声蓝牙 | PlayAndRecord | |
AllowAirPlay | 支持远程AirPlay | PlayAndRecord | 如果清除此选项,则AirPlay设备不会显示为可用的音频输出路线。 如果设置了此选项,这些设备将显示为可用的输出路径。 |
3.Modes
// 获取支持的模式
audioSession.availableModes
// 设置模式
audioSession.setMode(.default)
audioSession.setCategory(.playback, mode: .default)
audioSession.setCategory(.playback, mode: .default, options: .mixWithOthers)
// 获取当前模式
audioSession.mode
7大模式 Modes
: AVAudioSessionMode
场景 | 适用Category | 说明 | |
---|---|---|---|
Default | 默认场景 | 所有Category | 每种类别默认的就是这个模式,所有要想还原的话,就设置成这个模式 |
VoiceChat | VoIP | PlayAndRecord | 此时系统会选择最佳的输入设备,比如插上耳机就使用耳机上的麦克风进行采集。此时有个副作用,他会设置类别的选项为AllowBluetooth从而支持蓝牙耳机 |
GameChat | 游戏录制, 由GKVoiceChat自动设置, 无需手动调用 | PlayAndRecord | 游戏录制, 游戏App的采集和播放,比如“GKVoiceChat”对象 |
VideoRecording | 录制视频时 | Record/PlayAndRecord | 视频录制 |
Measurement | 最小系统 | Record/PlayAndRecord/Playback | 如果应用正在执行音频输入或输出的测试。此模式适用于需要将输入和输出信号的系统提供的信号处理量将至最低的应用程序。如果在具有多个内置麦克风的设备上录制,则使用主麦克风。 |
MoviePlayback | 视频播放 | Playback | 视频播放 |
VideoChat | 视频通话 | PlayAndRecord | 视频通话,比如QQ视频、FaceTime。此时系统也会选择最佳的输入设备,比如插上耳机就使用耳机上的麦克风进行采集并且会设置类别的选项为 AllowBluetooth 和 DefaultToSpeaker |
SpokenAudio | 有声读物 | SoloAmbient/Playback/PlayAndRecord/MultiRoute | 当其他应用程序播放短暂的语音提示时,希望自己的音频暂停而不是回避(声音变小)时使用 |
VoicePrompt | 语音提示 | - | 如:导航中的播报 |
暂时更改当前的音频端口, PlayAndRecord Category
下设置 PortOverrideSpeaker
时,可无视其他设置,使用话筒录音和扬声器播放
audioSession.overrideOutputAudioPort(.speaker)
4.Ports
AVAudioSessionPort
端口:
// 输入端口
AVAudioSessionPortLineIn // 充电口接入的电平信号(适合高质量音频传输,如:插入唱吧麦克风)
AVAudioSessionPortBuiltInMic // 内置麦克风
AVAudioSessionPortHeadsetMic // 耳机麦克风
// 输出端口
AVAudioSessionPortLineOut // 充电口输出的电平信号(连接到外部音频设备,如:连接音响)
AVAudioSessionPortHeadphones // 耳机
AVAudioSessionPortBluetoothA2DP // 蓝牙A2DP设备输出
AVAudioSessionPortBuiltInReceiver // 听筒
AVAudioSessionPortBuiltInSpeaker // 内置扬声器
AVAudioSessionPortHDMI // HDMI输出
AVAudioSessionPortAirPlay // 远程Air Play设备上的输出
AVAudioSessionPortBluetoothLE // 低功耗蓝牙的输出
// 输入 & 输入
AVAudioSessionPortBluetoothHFP // 蓝牙免提配置文件设备上的输入或输出
AVAudioSessionPortUSBAudio // 通用USB设备上的输入或输出
AVAudioSessionPortCarAudio // 通过汽车音响输入或输出
5.Notification
5.1.中断通知:
AVAudioSessionInterruptionNotification
比如: 来电话了/闹钟响了/被其他App影响了
通常: 先暂停, 待恢复的时候再继续
NotificationCenter.default.addObserver(forName: NSNotification.Name.init(rawValue: AVAudioSession.interruptionNotification.rawValue),
object: nil,
queue: .main) { notification in
// 中断类型: AVAudioSessionInterruptionTypeBegan / Ended
notification.userInfo?[AVAudioSessionInterruptionTypeKey]
// 应该恢复继续播放和采集: AVAudioSessionInterruptionOptionShouldResume (中断结束时有值)
notification.userInfo?[AVAudioSessionInterruptionOptionKey]
// 中断原因:AVAudioSessionInterruptionReason
notification.userInfo?[AVAudioSessionInterruptionReasonKey]
}
5.2.其他App占据Session通知
AVAudioSessionSilenceSecondaryAudioHintNotification
当来自其他应用程序的主音频开始和停止触发此通知, 此通知仅发送给位于前台且具有活动音频会话的APP,即正在前台使用时,后台其他APP有音频播放的情况
NotificationCenter.default.addObserver(forName: NSNotification.Name.init(rawValue: AVAudioSession.silenceSecondaryAudioHintNotification.rawValue),
object: nil,
queue: .main) { notification in
// 其他App开始 占据/释放 Session
// 中断类型: AVAudioSessionSilenceSecondaryAudioHintType Began / Ended
notification.userInfo?[AVAudioSessionSilenceSecondaryAudioHintTypeKey]
}
5.3.外设改变通知
AVAudioSessionRouteChangeNotification
NotificationCenter.default
.addObserver(forName: NSNotification.Name.init(rawValue: AVAudioSession.routeChangeNotification.rawValue),
object: nil,
queue: .main) { notification in
// 被系统中断
// 改变原因:
notification.userInfo?[AVAudioSessionRouteChangeReasonKey]
// 中断类型: AVAudioSessionSilenceSecondaryAudioHintType Began / Ended
notification.userInfo?[AVAudioSessionSilenceSecondaryAudioHintTypeKey]
}
AVAudioSessionRouteChangeReason
Unknown // 未知原因
NewDeviceAvailable // 连接了新设备, 如耳机
OldDeviceUnavailable // 断开了设备, 如耳机
CategoryChange // 类别改变了
Override // 复写output route,比如PlayAndRecord下从receiver(听筒)改为speaker(扬声器)
WakeFromSleep // 从休眠状态唤醒
NoSuitableRouteForCategory // 当前Category下没有合适的设备
RouteConfigurationChange // input and output ports没变,但是配置变了,比如port的selectedDataSource
5.4.其他通知
AVAudioSessionMediaServicesWereLostNotification
媒体服务器被杀时,触发此通知,在极少数情况下,系统会终止并重启媒体服务,一般很少这个通知,可用来提示。
AVAudioSessionMediaServicesWereResetNotification
媒体服务器重启时,触发此通知,在极少数情况下,系统会终止并重启媒体服务,收到此通知后需重新对音频会话做初始化设置等。但是不需要重新监听Notification 和 KVO 等,开发者模式下,设置-开发者-重置媒体服务,可主动触发此通知。
6.路由共享策略
AVAudioSessionRouteSharingPolicy
AVAudioSession.RouteSharingPolicy
default // 遵循正常的规则路由音频输出
longFormAudio // 将输出路由到共享的长格式音频输出
longForm // 已废弃
independent // 应用程序不应试图直接设置此值。在iOS上,当路由选择器UI用于将视频定向到无线路由时,系统将设置此值。
longFormVideo // 将输出路由到共享的长格式视频输出(使用此策略的应用程序在其Info.plist中设置AVInitialRouteSharingPolicy键)
7.硬件配置
AVAudioSessionHardwareConfiguration
// 采样率
audioSession.setPreferredSampleRate(1) // 设置
audioSession.preferredSampleRate // 获取
// I/O 首选缓冲时间,指单音频输入/输出周期的时长
// 比如说I/O缓冲时间为0.005s, 那么在每一个音频I/O周期里,在获取输入时,会收到0.005s的音频,在输出时,必须提供0.005s的音频。
audioSession.setPreferredIOBufferDuration(0.005) // 设置
audioSession.preferredIOBufferDuration // 获取
// 首选的音频输入信道数
audioSession.setPreferredInputNumberOfChannels(2)
audioSession.preferredInputNumberOfChannels
// 首选的音频输出信道数
audioSession.setPreferredOutputNumberOfChannels(2)
audioSession.preferredOutputNumberOfChannels
// 输入设备音量增益: [0.0, 1.0]
audioSession.setInputGain(0.5)
audioSession.inputGain
audioSession.inputGainSettable // 是否设置了音量增益
audioSession.inputAvailable // 输入设备是否支持音量增益
// 输入数据源
audioSession.inputDataSources // 当前可用输入数据源列表
audioSession.inputDataSource // 当前输入源
audioSession.setInputDataSource(source1) // 设置输入源
// 输出数据源
audioSession.outputDataSources // 当前可用输出数据源列表(部分外接USB配件时支持此功能)
audioSession.outputDataSource // 当前输出数据源
audioSession.setOutputDataSource(source1) // 设置输出源
// 控制是否聚合音频输入和输出
// notSpecified 不聚合
// aggregated 聚合
audioSession.setAggregatedIOPreference(AVAudioSession.IOType.aggregated)
8.远程交互
在 AppDelegate
里实现:
override func remoteControlReceived(with event: UIEvent?) {
switch event?.subtype {
case .none:
case .motionShake: // 摇动
case .remoteControlPlay: // 播放
case .remoteControlPause: // 暂停
case .remoteControlStop: // 停止
case .remoteControlTogglePlayPause: // 切换 播放/暂停
case .remoteControlNextTrack: // 下一首
case .remoteControlPreviousTrack: // 上一首
case .remoteControlBeginSeekingBackward: // 快退开始
case .remoteControlEndSeekingBackward: // 快退结束
case .remoteControlBeginSeekingForward: // 快进开始
case .remoteControlEndSeekingForward: // 快进结束
}
}
9.相关Errors
AVAudioSessionErrorCodeNone // 操作成功。
AVAudioSessionErrorCodeMediaServicesFailed // 尝试在媒体服务失败期间或之后使用音频会话。
AVAudioSessionErrorCodeIsBusy // 尝试将其音频会话设置为非活动状态,但仍在播放和/或录制。
AVAudioSessionErrorCodeIncompatibleCategory // 试图执行当前类别中不允许的操作。
AVAudioSessionErrorCodeCannotInterruptOthers // 尝试在应用程序处于后台时使不可混音的音频会话处于活动状态。
AVAudioSessionErrorCodeMissingEntitlement // 试图执行应用程序没有所需权利的操作。
AVAudioSessionErrorCodeSiriIsRecording // Siri正在录制时尝试执行不允许的操作。
AVAudioSessionErrorCodeCannotStartPlaying // 试图开始音频播放,但不允许播放。
AVAudioSessionErrorCodeCannotStartRecording // 试图开始录音,但失败了。
AVAudioSessionErrorCodeBadParam // 试图将属性设置为非法值。
AVAudioSessionErrorInsufficientPriority // 该应用程序不允许设置音频类别,因为它正在被另一个应用程序使用。
AVAudioSessionErrorCodeResourceNotAvailable // 由于设备没有足够的硬件资源来完成操作而失败的操作。
AVAudioSessionErrorCodeUnspecified // 没有更多的错误信息可用。当音频系统处于不一致状态时,通常会产生这种错误类型。
10.Reference
Audio Session Programming Guide
AVAudioSession
Handling audio interruptions
Responding to audio route changes
Audio Session Support