I am using CallKit for my audio call application. The speaker button in CallKit is not working properly. It turns on and off automatically. When I try to disable the speaker button, I can still hear the voice through the loudspeaker.
What I want is to initially set the call to use the loudspeaker and then allow the user to switch between the earpiece and the loudspeaker based on their action in the CallKit UI. However, when I disable the speaker button to play through the earpiece, it doesn’t work. Is there any solution for this issue?
I see that the CallKit speaker UI issue is still not resolved, as there are many open issues related to the same problem. Even if there is a UI issue, I want the audio to play through the earpiece or loudspeaker based on the user’s selection, regardless of the button’s UI state.
Below is my code for configuring the audio session, and I am activating the audio session in func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession)
func configureAudioSession() {
let rtcAudioSession = RTCAudioSession.sharedInstance()
rtcAudioSession.lockForConfiguration()
do {
var categoryOptions: AVAudioSession.CategoryOptions = [.defaultToSpeaker, .allowBluetoothA2DP, .allowAirPlay, .allowBluetooth]
try rtcAudioSession.setCategory(.playAndRecord, with: categoryOptions)
try rtcAudioSession.setMode(.voiceChat)
} catch {
//Error
}
rtcAudioSession.unlockForConfiguration()
NotificationCenter.default.addObserver(self, selector: #selector(routeChange), name: AVAudioSession.routeChangeNotification, object: nil)
}
@objc private func routeChange(_ n: Foundation.Notification) {
let session = AVAudioSession.sharedInstance()
let currentRoute = session.currentRoute
if session.currentRoute.outputs.contains(where: { $0.portType == .headphones || $0.portType == .bluetoothHFP || $0.portType == .bluetoothA2DP }) {
try? session.overrideOutputAudioPort(.none)
} else {
try? session.overrideOutputAudioPort(.speaker)
}
}