0

I want to activate the echo cancellation (Voice Processing) feature on my iOS audio pipeline.
I read something about that, that I have to use the kAudioUnitSubType_VoiceProcessingIO subtype.

My VoIP app uses 2 AudioUnits, one unit for the mic side and another unit for the speaker side. So in a full-duplex audio call I use at the moment 2 different audio units (I'm not sure, if that is allowed for voice processiong on iOS).

After I set this argument in my AudioUnit, the echo cancellation seems to work, but the audio quality is not pretty nice. It's difficult to describe, but I have some background noise in the signal.

What I have to do, to optimize this and to remove this noise from my signal? Here is my code for the setup of my audio engines. I will post not all of the code, because it's a lot, instead only the pieces, who I think it's relevant, if not please let me know.

Audio Session (audio format: PCM Int16, Sample Rate: 16000, 1 Channel):

 do {
           let session = AVAudioSession.sharedInstance()
           try session.setPreferredSampleRate(16000)
           try session.setPreferredIOBufferDuration(0.02)
            
           try session.setCategory(.playAndRecord)          
           try session.setActive(true)
            
        } catch let error {
            Logger.log("Error while setup AVAudioSession: \(error)", type: .error)
        }

First the Recorder (AudioUnit) side:

var componentDesc = AudioComponentDescription(
            componentType: kAudioUnitType_Output,
            componentSubType: kAudioUnitSubType_VoiceProcessingIO,
            componentManufacturer: kAudioUnitManufacturer_Apple,
            componentFlags: 0, componentFlagsMask: 0)

var streamFormatDesc = AudioStreamBasicDescription(
            mSampleRate: 16000,
            mFormatID: kAudioFormatLinearPCM,
            mFormatFlags: kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsNonInterleaved,
            mBytesPerPacket: 2,
            mFramesPerPacket: 1,
            mBytesPerFrame: 2,
            mChannelsPerFrame: 1,
            mBitsPerChannel: 16,
            mReserved: UInt32(0))

Here is the playback engine (AuAudioUnit):

do {
            let audioComponentDescription = AudioComponentDescription(
                componentType: kAudioUnitType_Output,
                componentSubType: kAudioUnitSubType_VoiceProcessingIO,
                componentManufacturer: kAudioUnitManufacturer_Apple,
                componentFlags: 0, componentFlagsMask: 0)
            
            if auAudioUnit == nil {
                try auAudioUnit = AUAudioUnit(componentDescription: audioComponentDescription)
                try auAudioUnit.inputBusses[0].setFormat(16000)
                
                auAudioUnit.outputProvider = { (_, _, frameCount, _, inputDataList) -> AUAudioUnitStatus in
                    self.fillSpeakerBuffer(inputDataList: inputDataList, frameCount: Int(frameCount))
                    return(0)
                }
            }
            auAudioUnit.isOutputEnabled = true
            
            try auAudioUnit.allocateRenderResources()  
            try auAudioUnit.startHardware()           
Tim
  • 91
  • 4

0 Answers0