Search code examples
iosaudiobluetoothcore-audioaudiounit

Is there a way to route the voice processing io audio unit to a bluetooth device?


I am doing an app which needs the voice processing io audio unit to do some echo cancellation work. It works fine, but it turned out that the audio output cannot route to bluetooth device (it is not a hands free bluetooth device but a bluetooth stereo speaker). The following is how I initiate the audio stuff

AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;

AudioComponent comp = AudioComponentFindNext(NULL, &desc);
AudioComponentInstanceNew(comp, &_audioUnit);

UInt32 one = 1;

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = (__bridge void *)self;

AudioUnitSetProperty(_audioUnit, kAudioOutputUnitProperty_SetInputCallback,
                                 kAudioUnitScope_Global,
                                 kInputBus,
                                 &callbackStruct,
                                 sizeof(callbackStruct));

_audioFormat.mSampleRate = kSampleRate;
_audioFormat.mFormatID = kAudioFormatLinearPCM;
_audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
_audioFormat.mFramesPerPacket = 1;
_audioFormat.mChannelsPerFrame = 1;
_audioFormat.mBitsPerChannel = 16;
_audioFormat.mBytesPerPacket = 2;
_audioFormat.mBytesPerFrame = 2;

AudioUnitSetProperty(_audioUnit, kAudioUnitProperty_StreamFormat,
                                 kAudioUnitScope_Output,
                                 kInputBus,
                                 &_audioFormat,
                                 sizeof(_audioFormat));
AudioUnitSetProperty(_audioUnit, kAudioUnitProperty_StreamFormat,
                                 kAudioUnitScope_Input,
                                 kOutputBus,
                                 &_audioFormat,
                                 sizeof(_audioFormat));
AudioUnitSetProperty(_audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one));
AudioUnitSetProperty(_audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &one, sizeof(one));


// Configure the audio session
AVAudioSession *sessionInstance = [AVAudioSession sharedInstance];
[sessionInstance setCategory:AVAudioSessionCategoryPlayAndRecord
                 withOptions:AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionAllowBluetooth
                       error:NULL];

[sessionInstance overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleRouteChange:)
                                             name:AVAudioSessionRouteChangeNotification
                                           object:nil];

[[AVAudioSession sharedInstance] setActive:YES error:NULL];
AudioUnitInitialize(_audioUnit);
AudioOutputUnitStart(_audioUnit);

I also route the output to the speaker instead of the default ear speaker, which volume is very low. However, I failed to achieve route the output to bluetooth. Could anyone help me on this? Thanks.


Solution

  • So it really depends on the type of bluetooth device, whether it is BluetoothHFP(input & output), BluetoothA2DP(output only) or BluetoothLE (output only). If the device is output only, you won't be able to connect and route the audio in kAudioSessionCategory_PlayAndRecord category.