探索iOS之CoreAudio核心音频框架

iOS的CoreAudio分为三层:应用服务层、驱动层、硬件层。其中,应用服务层包括:AudioQueue Service、AudioPlayer Service、AudioSession Service、AudioFile Service、AudioUnit等。

一、CoreAudio整体架构

CoreAudio的整体架构自顶向下是Service层、Driver层、Hardware层,如下图所示:

 二、Service层级架构

Service层按照等级分层,自顶向下是High-Level、Mid-Level、Low-Level。其中,高级别Service有AVAudioPlayer、AudioQueue、OpenAL等;中级别Service有AudioConverter、AudioFile、AudioUnit等;低级别Service有IOKit、Auido HAL等。如下图所示:

三、 AudioQueue

AudioQueue可用于音频播放、录音。我们不用了解硬件接口,就可以使用硬件录制和播放设备

1、播放

AudioQueue播放的数据源采用回调方式获取,提供缓冲队列,最终输出给扬声器播放。如下图所示:

2、录音

AudioQueue录音的数据源来自麦克风,内部提供缓冲队列,最终回调给业务层。如下图所示:

四、AudioConverter

AudioConverter提供音频格式转换。以mp3转aac为例,输入mp3解码得到pcn,然后pcm编码成aac。转换流程如下图所示:

五、AudioSession

AudioSession用于访问麦克风、扬声器的会话,提供管理音频服务、监听Route变化,如下图所示:

1、配置AudioSession

关于AudioSession的配置,示例代码如下:

let session = AVAudioSession.sharedInstance()
do {
    // Configure the audio session for playback
    try session.setCategory(AVAudioSessionCategoryPlayback,
                            mode: AVAudioSessionModeMoviePlayback,
                            options: [])
    // Activate audio session to enable your custom configuration
    try session.setActive(true)
} catch let error as NSError {
    print("Unable to activate audio session:  \(error.localizedDescription)")
}

2、后台播放

如果要后台播放音乐,或者Airplay投屏、画中画播放,需要把后台模式打开:

3、处理中断

不同session之间会互相中断。比如当前正在播放音乐,有个语音电话打进来,那么就会中断音乐播放,保存状态和上下文。等到通话结束,然后使用状态和上下文恢复音乐播放。示意图如下:

监听中断通知以及处理中断,示例代码如下:

func registerForNotifications() {
    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 {
        // save state and context
    }
    else if type == .ended {
        guard let optionsValue =
            userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else {
                return
        }
        let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) {
            // Interruption Ended, resume to playback
        }
    }
}

5、监听Route变化

通知注册AVAudioSessionRouteChangeNotification来监听。以监听连接耳机为例,代码示例如下:

func setupNotification() {
    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 {
            // headphone connected
        }
    case .oldDeviceUnavailable:
        if let previousRoute =
            userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
            for output in previousRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
                // headphone disconnected
            }
        }
    default: ()
    }
}

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/130743780
今日推荐