1、背景

在移动直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在采集录音的基础上玩一些花样。

比如演唱类的直播间中, 主播伴随着背景音乐演唱. 这时有些主播就会希望能够给自己声音增加混响的效果, 营造出在舞台剧场等环境下演唱的氛围. 再比如有些搞笑类的直播间, 主播会希望给自己的声音添加变声的效果, 女变男,男变女或者变成机器人等等. 为了实现这些需求我们需要对采集的声音进行处理, 并且为了让主播实时听到这些处理后的效果,以便根据效果进行调整,我们也需要提供低延时的回放,将变化后的声音播放给主播听.对声音处理的方案比较多,这里介绍一下金山云直播SDK中所采用的基于iOS提供的AudioUnit的方案。

iOS系统提供了非常丰富的音频相关的API,涵盖了从采集,处理到播放等各个环节,并且按照需求的层次进行了分组。

图1. Core Audio Overview

其中,离底层的驱动和硬件最近的就是AudioUnit系列的API,很多其他高层的API,都是对AudioUnit的封装. 比如AVFoundation、AudioQueue、AVAudioEngine等。

缺点:

涉及到的专有概念比较多,接口复杂

提供C风格的API

优点:

低延时,从采集到播放回环可以到10ms的级别

可以动态变更配置组合

可以直接获得后台执行权限

1、AudioUnit简介

AudioUnit这个名字取得还是比较形象的,它的主体就是一系列的unit,不同unit能够实现不同的功能,将一个或多个unit添加到AUGraph(Audio Processing Graph)中,并建立unit之间的连接,音频数据顺次通过各个节点即可完成我们最终需求。

图2. AudioUnit in iOS
iOS系统一共提供了如下4类unit。

其中,I/O主要负责和设备打交道,比如采集和播放;Mixing负责将不同来源的音频数据进行混合;Effect是对音频数据进行音效处理;Format Conversion主要是进行格式转换比如重采样等。这里有一个优化的点是音频格式转换 Multichannel Mixer 本身就能够实现格式转换的功能,输入和输出的音频数据格式可以不同,利用这一点可以节省一个格式转换unit。

使用AudioUnit进行音频采集

在直播应用中,我们主要是使用Remote I/O unit来进行采集工作。 在一个AUGraph中只允许有一个I/O unit。Remote I/O需要同时负责采集和播放的功能。当用户开启耳返功能时,要将采集到的声音,处理之后再送回当前节点直接播放,这样可以将采集和播放的延时控制在50ms以内,主播才察觉不到声音的延时。

基本的步骤如下:

  1. 实例化AUGraph,将用到units添加进去;

  2. 配置每个AudioUnit的属性;

  3. 设置Render Callback Function;

4.将units 建立连接;

5.启动AUGraph。

以上过程大家都可以到Apple官方的文档中找到具体的说明和代码示例。

在直播录制中比较关键的一步就是Render Callback Function。

AudioUnit每次都是处理一段音频数据,每次处理完成一段数据的时候,这个回调函数就会被调用一次。在这个回调函数中,通过AudioUnit的AudioUnitRender方法,可以AUGraph中的某一个节点中获取到一段处理后的音频PCM数据。同时,如果需要进行耳返播放,在这个回调中也需要将取得的音频数据送入到回调函数的最后一个参数ioData对应的buffer中。

在设置unit的属性时,需要注意的是一些公共的属性。比如音频格式属性和MaximumFramesPerSlice。如果音频格式设置错误,往往会出现AUGraph启动失败或者声音异常等问题。比如,使用iOS内置的麦克风或者有线耳机时,设备支持的采样率比较高,44.1KHz 能正常工作,我们整条音频通路上基本上都采用的是44.1KHz。但是当使用蓝牙设备时,一般蓝牙设备无法支持44.1KHz采集和播放,通常都是16KHz甚至更低。此时I/O Unit无法继续使用之前的配置。需要按照实际支持的采样率进行配置。

AudioUnit还要求两个单元衔接处的音频数据格式必须保持一致,当AUGraph中不同unit支持的格式不同时(比如在支持蓝牙设备或者使用回声消除模块时,I/O unit要求的格式和其他单元的有可能不同),此时就需要分别设置格式,并通过格式转换unit或mixer unit对格式进行转换。

