iOS实时音频采集与播放
1、前言
在iOS中有很多方法可以进行音视频采集。如AVCaptureDevice,AudioQueue以及AudioUnit。其中AudioUnit是最底层的接口,它的优点是功能强大,延迟低;而缺点是学习成本高,难度大。对于一般的iOS应用程序,AVCaptureDevice和AudioQueue完全够用了。但对于音视频直播,最好还是使用AudioUnit进行处理,这样可以达到最佳的效果,著名的WebRTC就使用的AudioUnit做的音频采集与播放。今天我们就重点介绍一下AudioUnit的基本知识和使用。
下图是AudioUnit在iOS架构中所处的位置:
2、基本概念
在介绍AudioUnit如何使用之前,先要介绍一下AudioUnit的基本概念,这样更有利于我们理解对它的使用。AudioUnit的种类AudioUnits共可分为四大类,並可细分为七种,可参考下表:AudoUnit的内部结构参考下图,AudioUnit内部结构分为两大部分,Scope与Element。其中scope又分三种,分別是inputscope,outputscope,globalscope。而element则是inputscope或outputscope內的一部分。
AudioUnit的输入与输出下图是一个IOtype的AudioUnit,其输入为麦克风,其输出为喇叭。这是一个最简单的AudioUnit使用范例。Theinputelementiselement1(mnemonicdevice:theletterIofthewordInputhasanappearancesimilartothenumber1)Theoutputelementiselement0(mnemonicdevice:theletterOofthewordOutputhasanappearancesimilartothenumber0)3、使用流程概要描述音频元件kAudioUnitTypeOutputkAudioUnitSubTypeRemoteIOkAudioUnitManufacturerApple使用AudioComponentFindNext(NULL,descriptionOfAudioComponent)获得AudioComponent。AudioComponent有点像生产AudioUnit的工厂。使用AudioComponentInstanceNew(ourComponent,audioUnit)获得AudioUnit实例。使用AudioUnitSetProperty函数为录制和回放开启IO。使用AudioStreamBasicDescription结构体描述音频格式,并使用AudioUnitSetProperty进行设置。使用AudioUnitSetProperty设置音频录制与放播的回调函数。分配缓冲区。初始化AudioUnit。启动AudioUnit。
C音视频学习资料免费获取方法:关注音视频开发T哥,点击链接即可免费获取2023年最新C音视频开发进阶独家免费学习大礼包!4、初始化
初始化看起来像下面这样。我们有一个AudioComponentInstance类型的成员变量,它用于存储AudioUnit。
下面的音频格式用16位表式一个采样。definekOutputBus0definekInputBus1。。。OSStatusstatus;AudioComponentInstanceaudioUnit;描述音频元件AudioComponentDescriptiondesc;desc。componentTypekAudioUnitTypeOutput;desc。componentSubTypekAudioUnitSubTypeRemoteIO;desc。componentFlags0;desc。componentFlagsMask0;desc。componentManufacturerkAudioUnitManufacturerApple;获得一个元件AudioComponentinputComponentAudioComponentFindNext(NULL,desc);获得AudioUnitstatusAudioComponentInstanceNew(inputComponent,audioUnit);checkStatus(status);为录制打开IOUInt32flag1;statusAudioUnitSetProperty(audioUnit,kAudioOutputUnitPropertyEnableIO,kAudioUnitScopeInput,kInputBus,flag,sizeof(flag));checkStatus(status);为播放打开IOstatusAudioUnitSetProperty(audioUnit,kAudioOutputUnitPropertyEnableIO,kAudioUnitScopeOutput,kOutputBus,flag,sizeof(flag));checkStatus(status);描述格式audioFormat。mSampleRate44100。00;audioFormat。mFormatIDkAudioFormatLinearPCM;audioFormat。mFormatFlagskAudioFormatFlagIsSignedIntegerkAudioFormatFlagIsPacked;audioFormat。mFramesPerPacket1;audioFormat。mChannelsPerFrame1;audioFormat。mBitsPerChannel16;audioFormat。mBytesPerPacket2;audioFormat。mBytesPerFrame2;设置格式statusAudioUnitSetProperty(audioUnit,kAudioUnitPropertyStreamFormat,kAudioUnitScopeOutput,kInputBus,audioFormat,sizeof(audioFormat));checkStatus(status);statusAudioUnitSetProperty(audioUnit,kAudioUnitPropertyStreamFormat,kAudioUnitScopeInput,kOutputBus,audioFormat,sizeof(audioFormat));checkStatus(status);设置数据采集回调函数AURenderCallbackStructcallbackStruct;callbackStruct。inputProcrecordingCallback;callbackStruct。inputProcRefConself;statusAudioUnitSetProperty(audioUnit,kAudioOutputUnitPropertySetInputCallback,kAudioUnitScopeGlobal,kInputBus,callbackStruct,sizeof(callbackStruct));checkStatus(status);设置声音输出回调函数。当speaker需要数据时就会调用回调函数去获取数据。它是拉数据的概念。callbackStruct。inputProcplaybackCallback;callbackStruct。inputProcRefConself;statusAudioUnitSetProperty(audioUnit,kAudioUnitPropertySetRenderCallback,kAudioUnitScopeGlobal,kOutputBus,callbackStruct,sizeof(callbackStruct));checkStatus(status);关闭为录制分配的缓冲区(我们想使用我们自己分配的)flag0;statusAudioUnitSetProperty(audioUnit,kAudioUnitPropertyShouldAllocateBuffer,kAudioUnitScopeOutput,kInputBus,flag,sizeof(flag));初始化statusAudioUnitInitialize(audioUnit);checkStatus(status);
开启AudioUnitOSStatusstatusAudioOutputUnitStart(audioUnit);checkStatus(status);
关闭AudioUnitOSStatusstatusAudioOutputUnitStop(audioUnit);checkStatus(status);
结束AudioUnitAudioComponentInstanceDispose(audioUnit);5、录制回调staticOSStatusrecordingCallback(voidinRefCon,AudioUnitRenderActionFlagsioActionFlags,constAudioTimeStampinTimeStamp,UInt32inBusNumber,UInt32inNumberFrames,AudioBufferListioData){TODO:使用inNumberFrames计算有多少数据是有效的在AudioBufferList里存放着更多的有效空间AudioBufferListbufferList;bufferList里存放着一堆buffers,buffers的长度是动态的。获得录制的采样数据OSStatusstatus;statusAudioUnitRender(〔audioInterfaceaudioUnit〕,ioActionFlags,inTimeStamp,inBusNumber,inNumberFrames,bufferList);checkStatus(status);现在,我们想要的采样数据已经在bufferList中的buffers中了。DoStuffWithTheRecordedAudio(bufferList);returnnoErr;}6、播放回调staticOSStatusplaybackCallback(voidinRefCon,AudioUnitRenderActionFlagsioActionFlags,constAudioTimeStampinTimeStamp,UInt32inBusNumber,UInt32inNumberFrames,AudioBufferListioData){Notes:ioData包括了一堆buffers尽可能多的向ioData中填充数据,记得设置每个buffer的大小要与buffer匹配好。returnnoErr;}7、结束
AudioUnit可以做很多非常棒的的工作。如混音,音频特效,录制等等。它处于iOS开发架构的底层,特别合适于音视频直播这种场景中使用。
我们今天介绍的只是AudioUnit众多功能中的一小点知识,但这一点点知识对于我来说已经够用了。对于那些想了解更多AudioUnit的人,只好自行去google了。
知识无穷尽,只取我所需。这就是我的思想,哈!
原文链接:iOS实时音频采集与播放
正常听力不好配多少钱的助听器合适?助听器有很多种,价格从几百元到几万元的都有,那么为了排除这种烦恼,你最好去专业的正规的助听器验配店,她们会根据你家人的听力情况,以及你想要助听器解决哪些主要的问题来帮助你选择的,但
美术老师工资多少合适?你好亲,很开心回答你的问题美术老师分为中小学美术老师,大学美术老师,高考美术专业老师,课外培训机构的美术老师如果是中小学美术老师,编制内都是固定的工资,基本工资,五险一金,年终奖等
汽车倒车的时候,里程数是增大还是不变,还是减小?以前的机械式里程表有两种一种是所谓的死轴,前进正转,倒车反转(里程数减少)。(以前有些二手车贩子把软轴卡在手枪钻上修改里程)。另一种是活轴,计数器只能正转,倒车时计数器不转。而现在
怀孕三个月过后就不用保胎了吗?首先,这里需要纠正的是三个月只是指在怀孕的十二周之后,胎儿的情况会慢慢稳定下来,根据实际情况,可以适当有性生活,而做其它的事情对胎儿的影响也相对较小。但小并不代表没有。因此,对于孕
4k液晶电视机有推荐品牌吗?现在家庭日常选品的清晰度都要求越来越清晰,液晶屏的观看效果会更舒适,所以现在国民电视机选款都会从4K液晶电视入手。在目前的国民电视机品牌中,新产品层出不穷,不断更新迭代。其中TCL
如何培养企业优秀的中层管理人才?一在培养之前首先要回答三个问题公司需要什么样的中层管理者?如何鉴定优秀?这一方面需要考虑到今天是否能够提供绩效,更重要的是要考虑到公司在未来的发展当中最需要什么样的人才,特别是在价
中层干部很难再进入高层,不是经验和能力的问题,而是做人格局和做事立场,你怎么看?中层干部进入高层,经验和能力是敲门砖,没有经验和能力,做人的格局和做事的立场都是虚的。所以,想要进入高层,经验和能力是必备品,怎么会不是经验和能力的问题?只是,仅仅凭借经验和能力,
特斯拉爆发大规模召回,问题频频依然销量猛涨,到底有何魔力?没有自己的电动新能源的核心技术,比如电池,电机和电控都生产不了,全是从其它工厂买来在东拼西凑的组装后销售,粗制滥造导致质量问题频发,特别是刹车失灵这种小问题都搞不好,靠的就是水军胡
政信类信托产品有哪些?你好,产品很多,下面有列表您自行查看。项目地类型项目名称分档收益规模期限付息江苏镇江政信国企央企信托镇江丹徒1006。21。5亿12月年付湖南怀化政信国企央企信托湖南怀化集合资金信
作为技术部门,我们比行政部门的地位还要低很多,这样的公司还要继续呆下去吗?客观的说,一直以来,大多数技术人才都屈居行政部门之下,因为行政部门靠文件和制度管理公司,偏向于务虚,且行政部门与技术部门没有太紧密的工作联系,所以行政部门相对来说是独立于技术之外的
那些高中早恋的人后来怎么样了?恋爱是人生最美好的事之一。高中时期的恋爱更是美中之美。只是美到及至,必将走向反面。高中早恋结果多令人叹息。我身边就有许多这样的例子,我把他们的状况分成几类,与大家分享。第一类两情相