//// AudioController.m// AudioCapture//// Created by CavanSu on 10/11/2017.// Copyright © 2017 Agora. All rights reserved.//#import "AudioController.h"#import "AudioWriteToFile.h"#define InputBus 1#define OutputBus 0@interface AudioController ()@property (nonatomic, assign) int sampleRate;@property (nonatomic, assign) int channelCount;@property (nonatomic, assign) AudioCRMode audioCRMode;@property (nonatomic, assign) OSStatus error;@property (nonatomic, assign) AudioUnit remoteIOUnit;#if TARGET_OS_MAC@property (nonatomic, assign) AudioUnit macPlayUnit;#endif@end@implementation AudioController#if TARGET_OS_IPHONEstatic double preferredIOBufferDuration = 0.02;#endif+ (instancetype)audioController {AudioController *audioController = [[self alloc] init];return audioController;}#pragma mark - <Capture Call Back>static OSStatus captureCallBack(void *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp,UInt32 inBusNumber, // inputBus = 1UInt32 inNumberFrames,AudioBufferList *ioData){AudioController *audioController = (__bridge AudioController *)inRefCon;AudioUnit captureUnit = [audioController remoteIOUnit];if (!inRefCon) return 0;AudioBuffer buffer;buffer.mData = NULL;buffer.mDataByteSize = 0;buffer.mNumberChannels = audioController.channelCount;AudioBufferList bufferList;bufferList.mNumberBuffers = 1;bufferList.mBuffers[0] = buffer;OSStatus status = AudioUnitRender(captureUnit,ioActionFlags,inTimeStamp,inBusNumber,inNumberFrames,&bufferList);if (!status) {if ([audioController.delegate respondsToSelector:@selector(audioController:didCaptureData:bytesLength:)]) {[audioController.delegate audioController:audioController didCaptureData:(unsigned char *)bufferList.mBuffers[0].mData bytesLength:bufferList.mBuffers[0].mDataByteSize];}}else {[audioController error:status position:@"captureCallBack"];}return 0;}#pragma mark - <Render Call Back>static OSStatus renderCallBack(void *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList *ioData){AudioController *audioController = (__bridge AudioController *)(inRefCon);if (*ioActionFlags == kAudioUnitRenderAction_OutputIsSilence) {return noErr;}int result = 0;if ([audioController.delegate respondsToSelector:@selector(audioController:didRenderData:bytesLength:)]) {result = [audioController.delegate audioController:audioController didRenderData:(uint8_t*)ioData->mBuffers[0].mData bytesLength:ioData->mBuffers[0].mDataByteSize];}if (result == 0) {*ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;ioData->mBuffers[0].mDataByteSize = 0;}return noErr;}#pragma mark - <Step 1, Set Up Audio Session>- (void)setUpAudioSessionWithSampleRate:(int)sampleRate channelCount:(int)channelCount audioCRMode:(AudioCRMode)audioCRMode IOType:(IOUnitType)ioType{if (_audioCRMode == AudioCRModeSDKCaptureSDKRender) {return;}self.audioCRMode = audioCRMode;self.sampleRate = sampleRate;self.channelCount = channelCount;#if TARGET_OS_IPHONEAVAudioSession *audioSession = [AVAudioSession sharedInstance];NSUInteger sessionOption = AVAudioSessionCategoryOptionMixWithOthers;sessionOption |= AVAudioSessionCategoryOptionAllowBluetooth;[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:sessionOption error:nil];[audioSession setMode:AVAudioSessionModeDefault error:nil];[audioSession setPreferredIOBufferDuration:preferredIOBufferDuration error:nil];NSError *error;BOOL success = [audioSession setActive:YES error:&error];if (!success) {NSLog(@"<Error> audioSession setActive:YES error:nil");}if (error) {NSLog(@"<Error> setUpAudioSessionWithSampleRate : %@", error.localizedDescription);}#endif[self setupRemoteIOWithIOType:ioType];}#pragma mark - <Step 2, Set Up Audio Unit>- (void)setupRemoteIOWithIOType:(IOUnitType)ioType {#if TARGET_OS_IPHONE// AudioComponentDescriptionAudioComponentDescription remoteIODesc;remoteIODesc.componentType = kAudioUnitType_Output;remoteIODesc.componentSubType = ioType == IOUnitTypeVPIO ? kAudioUnitSubType_VoiceProcessingIO : kAudioUnitSubType_RemoteIO;remoteIODesc.componentManufacturer = kAudioUnitManufacturer_Apple;remoteIODesc.componentFlags = 0;remoteIODesc.componentFlagsMask = 0;AudioComponent remoteIOComponent = AudioComponentFindNext(NULL, &remoteIODesc);_error = AudioComponentInstanceNew(remoteIOComponent, &_remoteIOUnit);[self error:_error position:@"AudioComponentInstanceNew"];#endifif (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) {#if !TARGET_OS_IPHONEAudioComponentDescription remoteIODesc;remoteIODesc.componentType = kAudioUnitType_Output;remoteIODesc.componentSubType = kAudioUnitSubType_HALOutput;remoteIODesc.componentManufacturer = kAudioUnitManufacturer_Apple;remoteIODesc.componentFlags = 0;remoteIODesc.componentFlagsMask = 0;AudioComponent remoteIOComponent = AudioComponentFindNext(NULL, &remoteIODesc);_error = AudioComponentInstanceNew(remoteIOComponent, &_remoteIOUnit);[self error:_error position:@"AudioComponentInstanceNew"];_error = AudioUnitInitialize(_remoteIOUnit);[self error:_error position:@"AudioUnitInitialize"];#endif[self setupCapture];}if (_audioCRMode == AudioCRModeSDKCaptureExterRender || _audioCRMode == AudioCRModeExterCaptureExterRender) {#if !TARGET_OS_IPHONEAudioComponentDescription macPlayDesc;macPlayDesc.componentType = kAudioUnitType_Output;macPlayDesc.componentSubType = kAudioUnitSubType_DefaultOutput;macPlayDesc.componentManufacturer = kAudioUnitManufacturer_Apple;macPlayDesc.componentFlags = 0;macPlayDesc.componentFlagsMask = 0;AudioComponent macPlayComponent = AudioComponentFindNext(NULL, &macPlayDesc);_error = AudioComponentInstanceNew(macPlayComponent, &_macPlayUnit);[self error:_error position:@"AudioComponentInstanceNew"];_error = AudioUnitInitialize(_macPlayUnit);[self error:_error position:@"AudioUnitInitialize"];#endif[self setupRender];}}- (void)setupCapture {// EnableIOUInt32 one = 1;_error = AudioUnitSetProperty(_remoteIOUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Input,InputBus,&one,sizeof(one));[self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input"];#if !TARGET_OS_IPHONEUInt32 disableFlag = 0;// Attention! set kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, disable_error = AudioUnitSetProperty(_remoteIOUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output,OutputBus,&disableFlag,sizeof(disableFlag));[self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output"];AudioDeviceID defaultDevice = kAudioDeviceUnknown;UInt32 propertySize = sizeof(defaultDevice);AudioObjectPropertyAddress defaultDeviceProperty = {.mSelector = kAudioHardwarePropertyDefaultInputDevice,.mScope = kAudioObjectPropertyScopeInput,.mElement = kAudioObjectPropertyElementMaster};_error = AudioObjectGetPropertyData(kAudioObjectSystemObject,&defaultDeviceProperty,0,NULL,&propertySize,&defaultDevice);[self error:_error position:@"AudioObjectGetPropertyData, kAudioObjectSystemObject"];// Set the sample rate of the input device to the output samplerate (if possible)Float64 temp = _sampleRate;defaultDeviceProperty.mSelector = kAudioDevicePropertyNominalSampleRate;_error = AudioObjectSetPropertyData(defaultDevice,&defaultDeviceProperty,0,NULL,sizeof(Float64),&temp);[self error:_error position:@"AudioObjectSetPropertyData, defaultDeviceProperty"];// Set the input device to the system's default input device_error = AudioUnitSetProperty(_remoteIOUnit,kAudioOutputUnitProperty_CurrentDevice,kAudioUnitScope_Global,InputBus,&defaultDevice,sizeof(defaultDevice));[self error:_error position:@"kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global"];#endif// AudioStreamBasicDescriptionAudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc];_error = AudioUnitSetProperty(_remoteIOUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,InputBus,&streamFormatDesc,sizeof(streamFormatDesc));[self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output"];// CallBackAURenderCallbackStruct captureCallBackStruck;captureCallBackStruck.inputProcRefCon = (__bridge void * _Nullable)(self);captureCallBackStruck.inputProc = captureCallBack;_error = AudioUnitSetProperty(_remoteIOUnit,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Global,InputBus,&captureCallBackStruck,sizeof(captureCallBackStruck));[self error:_error position:@"kAudioOutputUnitProperty_SetInputCallback"];}- (void)setupRender {#if TARGET_OS_IPHONE// EnableIOUInt32 one = 1;_error = AudioUnitSetProperty(_remoteIOUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output,OutputBus,&one,sizeof(one));[self error:_error position:@"kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output"];// AudioStreamBasicDescriptionAudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc];_error = AudioUnitSetProperty(_remoteIOUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,OutputBus,&streamFormatDesc,sizeof(streamFormatDesc));[self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input"];// CallBackAURenderCallbackStruct renderCallback;renderCallback.inputProcRefCon = (__bridge void * _Nullable)(self);renderCallback.inputProc = renderCallBack;AudioUnitSetProperty(_remoteIOUnit,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Input,OutputBus,&renderCallback,sizeof(renderCallback));[self error:_error position:@"kAudioUnitProperty_SetRenderCallback"];#else// AudioStreamBasicDescriptionAudioStreamBasicDescription streamFormatDesc = [self signedIntegerStreamFormatDesc];_error = AudioUnitSetProperty(_macPlayUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,OutputBus,&streamFormatDesc,sizeof(streamFormatDesc));[self error:_error position:@"kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input"];// CallBackAURenderCallbackStruct renderCallback;renderCallback.inputProcRefCon = (__bridge void * _Nullable)(self);renderCallback.inputProc = renderCallBack;_error = AudioUnitSetProperty(_macPlayUnit,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Input,OutputBus,&renderCallback,sizeof(renderCallback));[self error:_error position:@"kAudioUnitProperty_SetRenderCallback"];#endif}- (void)startWork {#if TARGET_OS_IPHONE_error = AudioOutputUnitStart(_remoteIOUnit);[self error:_error position:@"AudioOutputUnitStart"];#elseif (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) {_error = AudioOutputUnitStart(_remoteIOUnit);if (_error != noErr) {[self error:_error position:@"AudioOutputUnitStart"];return;}}if (self.audioCRMode == AudioCRModeExterCaptureExterRender || self.audioCRMode == AudioCRModeSDKCaptureExterRender) {_error = AudioOutputUnitStart(_macPlayUnit);[self error:_error position:@"AudioOutputUnitStart"];}#endif}- (void)stopWork {#if TARGET_OS_IPHONEAudioOutputUnitStop(_remoteIOUnit);#elseif (_audioCRMode == AudioCRModeExterCaptureSDKRender || _audioCRMode == AudioCRModeExterCaptureExterRender) {AudioOutputUnitStop(_remoteIOUnit);}if (self.audioCRMode == AudioCRModeExterCaptureExterRender || self.audioCRMode == AudioCRModeSDKCaptureExterRender) {AudioOutputUnitStop(_macPlayUnit);}#endif}- (void)error:(OSStatus)error position:(NSString *)position {if (error != noErr) {NSString *errorInfo = [NSString stringWithFormat:@"<ACLog> Error: %d, Position: %@", (int)error, position];if ([self.delegate respondsToSelector:@selector(audioController:error:info:)]) {[self.delegate audioController:self error:error info:position];}NSLog(@"<OSStatus> :%@", errorInfo);}}- (AudioStreamBasicDescription)signedIntegerStreamFormatDesc {AudioStreamBasicDescription streamFormatDesc;streamFormatDesc.mSampleRate = _sampleRate;streamFormatDesc.mFormatID = kAudioFormatLinearPCM;streamFormatDesc.mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked);streamFormatDesc.mChannelsPerFrame = _channelCount;streamFormatDesc.mFramesPerPacket = 1;streamFormatDesc.mBitsPerChannel = 16;streamFormatDesc.mBytesPerFrame = streamFormatDesc.mBitsPerChannel / 8 * streamFormatDesc.mChannelsPerFrame;streamFormatDesc.mBytesPerPacket = streamFormatDesc.mBytesPerFrame * streamFormatDesc.mFramesPerPacket;return streamFormatDesc;}- (void)dealloc {if (_remoteIOUnit) {AudioOutputUnitStop(_remoteIOUnit);AudioComponentInstanceDispose(_remoteIOUnit);_remoteIOUnit = nil;}#if !TARGET_OS_IPHONEif (_macPlayUnit) {AudioOutputUnitStop(_macPlayUnit);AudioComponentInstanceDispose(_macPlayUnit);_macPlayUnit = nil;}#endifNSLog(@"<ACLog> AudioController dealloc");}@end
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。