In my experience that's not enough: you also have to set the AVAudioSession category to playAndRecord
. This is suggested in the docs for the overrideOutputAudioPort:
method:
If your app uses the playAndRecord
category, calling this method with the AVAudioSession.PortOverride.speaker
causes the system to route audio to the built-in speaker and microphone regardless of other settings. This change remains in effect only until the current route changes or you call this method again with the AVAudioSession.PortOverride.none
option.
If you would prefer
to permanently enable this behavior, you should instead set the
category's defaultToSpeaker
option. Setting this option will always
route to the speaker rather than receiver if no other accessory such
as headphones are in use.
Note that those docs specify that that is sufficient. I don't know if it's necessary: I just haven't found other options that work as reliably.
However, the docs for defaultToSpeaker
do say that it's only usable with the AVAudioSessionCategoryPlayAndRecord
category.
So, doing the following works for me:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playAndRecord, mode: .default)
try audioSession.overrideOutputAudioPort(.speaker)
} catch {
print("Error occurred: \(error.localizedDescription)")
}