ios开发AudioUnit的录制与播放功能,双工模式下的回音抑制以及降噪
来源:互联网 发布:淘宝服装拍摄报价 编辑:程序博客网 时间:2024/06/07 02:33
前段时间因为做了音频的双功模式处理,使用系统的回音抑制以及降噪功能,使用了AudioQueue以及AudioUnit来处理,但是相比之下,还是比较喜欢AudioUnit的处理方式,简单易懂。
下面,我就为大家讲解一下具体的使用方法
/*头文件*/
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
@interface EchoCancel : NSObject
#define kInputBus 1//输入道
#define KOutputBus 0//输出道
#define BUFFER_SIZE 1280 //最后需要的Buffer的size
@property (readonly)AudioBuffer audioBuffer;
@property(nonatomic,assign)AudioUnit audioUnit;
@property (strong,readwrite)NSMutableData *mIn;
@property (strong,readwrite)NSMutableData *mOut;
- (void)starWithRecordCallBack:(void(^)(void*pcmData,UInt32size))reocrdback andPlayCallBack:(void(^)(void*outPCMData,UInt32 *inoutSize))playback;//开启录制与播放
- (void)processBuffer:(AudioBufferList* )audioBufferList;//开启对buffer的处理
-(NSData *)clearDataArray;//清除录制的原Buffer
- (void)stop;//关闭录制与播放
@end
#import "EchoCancel.h"
static NSMutableData *mIn;
static NSMutableData *mOut;
@interface EchoCancel()
{
@package
void (^_inputCallbackBlock)(void *inPCMData,UInt32 inSize);
void (^_outputCallbackBlock)(void *outPCMData,UInt32 *inoutSize);
}
@end
static OSStatus recordingCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
constAudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
// Because of the way our audio format (setup below) is chosen:
// we only need 1 buffer, since it is mono
// Samples are 16 bits = 2 bytes.
// 1 frame includes only 1 sample
NSLog(@"input");
EchoCancel *device = (__bridgeEchoCancel*)inRefCon;
AudioBuffer buffer;
buffer.mNumberChannels =1;
buffer.mDataByteSize = inNumberFrames *2;
buffer.mData =malloc( inNumberFrames *2 );
// Put buffer in a AudioBufferList
AudioBufferList bufferList;
bufferList.mNumberBuffers =1;
bufferList.mBuffers[0] = buffer;
// Then:
// Obtain recorded samples
OSStatus status;
status = AudioUnitRender(device.audioUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
&bufferList);
if (status !=noErr) {
return status;
}
[device processBuffer:&bufferList];
free(bufferList.mBuffers[0].mData);
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * outData = [deviceclearDataArray];
if (outData) {
if (device->_inputCallbackBlock) {
device->_inputCallbackBlock([outDatabytes], (UInt32)[outDatalength]);
}
}
});
returnnoErr;
}
static OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
constAudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
// Notes: ioData contains buffers (may be more than one!)
// Fill them up as much as you can. Remember to set the size value in each buffer to match how
// much data is in the buffer.
EchoCancel *device = (__bridgeEchoCancel*)inRefCon;
UInt32 size =0;
if (device->_outputCallbackBlock) {
size = ioData->mBuffers[0].mDataByteSize;
device->_outputCallbackBlock(ioData->mBuffers[0].mData,
&size);
}
memset(ioData->mBuffers[0].mData + size, 0, ioData->mBuffers[0].mDataByteSize - size);
returnnoErr;
}
@implementation EchoCancel
@synthesize audioBuffer;
- (id) init {
self = [superinit];
mIn = [[NSMutableDataalloc]init];
mOut = [[NSMutableDataalloc]init];
OSStatus status;
// Describe audio component
AudioComponentDescription desc;
desc.componentType =kAudioUnitType_Output;
desc.componentSubType =kAudioUnitSubType_VoiceProcessingIO;
//kAudioUnitSubType_RemoteIO不带回音消除功能,,kAudioUnitSubType_VoiceProcessingIO带回音消除功能
desc.componentFlags =0;
desc.componentFlagsMask =0;
desc.componentManufacturer =kAudioUnitManufacturer_Apple;
// Get component
AudioComponent inputComponent =AudioComponentFindNext(NULL, &desc);
// Get audio units
status = AudioComponentInstanceNew(inputComponent, &_audioUnit);
// checkStatus(status);
// Enable IO for recording
UInt32 flag =1;//falg为1表示开启录制功能,为0则不开启
status = AudioUnitSetProperty(_audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
// checkStatus(status);
// Enable IO for playback
UInt32 zero =1;//设置为0关闭playback
status = AudioUnitSetProperty(_audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
KOutputBus,
&zero,
sizeof(zero));
// checkStatus(status);
//声音是8k采样率,16bit,单声道,pcm的
// Describe format
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate=8000.00;
audioFormat.mFormatID=kAudioFormatLinearPCM;
audioFormat.mFormatFlags=kAudioFormatFlagIsSignedInteger |kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket=1;
audioFormat.mChannelsPerFrame=1;
audioFormat.mBitsPerChannel=16;
audioFormat.mBytesPerPacket=2;
audioFormat.mBytesPerFrame=2;
// Apply format
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);
// Set input callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc =recordingCallback;
callbackStruct.inputProcRefCon = (__bridgevoid *)(self);
status = AudioUnitSetProperty(_audioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
kInputBus,
&callbackStruct,
sizeof(callbackStruct));
// checkStatus(status);
// Set output callback
callbackStruct.inputProc =playbackCallback;
callbackStruct.inputProcRefCon = (__bridgevoid *)(self);
status = AudioUnitSetProperty(_audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
KOutputBus,
&callbackStruct,
sizeof(callbackStruct));
// checkStatus(status);
// Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
flag = 0;
status = AudioUnitSetProperty(_audioUnit,
kAudioUnitProperty_ShouldAllocateBuffer,
kAudioUnitScope_Output,
kInputBus,
&flag,
sizeof(flag));
// checkStatus(status);
// Initialise
audioBuffer.mNumberChannels =1;
audioBuffer.mDataByteSize =BUFFER_SIZE;
audioBuffer.mData =malloc(BUFFER_SIZE);
status = AudioUnitInitialize(_audioUnit);
// checkStatus(status);
returnself;
}
- (void)processBuffer:(AudioBufferList* )audioBufferList
{
NSData *pcmBlock = [NSDatadataWithBytes:audioBufferList ->mBuffers[0].mDatalength:audioBufferList ->mBuffers[0].mDataByteSize];
[mOutappendData:pcmBlock];
}
-(NSData *)clearDataArray
{
if ([mOutlength] <=0)
{
returnnil;
}
[mInappendBytes:mOut.byteslength:mOut.length];
[mOutreplaceBytesInRange:NSMakeRange(0,mOut.length)withBytes:NULLlength:0];
long len = [mInlength];
len = len > BUFFER_SIZE ?BUFFER_SIZE : len;
if (len <BUFFER_SIZE)
{
returnnil;
}
NSData *pcmBlock = [mInsubdataWithRange:NSMakeRange(0, len)];
[mIn replaceBytesInRange: NSMakeRange(0, len) withBytes: NULL length: 0];
return pcmBlock;
}
- (void)starWithRecordCallBack:(void(^)(void *pcmData,UInt32 size))reocrdback andPlayCallBack:(void(^)(void *outPCMData,UInt32 *inoutSize))playback
{
_inputCallbackBlock = reocrdback;
_outputCallbackBlock = playback;
AudioOutputUnitStart(_audioUnit);
}
- (void)stop
{
AudioOutputUnitStop(_audioUnit);
[mInreplaceBytesInRange:NSMakeRange(0, [mInlength])withBytes:NULLlength:0];
[mOutreplaceBytesInRange:NSMakeRange(0, [mOutlength])withBytes:NULLlength:0];
}
-----------------------------------------------------------------------------------------------------------------------------
详细的AudioUnit的使用方法可以参考官方文档
- ios开发AudioUnit的录制与播放功能,双工模式下的回音抑制以及降噪
- ios AudioUnit 录制播放 pcm
- iOS 视频的录制、合成以及播放
- 回音消除、噪音抑制的原理
- 音频录制的噪声抑制与PCM+H264封装MP4
- iOS 开发与安卓平台共通 实现录音文件的录制,上传,下载,播放
- ios AudioUnit 播放 pcm 数据
- 音频的录制与播放
- 回音抑制
- iOS 简单的视频直播功能开发(实时视音频流录制编码+RTMP传输+实时拉流解码播放)
- iOS 简单的视频直播功能开发(实时视音频流录制编码+RTMP传输+实时拉流解码播放)
- iOS 简单的视频直播功能开发(实时视音频流录制编码+RTMP传输+实时拉流解码播放)
- linux下声音的录制与播放 /dev/dsp
- linux 下音频的录制与播放测试例子
- IOS 实现声音的录制和播放
- iOS 声音的录制和播放
- ros下的消息录制与回放功能总结
- AudioUnit的学习
- 测试数据生成——树
- 人工智能(三)上——通过搜索进行问题求解(有信息搜索策略)
- 81、java的IO操作-FileInputStream
- springboot(九):定时任务
- OpenGL粒子系统详解及编程实现
- ios开发AudioUnit的录制与播放功能,双工模式下的回音抑制以及降噪
- Maven项目的导入
- FM算法详解
- Linux 服务器性能出问题,排查下这些参数指标
- 限额10位 | 成为鹿晗背后的男人,4个月搞定高薪Linux运维工程师
- 使用DatatTable插件實現分頁功能
- (4.1.45.4)撸出一份支持自定义Grid的RecyleView
- pat1102 无语的错误,感谢有你
- wireshark