iOS 实时音频采集与播放

前言

在iOS中有很多方法可以进行音视频采集。如 AVCaptureDevice, AudioQueue以及Audio Unit。其中 Audio Unit是最底层的接口,它的优点是功能强大,延迟低; 而缺点是学习成本高,难度大。对于一般的iOS应用程序,AVCaptureDevice和AudioQueue完全够用了。但对于音视频直播,最好还是使用 Audio Unit 进行处理,这样可以达到最佳的效果,著名的 WebRTC 就使用的 Audio Unit 做的音频采集与播放。今天我们就重点介绍一下Audio Unit的基本知识和使用。

下图是 Audio Unit在 iOS架构中所处的位置:

基本概念

在介绍 Audio Unit 如何使用之前,先要介绍一下Audio Unit的基本概念,这样更有利于我们理解对它的使用。

  • Audio Unit的种类

    Audio Units共可分为四大类,並可细分为七种,可参考下表:

  • Audo Unit 的内部结构

    参考下图,Audio Unit 内部结构分为两大部分,Scope 与Element。其中 scope 又分三种,分別是 input scope, output scope, global scope。而 element 则是 input scope 或 output scope 內的一部分。

  • Audio Unit 的输入与输出

    下图是一个 I/O type 的 Audio Unit,其输入为麦克风,其输出为喇叭。这是一个最简单的Audio Unit使用范例。
    ioUnit.png

    The input element is element 1 (mnemonic device: the letter “I” of the word “Input” has an appearance similar to the number 1)

    The output element is element 0 (mnemonic device: the letter “O” of the word “Output” has an appearance similar to the number 0)

使用流程概要

  1. 描述音频元件(kAudioUnitType_Output/kAudioUnitSubType_RemoteIO /kAudioUnitManufacturerApple
  2. 使用 AudioComponentFindNext(NULL, &descriptionOfAudioComponent) 获得 AudioComponent。AudioComponent有点像生产 Audio Unit 的工厂。
  3. 使用 AudioComponentInstanceNew(ourComponent, &audioUnit) 获得 Audio Unit 实例。
  4. 使用 AudioUnitSetProperty函数为录制和回放开启IO。
  5. 使用 AudioStreamBasicDescription 结构体描述音频格式,并使用AudioUnitSetProperty进行设置。
  6. 使用 AudioUnitSetProperty 设置音频录制与放播的回调函数。
  7. 分配缓冲区。
  8. 初始化 Audio Unit。
  9. 启动 Audio Unit。

初始化

初始化看起来像下面这样。我们有一个 AudioComponentInstance 类型的成员变量,它用于存储 Audio Unit。

下面的音频格式用16位表式一个采样。


#define kOutputBus 0
#define kInputBus 1

// ...


OSStatus status;
AudioComponentInstance audioUnit;

// 描述音频元件
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;

// 获得一个元件
AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

// 获得 Audio Unit
status = AudioComponentInstanceNew(inputComponent, &audioUnit);
checkStatus(status);

// 为录制打开 IO
UInt32 flag = 1;
status = AudioUnitSetProperty(audioUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Input, 
                              kInputBus,
                              &flag, 
                              sizeof(flag));
checkStatus(status);

// 为播放打开 IO
status = AudioUnitSetProperty(audioUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Output, 
                              kOutputBus,
                              &flag, 
                              sizeof(flag));
checkStatus(status);

// 描述格式
audioFormat.mSampleRate         = 44100.00;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket    = 1;
audioFormat.mChannelsPerFrame   = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame      = 2;

// 设置格式
status = AudioUnitSetProperty(audioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Output, 
                              kInputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));
checkStatus(status);
status = AudioUnitSetProperty(audioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Input, 
                              kOutputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));
checkStatus(status);


// 设置数据采集回调函数
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = self;
status = AudioUnitSetProperty(audioUnit, 
                              kAudioOutputUnitProperty_SetInputCallback, 
                              kAudioUnitScope_Global, 
                              kInputBus, 
                              &callbackStruct, 
                              sizeof(callbackStruct));
checkStatus(status);

// 设置声音输出回调函数。当speaker需要数据时就会调用回调函数去获取数据。它是 "拉" 数据的概念。
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = self;
status = AudioUnitSetProperty(audioUnit, 
                              kAudioUnitProperty_SetRenderCallback, 
                              kAudioUnitScope_Global, 
                              kOutputBus,
                              &callbackStruct, 
                              sizeof(callbackStruct));
checkStatus(status);

// 关闭为录制分配的缓冲区(我们想使用我们自己分配的)
flag = 0;
status = AudioUnitSetProperty(audioUnit, 
                            kAudioUnitProperty_ShouldAllocateBuffer,
                            kAudioUnitScope_Output, 
                            kInputBus,
                            &flag, 
                            sizeof(flag));

// 初始化
status = AudioUnitInitialize(audioUnit);
checkStatus(status);

开启 Audio Unit

OSStatus status = AudioOutputUnitStart(audioUnit);
checkStatus(status);

关闭 Audio Unit

OSStatus status = AudioOutputUnitStop(audioUnit);
checkStatus(status);

结束 Audio Unit

AudioComponentInstanceDispose(audioUnit);

录制回调

static OSStatus recordingCallback(void *inRefCon, 
                                  AudioUnitRenderActionFlags *ioActionFlags, 
                                  const AudioTimeStamp *inTimeStamp, 
                                  UInt32 inBusNumber, 
                                  UInt32 inNumberFrames, 
                                  AudioBufferList *ioData) {

    // TODO:
    // 使用 inNumberFrames 计算有多少数据是有效的
    // 在 AudioBufferList 里存放着更多的有效空间

    AudioBufferList *bufferList; //bufferList里存放着一堆 buffers, buffers的长度是动态的。  

    // 获得录制的采样数据

    OSStatus status;

    status = AudioUnitRender([audioInterface audioUnit], 
                             ioActionFlags, 
                             inTimeStamp, 
                             inBusNumber, 
                             inNumberFrames, 
                             bufferList);
    checkStatus(status);

    // 现在,我们想要的采样数据已经在bufferList中的buffers中了。
    DoStuffWithTheRecordedAudio(bufferList);
    return noErr;
}

播放回调

static OSStatus playbackCallback(void *inRefCon, 
                                  AudioUnitRenderActionFlags *ioActionFlags, 
                                  const AudioTimeStamp *inTimeStamp, 
                                  UInt32 inBusNumber, 
                                  UInt32 inNumberFrames, 
                                  AudioBufferList *ioData) {    
    // Notes: ioData 包括了一堆 buffers 
    // 尽可能多的向ioData中填充数据,记得设置每个buffer的大小要与buffer匹配好。
    return noErr;
}

结束

Audio Unit可以做很多非常棒的的工作。如混音,音频特效,录制等等。它处于 iOS 开发架构的底层,特别合适于音视频直播这种场景中使用。

我们今天介绍的只是 Audio Unit众多功能中的一小点知识,但这一点点知识对于我来说已经够用了。对于那些想了解更多Audio Unit的人,只好自行去google了。

“知识无穷尽,只取我所需”。这就是我的思想,哈!

希望大家 多多观注!

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: iOS平台上的WebRTC音频采集是一种先进的技术,它允许用户使用强大的语音通信功能进行实时通信。在iOS上使用WebRTC技术,可以轻松地捕捉和处理音频数据。 对于iOS平台上的WebRTC音频采集,首先需要通过开发应用程序来实现声音录制、音频处理和实时音频通信功能。WebRTC可以方便地进行音频采集,通过重新定义AVCaptureSession实现音频采集的协议RTCAudioSession,实现了音频捕获,处理,传输等多个步骤,使音频通信更加完善。 借助WebRTC的音频采集iOS开发人员可以轻松地在其应用程序中实现多方通话和语音聊天等高级音频功能。同时,我们还可以利用其他第三方库如WebRTC库,实现高质量的语音通信。 总之,对于iOS平台上的WebRTC音频采集,它提供了很好的实时音频通信能力,允许用户进行更高质量的音频通信和语音聊天。对于iOS开发人员和用户而言,这是一个颇具吸引力的技术,有望在未来的实时通信领域发挥更大的作用。 ### 回答2: WebRTC是Google推出的一个用于支持实时通信的开源项目,它提供了一套实时音视频通信的解决方案。iOS是一个广泛使用的移动操作系统,这两者的结合,也就是iOS.WebRTC音频采集,可以让我们用iOS设备进行音频采集,进而实现音频通信。 iOS上WebRTC音频采集的实现可以借助于一些第三方开源库,如WebRTC iOS SDK。这个开源库提供了iOS平台上的WebRTC音视频功能的使用方法。其中的音频采集模块可以调用iOS设备的硬件进行物理层面的音频采集。同时,该库还提供了高度定制化的UCLOUD API,可以让开发者在音频采集的过程中对音频数据进行处理,如滤波、降噪等。 此外,iOS.WebRTC音频采集还可以整合更多第三方音频处理库,实现更广泛、更复杂的音频处理功能。例如,引入FFmpeg库进行音频编解码,引入OpenAL库进行3D音效处理等,这些都可以为iOS.WebRTC音频采集带来更加丰富、多彩的音频行为表现,给用户带来更有趣、更生动的沟通体验。 总之,iOS.WebRTC音频采集是一项开放、灵活、易用的技术,它能够帮助我们快速实现音频通信的功能,让我们能够便捷地享受网络世界中的音频互动。 ### 回答3: iOS.webrtc音频采集是指利用iOS系统的webrtc技术来进行音频采集的过程。webrtc是一种实时通信技术,可以在网页上实现跨平台的音视频通信功能。在iOS系统上,webrtc技术得到了广泛的应用,可以实现多种实时通信的场景。 音频采集是指从音频输入设备(如麦克风)中获取音频信号的过程。在iOS.webrtc中,可以通过iOS系统提供的AVFoundation框架来实现音频采集功能。AVFoundation框架提供了一系列的类和接口,可以实现音频输入设备的访问和音频信号的采集。同时,webrtc技术也提供了一系列的接口,可以将采集到的音频信号传输到远程服务器上,实现实时音频通信的功能。 iOS.webrtc音频采集具有以下特点: 1、高效稳定:webrtc技术采用P2P通信模式,充分利用了网络带宽,保证了音频传输的效率和稳定性。 2、跨平台:webrtc技术可以在不同的平台上实现音视频通信,无需安装额外的软件。 3、易于集成:webrtc技术提供了完善的接口,可以方便的与其他应用程序集成。 4、高保真音质:webrtc技术采用高端音频编码算法,可以实现高保真音质的传输。 总之,iOS.webrtc音频采集是一种高效稳定,跨平台,易于集成,高保真的音频采集技术,具有广泛的应用前景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值