一,参考
Apple devleop Document:Core Audio Essentials
Audio Session Programming Guide(https://developer.apple.com/library/content/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Introduction/Introduction.html)
二,架构层次
CoreAudio的API分为三层:
底层跟硬件打交道;中间层包括了数据格式转换,读写磁盘,分析流;上层包括了一些包含底层特征的精简接口。
三,框架
AudioToolbox.framework:包括音频session相关。
AudioUnit.framework:让应用与音频插件配合工作。
AVFoundation.framework:提供AVAudioPlayer–精简的的音频播放接口。
CoreAudio.framework:提供Core Audio中用的数据类型。
四,具体处理
Callback函数:跟Core Audio交互
Audio Session:与Core Audio交互
应用与iOS之间的媒介,使用之前需要考虑:
1,应用想要如何处理电话等中断。
2,想要将本应用的声音与其他应用的混合,还是让他们静音?
3,应用如何处理声音路由变化–用户拔插耳机时。
1,激活AudioSession
中断:抑制和激活
程序启动时默认是激活状态,电话进来后进入抑制状态,如果不进行激活,音乐无法在电话结束后继续播放。
检查是否有其他声音在播放
可以在app delegate的applicationDidBecomeActive:中检查session.secondaryAudioShouldBeSilencedHint,也可以订阅这个类型的变化情况(AVAudioSessionSilenceSecondaryAudioHintNotification)、
2,配置Session
音频会话的默认行为:
1,支持声音播放,但不支持声音录制。
2,当用户将铃声/静音开关置为静音时,声音被静音。
3,用户通过睡眠/苏醒按钮进行锁屏时,声音被静音。
4,当声音开始后,其他音频被静音。
说明:
Category决定了音频的行为,主要行为有:
- 中断其他非混合的音频。
- 被手机侧面的静音开关静音。
- 支持音频输入。
- 支持音频输出。
最好在会话被音质后在改变category或者会话属性,这样做可以阻止音频系统进行不必要的重新配置。
SDK详细说明:
AVAudioSessionCategoryAmbient:背景声音,例如雨声、汽车引擎声等,跟其他声音混合。
AVAudioSessionCategorySoloAmbient:背景声音。会停掉其他音乐。
AVAudioSessionCategoryPlayback:音乐播放。
AVAudioSessionCategoryRecord:录音。
AVAudioSessionCategoryPlayAndRecord:录音和音乐播放。
AVAudioSessionCategoryAudioProcessing:当使用硬件编解码器或信号处理器时,请使用此类别。
不播放或录制音频。
AVAudioSessionCategoryMultiRoute:需要自定义可用的音频设备以及内置的声音硬件时使用。
说明:
除了Category还可以通过Mode,进一步精确音频的行为:
AVAudioSessionModeDefault:通用
AVAudioSessionModeVoiceChat:只在AVAudioSessionCategoryPlayAndRecord可用,适合VoIP应用。使得音频路径只为VoIP输出。
AVAudioSessionModeGameChat:只在AVAudioSessionCategoryPlayAndRecord可用。由Game Kit设定,不要直接设定。
AVAudioSessionModeVideoRecording:AVAudioSessionCategoryPlayAndRecord或者AVAudioSessionCategoryRecord时可用。修改音频路由选项,并可进行适当的系统提供的信号处理。
AVAudioSessionModeMeasurement:适用于希望尽量减少系统提供信号影响的应用程序输入和/或输出音频信号的处理。
AVAudioSessionModeMoviePlayback:对电影回放场景进行适当的输出信号处理。目前仅适用于内置扬声器播放时。
AVAudioSessionModeVideoChat:>=iOS7.0 只在kAudioSessionCategory_PlayAndRecord可用。减少允许的音频数量仅适用于视频聊天应用程序的路由。可以进行适当的系统提供的信号处理。
AVAudioSessionModeSpokenAudio:>=iOS9.0 如果其他应用(如导航应用程序)播放语音音频提示时,适用于希望暂停(通过音频会话中断)而不是躲避。使用此应用程序的示例是播客播放器和音频书。
3,中断处理
中断发生时,需要保存状态和环境,更新用户画面;
中断结束时,需要恢复状态和环境,更新用户画面,重新激活会话
观察中断
NotificationCenter.default.addObserver(self,
selector: #selector(handleInterruption),
name: .AVAudioSessionInterruption,
object: AVAudioSession.sharedInstance())
func handleInterruption(_ notification: Notification) {
guard let info = notification.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
return
}
if type == .began {
// Interruption began, take appropriate actions (save state, update user interface)
}
else if type == .ended {
guard let optionsValue =
userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else {
return
}
let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
// Interruption Ended - playback should resume
}
}
}
4,路径变化
func setupNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(handleRouteChange),
name: .AVAudioSessionRouteChange,
object: AVAudioSession.sharedInstance())
}
func handleRouteChange(notification: NSNotification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable:
let session = AVAudioSession.sharedInstance()
for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
headphonesConnected = true
}
case .oldDeviceUnavailable:
if let previousRoute =
userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
for output in previousRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
headphonesConnected = false
}
}
default: ()
}
}