如果MaximumFramesPerSlice设置错误,可能会出现声音异常的情况。 MaximumFramesPerSlice 表示的是每次回调送入或取出的音频数据的长度,在AUGraph的所有节点的这个属性也需要保持一致否则会导致有的unit丢弃数据,而出现声音异常 。

1、使用AudioUnit进行音效处理

这里所谓的音效处理,主要是指对原本的声音进行一些改变,比如混响效果,变声效果等。用到手段主要是数字信号处理提供的一系列时间和频域的工具,将输入的PCM数据经过运算后得到变化后的声音。

4.1 混响效果(reverberation)

我们在音乐厅,剧院,礼堂等比较空旷的室内说话或唱歌时,往往能听到和平时不一样的声音,主要是声音在墙壁上多次反射后叠加在一起,听起来就有了混响的效果。在声音处理中,我们可以人为的将声音缓存起来,延时一定时间后,和原声音叠加,就能够模拟出混响的效果。AudioUnit提供了kAudioUnitSubType_Reverb2来实现混响效果的生成。将该unit接入到AUGraph中之后,配置参数即可实现混响的效果。虽然混响原理是比较简单,但实际上为了模拟自然界中实际的音效,计算过程还是相当复杂的,要模拟出不同的大小的空间,不同材质的墙壁,障碍物的多少,需要输入比较多的参数来参与运算。iOS的reverb unit提供了7个参数。我们在直播应用中提供了4个不同场景的模拟(录音棚,演唱会,KTV,小舞台),主要是通过调整如下参数实现的:

kReverb2Param_DryWetMix混响效果声的大小与空间大小无关,而只与空间内杂物的多少以及墙壁及物体的材质有关;

kReverb2Param_DecayTimeAt0Hz / kReverb2Param_DecayTimeAtNyquist衰减时间,整个混响的总长度,与空间大小比较相关,越空旷越长。

4.2 变声效果

变声效果主要是在频域上对人的声音进行一定的处理,我们知道男声一般比较低沉,女声比较尖锐,这个主要说的是音调。通过对声音音调的调整,可以让低沉的男声听上去像尖锐女声。iOS提供了kAudioUnitSubType_NewTimePitch的unit来实现音调的调整。值得注意的是kAudioUnitSubType_NewTimePitch不是输入Effect类的,而是属于FormatConverter类的。通过设置TimePitch unit的kNewTimePitchParam_Pitch属性即可。

/// pitchShift为具体数值(0表示不变,负数表明调低沉,正数调尖锐)AudioUnitSetParameter(pitchUnit, kNewTimePitchParam_Pitch, kAudioUnitScope_Global, 0, pitchShift, 0);

变男声,需要强化突出低沉的特点,将音调调低,设置负数参数即可;

变女声,需要强化突出尖锐的特点,将音调调高,设置正数即可;

机器人音效,机器人的音效是一个组合效果,我们印象中的机器人音效都是老电影中的那种,音调比较高,而且有重音。所以我们采用的是TimePitch unit + Delay unit的方式。Delay unit也是iOS提供的一个将声音延时叠加的unit,但是比混音要简单很多,只有单次叠加;

庄严宏大音效,想象一下佛祖之类的声音,一般都是自带回声,而且比较男性化,所以我们选择的是TimePitch unit + Reverb unit的方式来实现。

这里推荐一个自己调音效的参考软件voxal voice changer。大家可以在这个软件上自己将不同的工具组件组合起来,调试参数,实时听到参数对应的结果。当效果满意后再移植到AudioUnit中。


图3 voixal voice changer

总结

以上大概介绍了怎么用AudioUnit来实现iOS直播中的音频采集,怎么使用AudioUnit中的音效组件来实现混响和变声效果。但是AudioUnit的潜力还远没有挖掘完,比如还可以将背景音乐播放,混音,回声消除等其他移动多媒体音频相关的功能纳入到这个框架中。

