使用Core Audio实现VoIP通用音频模块
最近一直在做iOS音频技术相关的项目,由于单项直播SDK,互动直播SDK(iOS/Mac),短视频SDK,都会用到音频技术,因此在这里收集三个SDK的音频技术需求,开发一个通用的音频模块用于三个SDK,同时支持iOS和Mac。
想要技术干货、行业洞察,欢迎关注网易云信博客。
了解网易云信,来自网易核心架构的通信与视频云服务。
需求实现
主要包括音频采集,音频格式转换,音频多路混音(本地文件和网络文件),写WAV/AAC音频文件,通话录制,音频文件播放,耳返,自定义音频输入,音视频设备管理等功能。
本文大部分图片和技术概念阐述均来自Apple官网。
概念介绍
Core Audio 是iOS和 Mac 的关于数字音频处理的基础,它提供应用程序用来处理音频的一组软件框架,所有关于iOS音频开发的接口都是由Core Audio来提供或者经过它提供的接口来进行封装的,按照官方的说法是集播放、音频处理、录制为一体的专业技术,通过它我们的程序可以同时录制,播放一个或者多个音频流,自动适应耳机,蓝牙耳机等硬件,响应各种电话中断,静音,震动等。
Low-Level
I/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 Unit
iOS提供了混音、均衡、格式转换、实时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 Session
AVAudioSession构建了一个音频使用生命周期的上下文。当前状态是否可以录音、对其他App有怎样的影响、是否响应系统的静音键、如何感知来电话了等都可以通过它来实现。
Audio Processing Graphs
AUGraph可以用来构建和管理一个音频单元处理链。能够利用多个音频单元的功能和多个渲染回调函数,允许您创建几乎任何你可以想象的音频处理的解决方案。同时它也是线程安全的。
Audio Flows Through a Graph Using “Pull”
在一个音频处理图,当需要更多的音频数据时,使用者调用提供者。有源源不断的音频数据流的请求,这个控制流的方向和音频流方向相反。
具体实现
一、音频采集
iOS采集:
kAudioUnitSubType_RemoteIO
kAudioUnitSubType_VoiceProcessingIO
Mac采集:
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/library/content/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html#//apple_ref/doc/uid/TP40009492-CH3-SW11
https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003577-CH1-SW1
使用Core Audio实现VoIP通用音频模块相关推荐
- 【实战分享】使用Core Audio实现VoIP通用音频模块
最近一直在做iOS音频技术相关的项目,由于单项直播SDK,互动直播SDK(iOS/Mac),短视频SDK,都会用到音频技术,因此在这里收集三个SDK的音频技术需求,开发一个通用的音频模块用于三个SDK ...
- Core Audio音频基础概述
Core Audio Core Audio提供了数字音频服务为iOS与OS X, 它提供了一系列框架去处理音频. Core Audio中包含我们最常用的Audio Toolbox与Audio Unit ...
- 【Audio】Unity音频模块:加载、转换、剪切、混音、合并
GitHub项目:Epitome.Audio音频模块 WWW类外部加载音乐文件 使用delegate委托:音频加载完成进行回调 namespace Epitome {public delegate v ...
- Windows下Core Audio APIS 音频应用开发(五)
之前做开发是一直有个疑问(博主qq,1204802552,欢迎交流) 按照Core Audio上面的文档,音频设备本身会有个设备周期,这个周期决定了音频设备所能缓存的最大数据量:而另外一方面,我们在初 ...
- 【SemiDrive源码分析】【X9 Audio音频模块分析】16 - 音频模块框图及硬件原理图分析
[SemiDrive源码分析][X9 Audio音频模块分析]16 - 音频模块框图及硬件原理图分析 一.X9HP 音频模块框图及硬件原理图分析 1.1 音频接口 I2S 介绍 1.2 X9 平台音频 ...
- Windows下Core Audio APIS 音频应用开发(二)
对于一个音频应用程序,最基本也是最重要的两个点就是:音频数据的采集:音频数据的播放.下面我们来看下如何用Core Audio APIS进行音频数据的采集. 最权威的学习资料无疑是微软的MSDN官方资料 ...
- Windows Core Audio 音频开发技术指南
在音视频通信处理流程中,音频方面最基本的无外乎就是音频的采集和播放.windows 平台下,有很多音频采集播放的方法.作为一个 windows 端音频应用程序开发人员,经常会被各种可用的API淹没,比 ...
- Windows Core Audio APIs(一)介绍
文章目录 Windows Core Audio APIs(一)介绍 Core Audio 架构介绍 Core Audio 架构图 音频高级API Core Audio APIs 共享模式和独占模式 音 ...
- Windows下Core Audio APIs的使用简介
文|网易云信资深PC端开发工程师 Windows Vista 之后的系统中,音频系统相比之前的系统有很大的变化,产生了一套新的底层 API 即 Core Audio APIs . 该低层 API 为高 ...
最新文章
- 2020年,计算机视觉领域会有哪些新的研究方向值得提前探索?
- 计算机科学与技术考,计算机科学与技术考研
- java虚拟机6.HotSpot的GC实现
- python unix时间戳转换成时间_关于python:将unix时间戳字符串转换为可读日期
- Python os.path模块的使用
- 基于ArcEngine的插件式框架
- OpenStack精华问答 | OpenStack 网络中 OpenFlow 规则的作用是什么?
- Linux多线程实践(9) --简单线程池的设计与实现
- 0基础自学前端好,还是报班培训好?
- 扩展Jquery方法创建LigerUI Grid
- 关于微积分学的基本定理
- 用Matlab筛选mirbase,一种基于miRBase数据库的无参的miRNA数据分析方法与流程
- Linux系统下下载Tomcat详细步骤。
- 阿里云盘tv版 v1.0.6电视版
- RedisTemplate使用
- HNU暑假程序设计训练 0419
- php 接口文档写法,php 接口文档
- 基于html的美食网站 奶茶网页设计与实现(HTML+CSS+JavaScript)
- python 合并word文件_python读取word合并单元格
- GEE实现图像随机森林分类
热门文章
- ZeroMQ之Publish/Subscribe (Java)
- PHP+JQuery实现ajax跨域
- 异构并行编程(CUDA)结课证书
- linux jdk免安装配置,生产环境免安装jdk的使用方法
- iap如何初始化_IAP超级详解
- 全网最全!2021最新常用肿瘤生信数据库收藏级汇总!
- RBPsuite RNA-蛋白质结合位点预测工具使用指南
- 软件工程导论个人项目 -- 中小学数学卷子自动生成程序
- JavaWeb(七)——Cookie、Session
- python动态改变标签的颜色_PyQt4 treewidget 选择改变颜色,并设置可编辑的方法