最近一直在做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 : 表示改变的原因

参考文档:

 
 

网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

使用Core Audio实现VoIP通用音频模块的更多相关文章

  1. Core Audio(二)

    用户模式音频组件 在windows vista中,core audio apis充当用户模式音频子系统的基础,core audio apis作为用户模式系统组件的一个thin layer,它用来将用户 ...

  2. Core Audio(一)

    Core Audio APIs core audio apis是vista之后引入的,不使用与之前的windows版本:core audio apis提供访问endpoint devices,比如耳机 ...

  3. Core Audio 在Vista/Win7上实现

    应用范围:Vista / win7, 不支持XP 1. 关于Windows Core Auido APIs 在Windowss Vista及Windows 7操作系统下,微软为应用程序提供了一套新的音 ...

  4. Abp通用配置模块的设计

    引言 约定优于配置,配置趋于灵活 约定优于配置(convention over configuration),也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处, ...

  5. 使用 Windows Core Audio APs 进行 Loopback Recording 并生成 WAV 文件

    参考文档 COM Coding Practices Audio File Format Specifications Core Audio APIs Loopback Recording #inclu ...

  6. HTML5的Audio标签打造WEB音频播放器

    目前,WEB页面上没有标准的方式来播放音频文件,大多数的音频文件是使用插件来播放,而众多浏览器都使用了不同的插件.而HTML5的到来,给我们提供了一个标准的方式来播放WEB中的音频文件,用户不再为浏览 ...

  7. WebRTC源码分析:音频模块结构分析

    一.概要介绍WebRTC的音频处理流程,见下图: webRTC将音频会话抽象为一个通道Channel,譬如A与B进行音频通话,则A需要建立一个Channel与B进行音频数据传输.上图中有三个Chann ...

  8. ylbtech-Model-Account(通用账户模块设计)

    ylbtech-DatabaseDesgin:ylbtech-Model-Account(通用账户模块设计) ylbtech-Model-Account(通用账户模块设计) 1.A,数据库关系图(Da ...

  9. javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

随机推荐

  1. 解决Eclipse代码提示消失的方法

    注意:首先要做的是windows->preferences->java->Editor->"ContentAssist", auto-activetion中 ...

  2. 在sqlserver中,使用sql语句更新数据库:生成随机数,更新每一行中的年龄字段

    use School --指定数据库 declare @min_id int --声明整数变量@x set @min_id=(select MIN(Id) from Students) --给变量@x ...

  3. 从入门机器学习的零单排:OctaveMatlab经常使用绘图知识

    OctaveMatlab经常使用绘图知识 之前一段时间在coursera看了Andrew ng的机器学习的课程,感觉还不错,算是入门了.这次打算以该课程的作业为主线,对机器学习基本知识做一下总结.小弟 ...

  4. MySQL TIMESTAMP(时间戳)详细解释

    当你创建一个表假设表中有类型的字段TIMESTAMP,该字段默认情况下,语句生成: CREATE TABLE `test` ( `id` int(11) DEFAULT NULL, `ctime` t ...

  5. windows 系统文件 —— 特殊文件及文件类型

    0. .mht 文件(MHTML) MHTML文件又称为聚合 HTML 文档.Web 档案或单一文件网页(聚合成单一文件).单个文件网页可将网站的所有元素(包括文本和图形)都保存到单个文件中.这种封装 ...

  6. 从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法

    原文:从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法 主程序 为 Main_Test.exe 被加载的DLL 为 Load_Test.dll  此DLL 中 有一个 文件夹Re ...

  7. 卷积、卷积矩阵(Convolution matrix)与核(Kernel)

    在图像处理领域,Kernel = convolution matrix = mask,它们一般都为一个较小的矩阵: 用于:Sharpen,Blur, Edge enhance,Edge detect, ...

  8. OpenGL(十五) OpenCV+OpenGL实现水面倒影

    有两幅原始图片,一个是景物图像,一个是水面图像,尝试生成景物在水中的倒影: 在OpenGL中,加载并显示这个景物图像可以把这个图像作为纹理载入即可,把图像直接选择180度的效果就相当于是在镜面中倒影的 ...

  9. postgresql && .net core 使用空间数据

    这里主要讲遇到的一些报错 增删改查 && 计算部分基本和sql server的空间数据操作一毛一样,感谢微软大大的倾情支持,直接看demo即可(- ̄▽ ̄)- 前往sql server ...

  10. 2019 renew 博客目录

    .net && .net core Microsoft.AspNet.SignalR实现弹幕(即时通讯) C#调用JS httpclient POST请求(urlencoded) 二维 ...