音频下载网站源码分享,免费下载音频网站

大家好,关于音频下载网站源码分享很多朋友都还不太明白,今天小编就来为大家分享关于免费下载音频网站的知识,希望对各位有所帮助!

最近一直在做iOS音频相关技术的项目,期间在官方及网上的资料文档也学习了很多,当然,iOS平台中音频相关技术还是有很多方面的,这里我先总体概述下,然后以I/OAudioUnit为例对其概念,基本用法和思路进行讲解,可能不够全面,一些细节需要自行查找相关文档。后面我会对github上一个开源的音频引擎框架进行源码分析,来展现在更复杂的音频技术应用场景下可能的设计及实现方式。

本文图片及大部分技术概念阐述均来自apple官网

1、CoreAudio

CoreAudio是iOS和MAC系统中的关于数字音频处理的基础设施,它是应用程序用来处理音频的一组软件框架,所有关于iOS音频开发的接口都是由CoreAudio来提供或者经过它提供的接口来进行封装的。Apple官方对CoreAudio的框架分层图示如下:

core_audio_layers.png

2、Low-Level

该主要在MAC上的音频APP实现中并且需要最大限度的实时性能的情况下使用,大部分音频APP不需要使用该层的服务。而且,在iOS上也提供了具备较高实时性能的高层API达到你的需求。例如OpenAL,在游戏中具备与I/O直接调用的实时音频处理能力I/OKit,与硬件驱动交互AudioHAL,音频硬件抽象层,使API调用与实际硬件相分离,保持独立CoreMIDI,为MIDI流和设备提供软件抽象工作层HostTimeServices,访问电脑硬件时钟

3、Mid-Level

该层功能比较齐全,包括音频数据格式转换,音频文件读写,音频流解析,插件工作支持等AudioConvertServices负责音频数据格式的转换AudioFileServices负责音频数据的读写AudioUnitServicesAudioProcessingGraphServices支持均衡器和混音器等数字信号处理的插件AudioFileScreamServices负责流解析CoreAudioClockServices负责音频音频时钟同步

4、High-Level

是一组从低层接口组合起来的高层应用,基本上我们很多关于音频开发的工作在这一层就可以完成AudioQueueServices提供录制、播放、暂停、循环、和同步音频它自动采用必要的编解码器处理压缩的音频格式AVAudioPlayer是专为IOS平台提供的基于Objective-C接口的音频播放类,可以支持iOS所支持的所有音频的播放ExtendedAudioFileServices由AudioFile与AudioConverter组合而成,提供压缩及无压缩音频文件的读写能力OpenAL是CoreAudio对OpenAL标准的实现,可以播放3D混音效果

5、不同场景所需要的APIService

只实现音频的播放,没有其他需求,AVAudioPlayer就可以满足需求。它的接口使用简单,不用关心其中的细节,通常只提供给它一个播放源的URL地址,并且调用其play、pause、stop等方法进行控制,observer其播放状态更新UI即可

APP需要对音频进行流播放,就需要AudioFileStreamer加AudioQueue,将网络或者本地的流读取到内存,提交给AudioFileStreamer解析分离音频帧,分离出来的音频帧可以送给AudioQueue进行解码和播放可参考AudioStreamerFreeStreamerAFSoundManager

APP需要需要对音频施加音效(均衡器、混响器),就是除了数据的读取和解析以外还需要用到AudioConverter或者Codec来把音频数据转换成PCM数据,再由AudioUnit+AUGraph来进行音效处理和播放可参考DouAudioStreamerTheAmazingAudioEngineAudioKit

6、AudioUnit

iOS提供了混音、均衡、格式转换、实时IO录制、回放、离线渲染、语音对讲(VoIP)等音频处理插件,它们都属于不同的AudioUnit,支持动态载入和使用。AudioUnit可以单独创建使用,但更多的是被组合使用在AudioProcessingGraph容器中以达到多样的处理需要,例如下面的一种场景:

APP持有的AudioProcessingGraph容器中包含两个EQUnit、一个MixerUnit、一个I/OUnit,APP将磁盘或者网络中的两路流数据分别通过EQUnit进行均衡处理,然后在MixerUnit经过混音处理为一路,进入I/OUnit将此路数据送往硬件去播放。在这整个流程中,APP随时可以调整设置AUGraph及其中每个Unit的工作状态及参数,动态性的接入或者移出指定的Unit,并且保证线程安全。

C++音视频学习资料免费获取方法:关注音视频开发T哥,点击「链接」即可免费获取2023年最新C++音视频开发进阶独家免费学习大礼包!

6.1AudioUnit类型:

I/O:RemoteI/O、Voice-ProcessingI/O、GenericOutputMixing:3DMixer、MutichannelMixerEffect:iPodEqualizerFormatConversion:FormatConverter

6.2AudioUnit构建方式

创建AudioUnit有两种途径,以I/OUnit为例,一种是直接调用unit接口创建,一种是通过AudioUnitGraph创建,下面是两种创建方式的基本流程和相关代码:

6.3UnitAPI方式(RemoteIOUnit)

//createIOUnit\nBOOLresult=NO;\nAudioComponentDescriptionoutputDescription={0};\noutputDescription.componentType=kAudioUnitType_Output;\noutputDescription.componentSubType=kAudioUnitSubType_RemoteIO;\noutputDescription.componentManufacturer=kAudioUnitManufacturer_Apple;\noutputDescription.componentFlags=0;\noutputDescription.componentFlagsMask=0;\nAudioComponentcomp=AudioComponentFindNext(NULL,&outputDescription);\nresult=CheckOSStatus(AudioComponentInstanceNew(comp,&mVoipUnit),@&39;tcreateanewinstanceofRemoteIO&34;couldnotenableoutputonRemoteIO&34;AudioUnitSetPropertyEnableIO&34;couldn&34;);\nif(!result)returnresult;\nresult=CheckOSStatus(AudioUnitSetProperty(mVoipUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,kOutputBus,&outputAudioDescription,sizeof(outputAudioDescription)),@&39;tsettheoutputclientformatonRemoteIO&34;couldn&34;);\nif(!result)returnresult;\n\n//Settherecordcallback\nAURenderCallbackStructrecordCallback;\nrecordCallback.inputProc=recordCallbackFunc;\nrecordCallback.inputProcRefCon=(__bridgevoid*_Nullable)(self);\nresult=CheckOSStatus(AudioUnitSetProperty(mVoipUnit,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Global,kInputBus,&recordCallback,sizeof(recordCallback)),@&39;tsetrecordcallbackonRemoteIO&34;couldn&34;);\nif(!result)returnresult;\n\n//setbufferallocate\nflag=0;\nresult=CheckOSStatus(AudioUnitSetProperty(mVoipUnit,\nkAudioUnitProperty_ShouldAllocateBuffer,\nkAudioUnitScope_Output,\nkInputBus,\n&flag,\nsizeof(flag)),@&39;tsetpropertyforShouldAllocateBuffer&34;couldn&34;);\nif(!result)returnresult;\n\nreturnYES;

6.4AUGraph方式(MultiChannelMixerUnit+RemoteIOUnit)

//createAUGraph\nBOOLresult=NO;\nresult=CheckOSStatus(NewAUGraph(&processingGraph),@&39;tcreateanewinstanceofAUGraph&34;couldn&34;);\nif(!result)returnresult;\n\nresult=CheckOSStatus(AUGraphAddNode(\nprocessingGraph,\n&MixerUnitDescription,\n&mixerNode),@&39;taddanodeinstanceofmixerunit&34;couldn&34;);\nif(!result)returnresult;\n\n//Obtainunitinstance\nresult=CheckOSStatus(AUGraphNodeInfo(\nprocessingGraph,\nmixerNode,\nNULL,\n&mMixerUnit\n),@&39;tgetinstanceofmixerunit&34;couldn&34;);\nif(!result)returnresult;\n\n/////////////////////////////////////////////////////////////////////////////////////////\n\nUInt32busCount=2;//buscountformixerunitinput\nUInt32guitarBus=0;//mixerunitbus0willbestereoandwilltaketheguitarsound\nUInt32beatsBus=1;//mixerunitbus1willbemonoandwilltakethebeatssound\nresult=CheckOSStatus(AudioUnitSetProperty(\nmMixerUnit,\nkAudioUnitProperty_ElementCount,\nkAudioUnitScope_Input,\n0,\n&busCount,\nsizeof(busCount)\n),@&34;);\nif(!result)returnresult;\n\nUInt32maximumFramesPerSlice=4096;\nresult=CheckOSStatus(AudioUnitSetProperty(\nmMixerUnit,\nkAudioUnitProperty_MaximumFramesPerSlice,\nkAudioUnitScope_Global,\n0,\n&maximumFramesPerSlice,\nsizeof(maximumFramesPerSlice)\n),@&34;);\nif(!result)returnresult;\n\n\n//Attachtheinputrendercallbackandcontexttoeachinputbus\nfor(UInt16busNumber=0;busNumber<busCount;++busNumber){\n\n//Setupthestruturethatcontainstheinputrendercallback\nAURenderCallbackStructplaybackCallback;\nplaybackCallback.inputProc=playbackCallbackFunc;\nplaybackCallback.inputProcRefCon=(__bridgevoid*_Nullable)(self);\n\nNSLog(@&34;,busNumber);\n//Setacallbackforthespecifiednode&34;couldn&34;);\nif(!result)returnresult;\n}\n\n\n//Configmixerunitinputdefaultformat\nresult=CheckOSStatus(AudioUnitSetProperty(\nmMixerUnit,\nkAudioUnitProperty_StreamFormat,\nkAudioUnitScope_Input,\nguitarBus,\n&outputAudioDescription,\nsizeof(outputAudioDescription)\n),@&39;tsettheinput0clientformatonmixerunit&34;couldn&34;);\nif(!result)returnresult;\n\nFloat64graphSampleRate=44100.0;//Hertz;\nresult=CheckOSStatus(AudioUnitSetProperty(\nmMixerUnit,\nkAudioUnitProperty_SampleRate,\nkAudioUnitScope_Output,\n0,\n&graphSampleRate,\nsizeof(graphSampleRate)\n),@&39;tsettheoutputclientformatonmixerunit&34;couldnotenableoutputonkAudioUnitSubType_RemoteIO&34;couldnotenableinputonkAudioUnitSubType_RemoteIO&34;couldn&34;);\nif(!result)returnresult;\n\n\nUInt32maxFramesPerSlice=4096;\nresult=CheckOSStatus(AudioUnitSetProperty(mVoipUnit,\nkAudioUnitProperty_MaximumFramesPerSlice,\nkAudioUnitScope_Global,\n0,\n&maxFramesPerSlice,\nsizeof(UInt32)\n),@&39;tsetmaxframespersliceonkAudioUnitSubType_RemoteIO&34;couldn&34;);\nif(!result)returnresult;\n\n//setbufferallocate\nflag=0;\nresult=CheckOSStatus(AudioUnitSetProperty(mVoipUnit,\nkAudioUnitProperty_ShouldAllocateBuffer,\nkAudioUnitScope_Output,\nkInputBus,\n&flag,\nsizeof(flag)),@&39;tsetpropertyforShouldAllocateBuffer&34;couldn&34;);\nif(!result)returnresult;\n\nresult=CheckOSStatus(AUGraphInitialize(processingGraph),@&34;);\nif(!result)returnresult;\n\nreturnYES;

6.5AudioUnit数据的输入输出方式

