Setting preffered audio input on iOS


Is there a mechanism in JUCE to change the audio input on iOS, to switch between headset mic and built-in mic?

for example in swift i can do

for portDesc in session.availableInputs! {
    if(portDesc.portType == AVAudioSessionPortBuiltInMic) {
        try session.setPreferredInput(portDesc)

a quick search through juce_ios_Audio.cpp doesn’t reveal any glue for this, nor does a search of the forum. anyone have a solution before i try to hack my own? (i have little experience with iOS or objective-c++, truth be told, so its a little intimidating.)

apologies if i’ve missed something obvious, and thanks.

[edit] well i’ve successfully hacked in something along the lines of

AVAudioSession* session = [AVAudioSession sharedInstance];
auto inputs = [session availableInputs];
for (AVAudioSessionPortDescription* input : inputs) {
    auto type = input.portType;
    bool isInternalMic = [type isEqualToString:@"MicrophoneBuiltIn"];
    if(isInternalMic) {
        JUCE_NSERROR_CHECK ( [session setPreferredInput:input error:&error]);

which seems to work ok. though, strangely, changing the session mode (e.g. toggling preprocessing) resets the selected input port to the default.

incidentally, the preprocessing mode flag is backwards in juce_ios_Audio.cpp:setAudioPreProcessingEnabled():

NSString* mode = (enable ? AVAudioSessionModeMeasurement
                                 : AVAudioSessionModeDefault);

( AVAudioSessionModeMeasurement is the mode that disables AGC and so on. )

Yes, that’s the way to go. As you’re experiencing, iOS likes to manage the input and output devices itself so you’ll need to fight to keep control of it. There are various callbacks you can listen to to find out about hardware and/or input source changes like here (on the develop branch - we’ve made significant changes since the last master release)

but exactly how you should handle those to do what you want is pretty unclear. It’s easy to end up on the wrong thread or in a callback loop…

1 Like

Thanks for sharing this!

I’ve been following your implementation, but weirdly it overrides the output as well…
I’m setting the preferred input in the open() method, right after the session category is selected.
Any idea what am I possibly missing?