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 //最后需要的Buffersize

@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 replaceBytesInRangeNSMakeRange(0, len) withBytesNULL length0];


    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];

}


录制的buf是从- (void)starWithRecordCallBack:(void(^)(void *pcmData, UInt32 size))reocrdback andPlayCallBack:(void(^)(void *outPCMData, UInt32*inoutSize))playback;函数recordBack里面传递过来的,需要播放的时候,要将需要播放的buffer传入playback函数里面。

-----------------------------------------------------------------------------------------------------------------------------

详细的AudioUnit的使用方法可以参考官方文档



阅读全文
0 0
原创粉丝点击