feat(video_calls): ios mic fix

This commit is contained in:
misha
2026-10-21 17:11:25 +03:00
parent 8cb3a184b0
commit 9916828956
2 changed files with 46 additions and 12 deletions

View File

@@ -1036,6 +1036,9 @@ import flutter_foreground_task
finish()
}
if !endAfterReport {
prepareCallAudioCategory()
}
if let plugin = SwiftFlutterCallkitIncomingPlugin.sharedInstance {
plugin.showCallkitIncoming(data, fromPushKit: true, completion: afterReport)
return
@@ -1053,6 +1056,9 @@ import flutter_foreground_task
finish()
return
}
if !endAfterReport {
prepareCallAudioCategory()
}
voipCallReporter.report(
uuid: uuid,
callerName: data.nameCaller,
@@ -1072,6 +1078,9 @@ import flutter_foreground_task
func onAccept(_ call: Call, _ action: CXAnswerCallAction) {
resumeAudioAfterCallKitEnds = true
// Dart may call activate before didActivate. Claim the session now so
// that path does not setActive or start the audio unit without a track.
callKitOwnsAudioSession = true
prepareCallAudioCategory()
storePendingAcceptedCall(call)
recordVoipDiagnostic(
@@ -1114,9 +1123,10 @@ import flutter_foreground_task
rtcSession.useManualAudio = true
rtcSession.audioSessionDidActivate(audioSession)
applyCallAudioConfiguration(active: false)
// Do not start the audio unit here. Incoming accept has no LiveKit
// microphone track yet; enabling the unit attaches capture to nothing,
// and a later `isAudioEnabled = true` is then a no-op.
// Incoming accept has no LiveKit microphone track yet. Starting the
// unit here attaches capture to nothing; a later isAudioEnabled=true
// is a no-op and the callee microphone stays silent. Dart starts the
// unit via restart after setMicrophoneEnabled.
}
func didDeactivateAudioSession(_ audioSession: AVAudioSession) {
@@ -1145,6 +1155,16 @@ import flutter_foreground_task
}
private func prepareCallAudioCategory() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(
.playAndRecord,
mode: .videoChat,
options: [.allowBluetooth, .defaultToSpeaker]
)
} catch {
NSLog("[EatvioVoIP] prepare call audio category failed: \(error)")
}
applyCallAudioConfiguration(active: false)
}
@@ -1154,23 +1174,37 @@ import flutter_foreground_task
// CallKit already activated the session on answer. A second setActive
// fails or replaces that session, and the incoming microphone stays dead.
applyCallAudioConfiguration(active: !callKitOwnsAudioSession)
// Starting the audio unit while the configuration lock is held deadlocks
// the capture thread, so the mic stays silent.
if callKitOwnsAudioSession {
// The unit starts in restartInAppCallAudioUnit after the microphone
// track exists. Enabling it here is the incoming-only silent-mic bug.
return
}
rtcSession.isAudioEnabled = true
}
/// Restarts capture after the previous audio graph has disconnected.
/// Toggling the unit in the same turn makes voice processing throw.
/// Starts capture after the microphone track exists. Incoming CallKit
/// must not have started the unit earlier, or this assignment is a no-op.
private func restartInAppCallAudioUnit() {
audioRestartGeneration += 1
let generation = audioRestartGeneration
let rtcSession = RTCAudioSession.sharedInstance()
rtcSession.useManualAudio = true
rtcSession.isAudioEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
guard let self, generation == self.audioRestartGeneration else { return }
self.activateInAppCallAudioSession()
let needsTeardown = rtcSession.isAudioEnabled
if needsTeardown {
rtcSession.isAudioEnabled = false
}
let delay: TimeInterval = needsTeardown ? 0.25 : 0
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
guard let self, generation == self.audioRestartGeneration else { return }
self.enableInAppCallAudioUnit()
}
}
private func enableInAppCallAudioUnit() {
let rtcSession = RTCAudioSession.sharedInstance()
rtcSession.useManualAudio = true
applyCallAudioConfiguration(active: !callKitOwnsAudioSession)
rtcSession.isAudioEnabled = true
}
private func applyCallAudioConfiguration(active: Bool) {

View File

@@ -1,6 +1,6 @@
name: eatvio_app
description: A new Flutter project.
version: 1.3.61+150
version: 1.3.62+151
publish_to: 'none'
environment: