iOS Audio Unit (一)

本文介绍了iOS音频开发中的Core Audio框架,重点讲解了Audio Unit,包括其类型、构建方式、数据输入输出,以及不同场景的应用示例。通过Audio Unit,开发者可以实现音频的播放、录音、音效处理等功能,适用于各种音频处理需求。

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

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

1、Core Audio

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

core_audio_layers.png

2、Low-Level

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

3、Mid-Level

该层功能比较齐全,包括音频数据格式转换,音频文件读写,音频流解析,插件工作支持等 Audio Convert Services 负责音频数据格式的转换 Audio File Services 负责音频数据的读写 Audio Unit ServicesAudio Processing Graph Services 支持均衡器和混音器等数字信号处理的插件 Audio File Scream Services 负责流解析 Core Audio Clock Services 负责音频音频时钟同步

4、High-Level

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

5、不同场景所需要的API Service

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

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

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

6、Audio Unit

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

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

【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发

【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~

6.1 Audio Unit类型:

I/O: Remote I/O、Voice-Processing I/O、Generic Output Mixing: 3D Mixer、Mutichannel Mixer Effect: iPod Equalizer Format Conversion: Format Converter

6.2 AudioUnit构建方式

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

6.3 Unit API方式(Remote IO Unit)

    // create IO Unit
    BOOL result = NO;
    AudioComponentDescription outputDescription = {0};
    outputDescription.componentType = kAudioUnitType_Output;
    outputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
    outputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
    outputDescription.componentFlags = 0;
    outputDescription.componentFlagsMask = 0;
    AudioComponent comp = AudioComponentFindNext(NULL, &outputDescription);
    result = CheckOSStatus(AudioComponentInstanceNew(comp, &mVoipUnit), @"couldn't create a new instance of RemoteIO");
    if (!result) return result;
​
    // config IO Enable status
    UInt32 flag = 1;
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)), @"could not enable output on RemoteIO");
    if (!result) return result;
​
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)),                  @"AudioUnitSetProperty EnableIO");
    if (!result) return result;
​
    // Config default format
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &inputAudioDescription, sizeof(inputAudioDescription)), @"couldn't set the input client format on RemoteIO");
    if (!result) return result;
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &outputAudioDescription, sizeof(outputAudioDescription)), @"couldn't set the output client format on RemoteIO");
    if (!result) return result;
​
    // Set the MaximumFramesPerSlice property. This property is used to describe to an audio unit the maximum number
    // of samples it will be asked to produce on any single given call to AudioUnitRender
    UInt32 maxFramesPerSlice = 4096;
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(UInt32)), @"couldn't set max frames per slice on RemoteIO");
    if (!result) return result;
​
    // Set the record callback
    AURenderCallbackStruct recordCallback;
    recordCallback.inputProc = recordCallbackFunc;
    recordCallback.inputProcRefCon = (__bridge void * _Nullable)(self);
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &recordCallback, sizeof(recordCallback)), @"couldn't set record callback on RemoteIO");
    if (!result) return result;
​
    // Set the playback callback
    AURenderCallbackStruct playbackCallback;
    playbackCallback.inputProc = playbackCallbackFunc;
    playbackCallback.inputProcRefCon = (__bridge void * _Nullable)(self);
    result = CheckOSStatus(AudioUnitSetProperty(mVoipUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &playbackCallback, sizeof(playbackCallback)), @"couldn't set playback callback on RemoteIO");
    if (!result) return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值