In Objective-C, recording and playing audio simultaneously is fairly simple. And there are tonnes of sample code on the internet. But I want to record and play audio simultaneously using Audio Unit/Core Audio in Swift. There are vary small amount of help and sample code on this using Swift. And i couldn't find any help which could show how to achieve this.
I am struggling with the bellow code.
let preferredIOBufferDuration = 0.005
let kInputBus = AudioUnitElement(1)
let kOutputBus = AudioUnitElement(0)
init() {
// This is my Audio Unit settings code.
var status: OSStatus
do {
try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(preferredIOBufferDuration)
} catch let error as NSError {
print(error)
}
var desc: AudioComponentDescription = AudioComponentDescription()
desc.componentType = kAudioUnitType_Output
desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO
desc.componentFlags = 0
desc.componentFlagsMask = 0
desc.componentManufacturer = kAudioUnitManufacturer_Apple
let inputComponent: AudioComponent = AudioComponentFindNext(nil, &desc)
status = AudioComponentInstanceNew(inputComponent, &audioUnit)
checkStatus(status)
var flag = UInt32(1)
status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, UInt32(sizeof(UInt32)))
checkStatus(status)
status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, UInt32(sizeof(UInt32)))
checkStatus(status)
var audioFormat: AudioStreamBasicDescription! = AudioStreamBasicDescription()
audioFormat.mSampleRate = 8000
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, UInt32(sizeof(UInt32)))
checkStatus(status)
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, UInt32(sizeof(UInt32)))
checkStatus(status)
// Set input/recording callback
var inputCallbackStruct: AURenderCallbackStruct! = AURenderCallbackStruct(inputProc: recordingCallback, inputProcRefCon: UnsafeMutablePointer(unsafeAddressOf(self)))
inputCallbackStruct.inputProc = recordingCallback
inputCallbackStruct.inputProcRefCon = UnsafeMutablePointer(unsafeAddressOf(self))
status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &inputCallbackStruct, UInt32(sizeof(UInt32)))
checkStatus(status)
// Set output/renderar/playback callback
var renderCallbackStruct: AURenderCallbackStruct! = AURenderCallbackStruct(inputProc: playbackCallback, inputProcRefCon: UnsafeMutablePointer(unsafeAddressOf(self)))
renderCallbackStruct.inputProc = playbackCallback
renderCallbackStruct.inputProcRefCon = UnsafeMutablePointer(unsafeAddressOf(self))
status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &renderCallbackStruct, UInt32(sizeof(UInt32)))
checkStatus(status)
flag = 0
status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ShouldAllocateBuffer, kAudioUnitScope_Output, kInputBus, &flag, UInt32(sizeof(UInt32)))
}
func recordingCallback(inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
print("recordingCallback got fired >>>")
return noErr
}
func playbackCallback(inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
print("playbackCallback got fired <<<")
return noErr
}
With that code, only recordingCallback
method is getting called. And playbackCallback
method is not being fired at all. I sure that i am going something wrong here. Can someone please help me with this. I am banging my head over this problem.
You are setting the
InputCallback
andRenderCallback
method incorrectly. Other settings seems OK. So yourinit
method should be like this.Try with this code and let us know if that helps.