iOS音频采集过程中的音效实现的更多相关文章

  1. jenkins自动化构建iOS应用配置过程中遇到的问题

    最近配置jenkins来自动构建iOS应用,期间遇上不少问题.在这里分享给大家,也给自己留个底,方便下次解决问题. 首先说明下基本情况,我们因为部署jenkins的机器不是Mac,所以不能安装Xcod ...

  2. ios授权登录过程中一直提示“没有安装qq”

    遇到问题:http://www.cocoachina.com/ask/questions/show/107029 之前都登录都很正常,这两天突然出现这个问题,没有安装qq软件的iphone手机上登录的 ...

  3. alsa音频播放过程中的基本概念

    以下为 ALSA-Project/FramesPeriods[1] 学习笔记 1, sample_rate: 即每秒进行多少次采样,常见的比如 8000.16000.44100和48000等 2, s ...

  4. iOS 集成支付宝过程中 我遇到的一些坑,请大家注意啦(ALI69错误,ALI64错误)

    支付宝很早一段时间就集成了,之前由于一直忙于开发就没有总结,今天整理桌面的时候看到,当时做支付时候的一些散落的笔记,就稍微整理一下,给大家分享一下. 第一:当时调用支付宝的时候,总是调不起来,进过断点 ...

  5. 一篇对iOS音频比较完善的文章

    转自:http://www.cnblogs.com/iOS-mt/p/4268532.html 感谢作者:梦想通 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也 ...

  6. IOS 音频播放

    iOS音频播放 (一):概述 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也因此对于iOS下的音频播放实现有了一定的研究.写这个系列的博客目的一方面希望能够抛砖 ...

  7. iOS音频播放 (五):AudioQueue

    码农人生 ChengYin's coding life 主页 Blog 分类 Categories 归档 Archives 关于 About Weibo GitHub RSS Where there ...

  8. 3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终解决方案

    根据之前解析的循环依赖的源码, 分析了一级缓存,二级缓存,三级缓存的作用以及如何解决循环依赖的. 然而在多线程的情况下, Spring在创建bean的过程中, 可能会读取到不完整的bean. 下面, ...

  9. iOS 实时音频采集与播放Audio Unit使用

    前言 在iOS中有很多方法可以进行音视频采集.如 AVCaptureDevice, AudioQueue以及Audio Unit.其中 Audio Unit是最底层的接口,它的优点是功能强大,延迟低; ...

随机推荐

  1. JavaScript学习笔记(十五)——对象之Date,RegExp

    在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...

  2. 简单模板view调用

    $this->display();//模板名称与当前控制器.当前操作方法的名称不一致 $this->display();//调用当前控制器对应目录指定名称的模板 $this->dis ...

  3. 洛谷最短路计数SPFA

    题目描述 给出一个N个顶点M条边的无向无权图,顶点编号为1-N.问从顶点1开始,到其他每个点的最短路有几条. 输入输出格式 输入格式: 输入第一行包含2个正整数N,M,为图的顶点数与边数. 接下来M行 ...

  4. 关于hue安装后出现KeyError: "Couldn't get user id for user hue"的解决方法

    首先说明出现此问题的原因是因为你使用的root用户安装了hue,然后在root用户下使用的build/env/bin/supervisor,如下图所示那样: 知道了原因,就容易解决问题了.首先要创建个 ...

  5. Python的列表

    1. Python的列表简介 1. 1 列表的定义 列表是Python中最基本的数据结构,列表是最常用的Python数据类型,列表的数据项不需要具有相同的类型.列表中的每个元素都分配一个数字 ,即它的 ...

  6. Android数据绑定技二,企业级开发

    PS:上一篇文章写了Databinding的简单使用,写了一个绑定textview的示例,和绑定的一些用法,估计有的人会说,之前的写的好好的,为什么要数据绑定这样的写法呢,没办法,社会在进步,当然是怎 ...

  7. Java 面试宝典

    1. 类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,他们的执行顺序 答:先静态.先父后子. 先静态:父静态 > 子静态 优先级:父类 > 子类 静态代码块 ...

  8. Python源代码剖析笔记3-Python运行原理初探

    Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...

  9. 【CODEFORCES】 A. Dreamoon and Sums

    A. Dreamoon and Sums time limit per test 1.5 seconds memory limit per test 256 megabytes input stand ...

  10. linux启动失败

    如图 1.开机界面 按 e 键 2.选择第二个进入就好了 根据网上说的修改kernel 配置  加上 enforcing=0 无效 1.进入界面后再按 e 键 3.选择第二个按e键进入编辑 界面 每次 ...