AUGraph结合RemoteI/O Unit与Mixer Unit

前言

相关文章:
使用VideoToolbox硬编码H.264
使用VideoToolbox硬解码H.264
使用AudioToolbox编码AAC
使用AudioToolbox播放AAC
HLS点播实现(H.264和AAC码流)
HLS推流的实现(iOS和OS X系统)
iOS在线音频流播放
Audio Unit播放PCM文件
Audio Unit录音(播放伴奏+耳返)
Audio Unit播放aac/m4a/mp3等文件
Audio Unit和ExtendedAudioFile播放音频
前文介绍了AudioUnit的录音/播放、AudioConvert进行音频转换、ExtendedAudioFile进行音频文件的读/写,其中AudioUnit的初始化都是通过AudioComponentInstanceNew实现,实际工程中更多使用的是AUGraph的方式进行AudioUnit的初始化。
本文尝试用AUGraph来管理RemoteI/O Unit和Mixer Unit,实现录音、伴奏播放、人声和伴奏混合的功能。

基础结构图

正文

1、概念介绍

AUGraph连接一组 audio unit 之间的输入和输出,构成一张图,同时也为audio unit 的输入提供了回调。AUGraph抽象了音频流的处理过程,子结构可以作为一个AUNode嵌入到更大的结构里面进行处理。AUGraph可以遍历整个图的信息,每个节点都是一个或者多个AUNode,音频数据在点与点之间流通,并且每个图都有一个输出节点。输出节点可以用来启动、停止整个处理过程。

每个AudioUnit都有Input, Output 和 Global 三个域。
input输入域是音频流进入unit的入口,output输出域是音频流离开unit的出口,global全局域则代表整个unit。
输入域和输出域都有若干个bus/element,比如说mixer unit有多个输入bus,只有一个输出bus;而splitter unit则有一个输入bus,有多个输出的bus。

注意的是,bus和channel不是一个东西,一个是音频流,一个是音频流的格式。
比如说Remote I/O Unit的输入域的inputBus是来自麦克风的音频流,其音频格式是双声道。

2、具体流程

  • 1、初始化文件流和AVAudioSession,分配buffer;
  • 2、新建AUGraph,并添加两个AUNode,一个是RemoteI/O Unit的节点,一个是Mixer Unit的节点。
    添加AUNode的节点有两个步骤,先通过AUGraphAddNode添加节点,再通过AUGraphNodeInfo获取节点对应的AudioUnit。
  • 3、建立两个AUNode的联系,AUGraphConnectNodeInput通过把Mixer Unit的outputBus的输出作为RemoteI/O Unit的outputBus的输入;
    (这里需要注意,不是RemoteI/O的inputBus 的输入,因为RemoteI/O Unit的inputBus的输入是麦克风)
    同时设置好RemoteI/O Unit的输入和输出格式、Record的回调函数;
  • 4、调用AUGraphInitialize初始化AUGraph,然后通过AUGraphStart开始整个AUGraph;
    在AUGraph开启后,麦克风收到录制数据后调用kAudioOutputUnitProperty_SetInputCallback的回调,把麦克风的数据回调给APP;
    Mixer Unit还会通过之前kAudioUnitProperty_SetRenderCallback设置好的回调,要求APP填充两个inputBus的输入;
    在Mixer Unit处理好数据之后,会按照之前AUGraphConnectNodeInput设置的,把数据发送给Remote I/O Unit;
    Remote I/O Unit再把数据发送给扬声器。

3、音频流解析

如下,是整个demo的音频流向:



伴奏文件被读取到内存,再被送到MixUnit的inputBus0;
麦克风录取到音频数据,送到Remote I/O Unit的inputBus,存到内存中,再被送到MixUnit的inputBus1;
MixUnit混合两个inputBus的数据,通过outputBus输出到Remote I/O Unit的outputBus中;
Remote I/O Unit再把outputBus的数据发送个扬声器。

遇到的问题

1、AUGraphNodeInfo无法初始化AudioUnit

实际运行时,报错是AudioUnitSetProperty方法,返回了-50的错误码。
检查错误码,是AudioUnitSetProperty的audio unit参数为空。
往上回溯,定位到AUGraphNodeInfo没正确初始化传入的audio unit参数,导致audio unit为空,并且当时没有报错,直到AudioUnitSetProperty时才报错。

