GSM通话被对方结束后,VoIP通话音频无法恢复的问题求助
解决VoIP通话被GSM中断后对方挂断GSM音频无法恢复的问题
问题场景回顾
当VoIP通话被GSM通话中断,选择“保持/接听”GSM通话后,VoIP通话被保持、音频会话停用均正常;但对方主动结束GSM通话时,iOS不会自动激活VoIP的音频会话,手动激活还会出现“会话激活失败”错误。
可行解决思路
通过CXCallObserver监听GSM通话结束事件
利用CallKit的CXCallObserver监听系统内所有通话的状态变化,精准捕捉GSM通话结束的时机,触发VoIP音频恢复逻辑。class CallStatusObserver: NSObject, CXCallObserverDelegate { private let callObserver = CXCallObserver() private var VoIPCallUUID: UUID! // 替换为你的VoIP通话UUID override init() { super.init() callObserver.setDelegate(self, queue: DispatchQueue.main) } func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) { // 过滤非VoIP通话,且确认通话已结束 if call.hasEnded && !call.isVoIP { restoreVoIPAudioSession() } } private func restoreVoIPAudioSession() { // 先更新CallKit中VoIP通话的保持状态为激活 let setHeldAction = CXSetHeldCallAction(callUUID: VoIPCallUUID, onHold: false) let transaction = CXTransaction(action: setHeldAction) CXCallController().request(transaction) { [weak self] error in guard error == nil else { print("更新VoIP通话状态失败: \(error!.localizedDescription)") return } self?.activateAudioSession() } } private func activateAudioSession() { let session = AVAudioSession.sharedInstance() do { try session.setCategory(.playAndRecord, mode: .voiceChat, options: [.allowBluetooth, .allowBluetoothA2DP]) try session.setActive(true, options: .notifyOthersOnDeactivation) // 恢复音视频流的播放与采集 } catch { print("激活音频会话失败: \(error.localizedDescription)") // 打印错误详情定位问题,比如错误码、域 if let nsError = error as NSError? { print("错误码: \(nsError.code), 错误域: \(nsError.domain)") } } } }监听音频会话中断通知,处理恢复逻辑
注册AVAudioSession.interruptionNotification,在中断结束时判断是否需要手动恢复,尤其注意系统未自动触发shouldResume的场景:// 在初始化方法中注册通知 NotificationCenter.default.addObserver(self, selector: #selector(handleAudioInterruption(_:)), name: AVAudioSession.interruptionNotification, object: nil) @objc private func handleAudioInterruption(_ notification: Notification) { guard let info = notification.userInfo else { return } let typeValue = info[AVAudioSessionInterruptionTypeKey] as! UInt let interruptionType = AVAudioSession.InterruptionType(rawValue: typeValue)! if interruptionType == .ended { let optionsValue = info[AVAudioSessionInterruptionOptionKey] as! UInt let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue) if options.contains(.shouldResume) { activateAudioSession() } else { // 系统未建议自动恢复,手动触发CallKit状态更新+音频激活 restoreVoIPAudioSession() } } }排查手动激活失败的核心原因
出现“会话激活失败”时,重点排查:- 音频会话的category/mode配置是否正确,确保和VoIP通话场景匹配(必须是
playAndRecord+voiceChat) - 是否有其他音频会话未释放,可通过
AVAudioSession.sharedInstance().isOtherAudioPlaying检查 - 激活时的
options参数是否合理,比如使用.notifyOthersOnDeactivation而非.mixWithOthers
- 音频会话的category/mode配置是否正确,确保和VoIP通话场景匹配(必须是
内容的提问来源于stack exchange,提问作者rauldhasmana
相关产品推荐
相关产品推荐

