使用Core Audio实现VoIP通用音频模块

34次阅读

共计 4485 个字符,预计需要花费 12 分钟才能阅读完成。

最近一直在做 c 音频技术相关的项目,由于单项直播 SDK,互动直播 SDK(iOS/Mac),短视频 SDK,都会用到音频技术,因此在这里收集三个 SDK 的音频技术需求,开发一个通用的音频模块用于三个 SDK,同时支持 iOS 和 Mac。
想要阅读更多技术干货、行业洞察,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。
需求实现主要包括音频采集,音频格式转换,音频多路混音(本地文件和网络文件),写 WAV/AAC 音频文件,通话录制,音频文件播放,耳返,自定义音频输入,音视频设备管理等功能。本文大部分图片和技术概念阐述均来自 Apple 官网。概念介绍 Core Audio 是 iOS 和 Mac 的关于数字音频处理的基础,它提供应用程序用来处理音频的一组软件框架,所有关于 iOS 音频开发的接口都是由 Core Audio 来提供或者经过它提供的接口来进行封装的,按照官方的说法是集播放、音频处理、录制为一体的专业技术,通过它我们的程序可以同时录制,播放一个或者多个音频流,自动适应耳机,蓝牙耳机等硬件,响应各种电话中断,静音,震动等。
Low-LevelI/O Kit:与硬件驱动交互 Audio HAL:音频硬件抽象层,使 API 调用与实际硬件相分离,保持独立 Core MIDI:为 MIDI 流和设备提供软件抽象工作层 Host Time Services:访问电脑硬件时钟
Mid-Level Audio Convert Services 负责音频数据格式的转换 Audio File Services 负责音频数据的读写 Audio Unit Services 和 Audio Processing Graph Services 支持均衡器和混音器等数字信号处理的插件 Audio File Scream Services 负责流解析 Core Audio Clock Services 负责音频时钟同步
High-Level Audio Queue Services 提供录制、播放、暂停、循环、和同步音频,它自动采用必要的编解码器处理压缩的音频格式 AVAudioPlayer 是专为 iOS 平台提供的基于 Objective- C 接口的音频播放类,可以支持 iOS 所支持的所有音频的播放 Extended Audio File Services 由 Audio File 与 Audio Converter 组合而成,提供压缩及无压缩音频文件的读写能力 OpenAL 是 CoreAudio 对 OpenAL 标准的实现,可以播放 3D 混音效果
OS X 和 iOS 的核心音频架构
Audio UnitiOS 提供了混音、均衡、格式转换、实时 IO 录制、回放、离线渲染、语音对讲 (VoIP) 等音频处理插件,它们都属于不同 AudioUnit,支持动态载入和使用。AudioUnit 可以单独创建使用,但更多的是被组合使用在 Audio Processing Graph 容器中以达到多样的处理需要。
一个 I /O Unit 包含两个实体对象,两个实体对象(Element 0、Element 1)相互独立,根据需求可通过 kAudioOutputUnitProperty_EnableIO 属性去开关它们。Element 1 与硬件输入连接,并且 Element 1 的输入域 (input scope) 对你不可见,你只能读取它的输出域的数据及设置其输出域的音频格式;Element 0 与硬件输出连接,并且 Element 0 的输出域 (ouput scope) 对你不可见,你只能写入它的输入域的数据及设置其输入域的音频格式。
Audio SessionAVAudioSession 构建了一个音频使用生命周期的上下文。当前状态是否可以录音、对其他 App 有怎样的影响、是否响应系统的静音键、如何感知来电话了等都可以通过它来实现。Audio Processing GraphsAUGraph 可以用来构建和管理一个音频单元处理链。能够利用多个音频单元的功能和多个渲染回调函数, 允许您创建几乎任何你可以想象的音频处理的解决方案。同时它也是线程安全的。
Audio Flows Through a Graph Using“Pull”在一个音频处理图, 当需要更多的音频数据时,使用者调用提供者。有源源不断的音频数据流的请求, 这个控制流的方向和音频流方向相反。
具体实现一、音频采集 iOS 采集:kAudioUnitSubType_RemoteIOkAudioUnitSubType_VoiceProcessingIOMac 采集:kAudioUnitSubType_VoiceProcessingIO
一个 I /O Unit 包含两个实体对象,两个实体对象(Element 0、Element 1)相互独立。Element 1 与硬件输入(麦克风或者听筒)连接,并且 Element 1 的输入域 (input scope) 对你不可见,你只能读取它的输出域的数据及设置其输出域的音频格式;Element 0 与硬件输出(扬声器或者听筒)连接,并且 Element 0 的输出域 (ouput scope) 对你不可见,你只能写入它的输入域的数据及设置其输入域的音频格式。操作步骤:第一,创建 AudioUnit。第二,开启麦克风或者听筒的输入开关;开启扬声器或者听筒的输出开关。第三,设置输入和输出的采集回调和播放回调。第四,设置输入和输出的音频格式。第五,初始化 AudioUnit。第六,开启 AudioUnit。Mac 采集:kAudioUnitSubType_HALOutput
Mac 的音频采集使用的是 kAudioUnitSubType_HALOutput, 音频硬件抽象层 HAL。因此它使用的是 2 个 I /O Uint 串联,前一个 I /O Uint 的输出作为后一个 I /O Uint 的输入。操作步骤:第一,创建 2 个 AudioUnit。第二,开启第一个 I /O Uint 的麦克风或者听筒的输入开关,关闭第一个 I /O Uint 的扬声器或者听筒的输出开关;开启第二个 I /O Uint 的扬声器或者听筒的输出开关,关闭第二个 I /O Uint 的麦克风或者听筒的输入开关。第三,将第一个 I /O Unit 设为 Mac 的 kAudioHardwarePropertyDefaultInputDevice,第二个 I /O Unit 设为 Mac 的 kAudioHardwarePropertyDefaultOutputDevice,第四,设置第二个 I /O Uint 的输入和第一个 I /O Uint 的输出的采集回调和播放回调。第五,设置第二个 I /O Uint 的输入和第一个 I /O Uint 的输出的音频格式。第六,初始化 2 个 AudioUnit。第七,开启 2 个 AudioUnit。二、音频架构
从图中可以看出,我们使用了一个 I /O Unit 作为最核心的部件,用于驱动整个流程,同时使用三个 Audio Processing Graphs 作为混音器。三个 Audio Processing Graphs 分别代表播放混音器,发送混音器,录制混音器。每个混音器有三个 Unit 最为其部件,音频混音 Mixing(kAudioUnitSubType_MultiChannelMixer),音频格式转换(kAudioUnitSubType_AUConverter),音频通用输出(kAudioUnitSubType_GenericOutput)。同时支持多路输入,一路输出。1. 播放混音器支持来自服务器的多路音频流和一路本地伴音以及一路耳返音频,每一路输入都会接一个音频格式转换,同时设置一个输入回调,用于音频数据的主动拉取。并将混音器的输出作为 Audio Unit 的输入。2. 发送混音器支持一路 Audio Unit 的采集和本地多路音频伴音的输入,每一路输入都会接一个音频格式转换,同时设置一个输入回调,用于音频数据的主动拉取。并将混音器的输出作为音频编码和发送的输入。3. 录制混音器支持 Audio Unit 的一路采集和 Audio Unit 的一路播放,将整个通话过程涉及到的音频数据都合成一路。每一路输入都会接一个音频格式转换,同时设置一个输入回调,用于音频数据的主动拉取。并将混音器的输出作为通话录制的输入,并写 WAV/AAC 文件。4.Audio Unit 的采集回调驱动音频编码,从而驱动整个发送混音器;Audio Unit 的采集回调驱动通话录制,从而驱动整个录制混音器;Audio Unit 的播放回调驱动播放,从而驱动整个播放混音器。5. 目前最新的音频架构,我们使用了两个 I /O Unit 作为最核心的部件,用于驱动整个流程。同时统一了 iOS 和 Mac 2 个版本,也解决了采集和播放同一个线程的问题,为我们的音频前处理提供了安全的线程保障。
三、AVAudioSeeion 管理 AVAudioSession 的主要功能包括以下几点功能:向系统说明你的 app 使用音频的模式(比如是播放还是录音,是否支持蓝牙播放,是否支持后台播放)为你的 app 选择音频的输入输出设备(比如输入用的麦克风,输出是耳机、手机功放或者 airplay)协助管理多个音源需要播放时的行为(例如同时使用多个音乐播放 app,或者突然有电话接入)如果需要音频支持后台运行,需要按下图配置:
在需要完成上述功能点的前提下,我们需要监听中断响应,外设改变,媒体服务器终止,媒体服务器重新启动,前后台切换的通知。在不同的通知下,做出相应的调整。系统中断响应:AVAudioSession 提供了多种 Notifications 来进行此类状况的通知。其中将来电话、闹铃响等都归结为一般性的中断,用 AVAudioSessionInterruptionNotification 来通知。其回调回来的 userInfo 主要包含两个键:AVAudioSessionInterruptionTypeKey:取值为 AVAudioSessionInterruptionTypeBegan 表示中断开始,我们应该暂停播放和采集,取值为 AVAudioSessionInterruptionTypeEnded 表示中断结束,我们可以继续播放和采集。AVAudioSessionInterruptionOptionKey:当前只有一种值 AVAudioSessionInterruptionOptionShouldResume 表示此时也应该恢复继续播放和采集。外设改变:在 NSNotificationCenter 中对 AVAudioSessionRouteChangeNotification 进行注册。在其 userInfo 中有键:AVAudioSessionRouteChangeReasonKey:表示改变的原因
参考文档:https://developer.apple.com/l…https://developer.apple.com/l…
网易云信(NeteaseYunXin)是集网易 18 年 IM 以及音视频技术打造的 PaaS 服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端 SDK 和云端 OPEN API,即可快速实现包含 IM、音视频通话、直播、点播、互动白板、短信等功能。

正文完
 0