经过仔细检查,发现是AUGraphOpen方法被遗漏。
必须先打开AUGraph,才进行获取AudioUnit的操作。

2、AUGraphSetNodeInputCallback给RemoteI/O Unit设置回调无效

如下,给RemoteI/O Unit设置回调可以用AudioUnitSetProperty方法修改kAudioOutputUnitProperty_SetInputCallback设置回调,但尝试用AUGraphSetNodeInputCallback对RemoteI/O Unit节点添加回调的时候,发现没法正常调用回调函数。

    AURenderCallbackStruct recordCallback;
    recordCallback.inputProc = RecordCallback;
    recordCallback.inputProcRefCon = (__bridge void *)self;
    
//    CheckError(AUGraphSetNodeInputCallback(auGraph, outputNode, INPUT_BUS, &recordCallback), "record callback set fail");  // 这个不行,因为scope不一致
    CheckError(AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Output, INPUT_BUS, &recordCallback, sizeof(recordCallback)), "set property fail");

AUGraphSetNodeInputCallback 默认是inputScope,如果在input bus的inputScope修改属性,会造成异常现象;

3、kAudioOutputUnitProperty_SetInputCallback 和 kAudioUnitProperty_SetRenderCallback 混淆

  • kAudioUnitProperty_SetRenderCallback 是audio unit需要数据,向Host请求数据;
  • kAudioOutputUnitProperty_SetInputCallback是audio unit通知Host数据已经就绪,可以通过AudioUnitRender拉取数据;

AudioUnitRender的解释是:Initiates a rendering cycle for an audio unit.
下图阐释了AudioUnit是如何通过AudioUnitRender去Pull音频流数据

4、AUGraphConnectNodeInput的BUS参数设置错误

AUGraphConnectNodeInput(auGraph, mixNode, OUTPUT_BUS, outputNode, OUTPUT_BUS),从字面看是把mixNode的输出作为outputNode的输入。
但是在bus的参数设置上,为什么Remote I/O Unit的bus不是inputBus?
因为Remote I/O Unit有输入域有两个Bus,inputBus对应的是麦克风的输入,outputBus对应的是app发送给Remote I/O Unit的数据。
这里Mixer Unit是把人声和伴奏混合后,输出给Remote I/O Unit,相当于app发送数据给Remote I/O Unit,所以这里应该填outputBus。

总结

demo中仍然存在问题,因为两个unit结构混乱:
麦克风=>I/O Unit=>APP=>MixUnit
文件=>APP=>MixUnit
然后再是MixUnit=>I/O Unit=>扬声器
其中,I/O Unit既指向MixUnit,同时MixUnit又指向I/O Unit。
更好的实现方案,用一个Unit来实现录音,再用另外一个Unit进行播放,形成 RecordUnit=>MixUnit=>PlayUnit这样的结构会更加漂亮。
这个设想就交由你去实现了!
demo的代码点击这里书写不易,不如来个喜欢支持下↓↓

附录

Core Audio Tips
Audio Unit Properties Reference PDF
Audio Unit Hosting Guide for iOS

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 本例需求:将Mic采集的PCM转成AAC,可得到两种不同数据,本例采用AudioQueue/AudioUnit两种...
    小东邪啊阅读 18,354评论 67 54
  • 一、Audio Unit综述1.1、Audio Unit 概念点1.2、 AuidoUnit类型二、构建Audio...
    _羊羽_阅读 6,718评论 3 17
  • 前言 相关文章:使用VideoToolbox硬编码H.264使用VideoToolbox硬解码H.264使用Aud...
    落影loyinglin阅读 13,135评论 21 38
  • 国人一直都在改变世人看法,提高全民素质,但意识不该谈何容易。 环保在中国,刚刚起步。实行困难重重的,一个塑料袋引发...
    19号淡然阅读 360评论 0 0
  • 俺觉得有些同学,是青翠的故事 记忆泛黄了,不影响 他们是树,是草,是花,是鸟 是一片茂密森林 他们随风摇动百家姓中...
    乔桥阅读 297评论 3 4