在iOS中有很多方法可以进行音视频采集。如 AVCaptureDevice, AudioQueue以及Audio Unit。其中 Audio Unit是最底层的接口,它的优点是功能强大,延迟低; 而缺点是学习成本高,难度大。对于一般的iOS应用程序,AVCaptureDevice和AudioQueue完全够用了。但对于音视频直播,最好还是使用 Audio Unit 进行处理,这样可以达到最佳的效果,著名的 WebRTC 就使用的 Audio Unit 做的音频采集与播放。今天我们就重点介绍一下Audio Unit的基本知识和使用。
下图是 Audio Unit在 iOS架构中所处的位置:
在介绍 Audio Unit 如何使用之前,先要介绍一下Audio Unit的基本概念,这样更有利于我们理解对它的使用。
C++音视频学习资料免费获取方法:关注音视频开发T哥,点击「链接」即可免费获取2023年最新C++音视频开发进阶独家免费学习大礼包!
初始化看起来像下面这样。我们有一个 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 Unitstatus = AudioComponentInstanceNew(inputComponent, &audioUnit);
checkStatus(status);// 为录制打开 IOUInt32 flag = 1;
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
checkStatus(status);// 为播放打开 IOstatus = 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了。
“知识无穷尽,只取我所需”。这就是我的思想,哈!
原文链接:iOS 实时音频采集与播放
页面更新:2024-03-05
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号