iOS_AVAudioSession 音频硬件 Input/Ouput 管理

在这里插入图片描述


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 为不同的类别,可以控制:

  1. 当 App 激活 Session 的时候,是否会打断其他不支持混音的 App 声音
  2. 当用户触发手机上的“静音”键时或者锁屏时,是否相应静音
  3. 当前状态是否支持录音
  4. 当前状态是否支持播放
  5. 每个 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大类别 CategorysAVAudioSessionCategory

锁屏/静音不支持混音的App录音/播放说明举例
Ambient静音不中断播放可与音乐同时播放游戏背景音乐和QQ音乐共存
SoloAmbient静音中断播放不希望其他App干扰如:节奏大师
Playback继续默认中断播放锁屏/静音了还想听音乐如:QQ音乐
Record继续中断YES录音时中断其他播放如:微信长按录音
PlayAndRecord继续默认不中断YESVoIP(通话)打电话
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模式下,希望默认打开免提功能
InterruptSpokenAudioAndMixWithOthersiOS9, 播放此应用的音频内容时,是否暂停来自其他应用的连续语音内容PlayAndRecord/Playback/MultiRoute
AllowBluetoothA2DP支持立体声蓝牙PlayAndRecord
AllowAirPlay支持远程AirPlayPlayAndRecord如果清除此选项,则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每种类别默认的就是这个模式,所有要想还原的话,就设置成这个模式
VoiceChatVoIPPlayAndRecord此时系统会选择最佳的输入设备,比如插上耳机就使用耳机上的麦克风进行采集。此时有个副作用,他会设置类别的选项为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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小莫同学~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值