Unit处理音频数据,都要经过一个输入和输出过程,设置输入输出的音频格式(可以相同或者不同),两个Unit对接即是将一个Unit的输入接到另一个Unit的输出,或者将一个Unit的输出接到另一个Unit的输入,需要注意的是在对接点要保证AudioFormat的一致性。以RemoteI/OUnit为例,结构如下图所示:

一个I/OUnit包含两个实体对象,两个实体对象(Element0、Element1)相互独立,根据需求可通过kAudioOutputUnitProperty_EnableIO属性去开关它们。Element1与硬件输入连接,并且Element1的输入域(inputscope)对你不可见,你只能读取它的输出域的数据及设置其输出域的音频格式;Element0与硬件输出连接,并且Element0的输出域(ouputscope)对你不可见,你只能写入它的输入域的数据及设置其输入域的音频格式。

如何将输入设备采集的数据抓出来,又如何将处理后的数据送到输出设备呢?通过AURenderCallbackStruct结构,将定义的两个回调静态方法地址设置到需要的Element0/1上,当Unit配置完毕并且运行后,Unit调度线程会按照当前设备状态及音频格式安排调度周期,循环往复的调用你提供的录制与播放回调方法,样例代码如下:

//forrecordcallback,readaudiodatafrombufferlist\nstaticOSStatusrecordCallbackFunc(void*inRefCon,\nAudioUnitRenderActionFlags*ioActionFlags,\nconstAudioTimeStamp*inTimeStamp,\nUInt32inBusNumber,\nUInt32inNumberFrames,\nAudioBufferList*ioData){\n\nASAudioEngineSingleU*engine=(__bridgeASAudioEngineSingleU*)inRefCon;\n\nOSStatuserr=noErr;\nif(engine.audioChainIsBeingReconstructed==NO){\n\n@autoreleasepool{\nAudioBufferListbufList=[enginegetBufferList:inNumberFrames];\nerr=AudioUnitRender([enginerecorderUnit],ioActionFlags,inTimeStamp,inBusNumber,inNumberFrames,&bufList);\nif(err){\nHMLogDebug(LogModuleAudio,@&34;,err);\n}else{\nAudioBufferbuffer=bufList.mBuffers[0];\nNSData*pcmBlock=[NSDatadataWithBytes:buffer.mDatalength:buffer.mDataByteSize];\n[enginedidRecordData:pcmBlock];\n}\n}\n}\n\nreturnerr;\n}\n\n//forplaycallback,fillaudiodatatobufferlist\nstaticOSStatusplaybackCallbackFunc(void*inRefCon,\nAudioUnitRenderActionFlags*ioActionFlags,\nconstAudioTimeStamp*inTimeStamp,\nUInt32inBusNumber,\nUInt32inNumberFrames,\nAudioBufferList*ioData){\n\nASAudioEngineSingleU*engine=(__bridgeASAudioEngineSingleU*)inRefCon;\n\nOSStatuserr=noErr;\nif(engine.audioChainIsBeingReconstructed==NO)\n{\nfor(inti=0;i<ioData->mNumberBuffers;i++){\n@autoreleasepool{\nAudioBufferbuffer=ioData->mBuffers[i];\nNSData*pcmBlock=[enginegetPlayFrame:buffer.mDataByteSize];\nif(pcmBlock&&pcmBlock.length){\nUInt32size=(UInt32)MIN(buffer.mDataByteSize,[pcmBlocklength]);\nmemcpy(buffer.mData,[pcmBlockbytes],size);\nbuffer.mDataByteSize=size;\n//HMLogDebug(LogModuleAudio,@&34;);\n}else{\nbuffer.mDataByteSize=0;\n*ioActionFlags|=kAudioUnitRenderAction_OutputIsSilence;\n}\n}//endpool\n}//endfor\n}//endif\n\nreturnerr;

7、不同场景下AudioUnit构建样例

7.1I/O无渲染

从输入设备采集过来的数据,先经过MutilChannelMixerUnit,再送到输出设备播放,该构建方式在于中间的Unit可对mic采集采集过来的数据进行声相调节以及音量的调节

7.2I/O有渲染

该构建方式在输入与输出之间增加了rendercallback,可以在硬件采集过来的数据上做一些处理(例如,增益、调制、音效等)后再送到输出播放

IOWithRenderCallback_2x.png

7.3仅输出并且带渲染

适合音乐游戏及合成器类的APP,仅使用IOUnit的output端,在rendercallback中负责播放源的提取整理并准备送播,比较简单的构建方式

输入端有两路音频流,都是通过rendercallback方式抓取数据,其中一路音频流直接给入到MixerUnit中,另一路先经过EQUnit处理后给入到MixerUnit中,

8、Tips

8.1多线程及内存管理

尽可能的避免rendercallback方法内做加锁及处理耗时较高的操作,这样可以最大限度的提升实时性能,如果播放数据或者采集数据存在不同线程读写的情况,必需要加锁保护,推荐pthread相关lock方法性能比其它锁要高音频的输入输出一般都是一个持续的过程,在采集与播放的callback中,应尽量复用buffer及避免多次buffer拷贝,而不是每次回调都重新申请和释放,在适当的位置加上@autoreleasepool避免长时间运行内存不断上涨

8.2格式

CoreAudioType中定义了AudioStreamBasicDescription结构,AudioUnit及其它很多音频API对格式的配置都需要用到它,根据需要将该结构的信息填充正确,下面是44.1K,stereo,16bit的填充例子

audioDescription.mSampleRate=44100;\naudioDescription.mChannelsPerFrame=2;\naudioDescription.mBitsPerChannel=16;\n\naudioDescription.mFramesPerPacket=1;\naudioDescription.mFormatID=kAudioFormatLinearPCM;\naudioDescription.mFormatFlags=kLinearPCMFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;\n\naudioDescription.mBytesPerFrame=(audioDescription.mBitsPerChannel/8)*audioDescription.mChannelsPerFrame;\naudioDescription.mBytesPerPacket=audioDescription.mBytesPerFrame;

苹果官方建议在整个AudioProcessingGraph或者Unit之间尽量以相同的音频格式流通,尽管AudioUnit的输入输出可以不同。另外在Unit之间输入输出连接点要保持一致。

8.3音质

在使用过程中,AudioUnit的format是可以动态改变的,但存在一种情况,Unit在销毁前最好恢复到默认创建时的format,否则在销毁后再重建Unit后,可能出现播放音质变差(音量变小,声音粗糙)的情况。在使用VoiceProcessingI/OUnit过程,遇到在有些iphone上开启扬声器后,Unit从Mic采集过来的数据为空或者噪音的情况,从APPSTORE中下载了其它的VOIP类型的APP也同样存在该问题,后来将AudioUnitSubType改成RemoteIO类型后,问题消失,怀疑苹果在VoiceProcessingUnit上对回声消除功能的处理上有bug

8.4AudioSession

既然使用了音频特性,就会用到AudioSession,随着功能需求跟进,与它相关的问题也瞒多的,比如路由管理(听筒扬声器、线控耳机、蓝牙耳机),打断处理(interruption、iphonecall)等,这里以AudioUnit为主,就不对它进行详细描述了,需要注意的是

音频的路由变更(用户挺拔耳机,或者代码调用强制切换)涉及到iOS硬件上输入和输出设备的改变,I/O类型Unit的采集和播放线程在切换过程中会阻塞一定时间(200ms左右),如果是语音对讲类对实时性要求较高的应用场景要考虑丢包策略。在APP前台工作时,iPhone来电或者用户主动切换到其它音频类APP后,要及时处理音频的打断机制,在恰当的时机停止及恢复Unit的工作,由于iOS平台对资源的独占方式,iPhone在通话等操作时,APP中的Unit是无法初始化或者继续工作的。

原文链接:iOSAudioUnit(涓)-鎺橀噾

OK,关于音频下载网站源码分享和免费下载音频网站的内容到此结束了,希望对大家有所帮助。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平