[英]Voip call got crashed when app is background and triggered endCall method. (After adding timer for unanswered case)
我正在嘗試為 voip 呼叫實施未應答的案例。
在reportNewIncomingCall
完成時,我啟動了內部計時器來跟蹤 60 秒的超時。
public final class CallCenter: NSObject {
fileprivate var sessionPool = [UUID: String]()
public func showIncomingCall(of session: String, completion: @escaping () -> Void) {
let callUpdate = CXCallUpdate()
callUpdate.remoteHandle = CXHandle(type: .generic, value: session)
callUpdate.localizedCallerName = session
callUpdate.hasVideo = true
callUpdate.supportsDTMF = false
let uuid = pairedUUID(of: session)
provider.reportNewIncomingCall(with: uuid, update: callUpdate, completion: { [unowned self] error in
if let error = error {
print("reportNewIncomingCall error: \(error.localizedDescription)")
}
// We cant auto dismiss incoming call since there is a chance to get another voip push for cancelling the call screen ("reject") from server.
let timer = Timer(timeInterval: incomingCallTimeoutDuration, repeats: false, block: { [unowned self] timer in
self.endCall(of: session, at: nil, reason: .unanswered)
self.ringingTimer?.invalidate()
self.ringingTimer = nil
})
timer.tolerance = 0.5
RunLoop.main.add(timer, forMode: .common)
ringingTimer = timer
completion()
})
}
public func endCall(of session: String, at: Date?, reason: CallEndReason) {
let uuid = pairedUUID(of: session)
provider.reportCall(with: uuid, endedAt: at, reason: reason.reason)
}
}
當對等用戶(呼叫者)拒絕時,我將收到另一個 voip 通知,我正在調用它。
callCenter.endCall(of: caller, at: Date(), reason: .declinedElsewhere)
設想:
*** 由於未捕獲的異常“NSInternalInconsistencyException”而終止應用程序,原因:“正在殺死應用程序,因為它在收到 PushKit VoIP 推送后從未向系統發布傳入呼叫。”
應用委托:
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
print("Payload: \(payload.dictionaryPayload)")
guard let data = payload.dictionaryPayload as? [String: Any],
let userID = data["user"] as? UInt64,
let event = data["event"] as? String,
let caller = data["callerName"] as? String
else {
print("Incoming call failed due to missing keys.")
callCenter.showIncomingCall(of: "Unknown") { [unowned self] in
self.callCenter.endCall(of: "Unknown", at: nil, reason: .failed)
completion()
}
return
}
switch event {
case "reject":
callCenter.endCall(of: caller, at: Date(), reason: .declinedElsewhere)
callingUser = nil
completion()
return;
case "cancel":
callCenter.endCall(of: caller, at: Date(), reason: .answeredElsewhere)
callingUser = nil
completion()
return;
default: break
}
let callingUser = CallingUser(session: caller, userID: userID)
callCenter.showIncomingCall(of: callingUser.session) {
completion()
}
self.callingUser = callingUser
}
在沒有未解決的情況下,上述情況運行良好。 意味着,當應用程序處於后台時,我可以觸發 endCall 方法(出於任何原因)。 它有效。 所以我認為問題出在計時器上。 基本上我用相同的 UUID 和不同的原因調用 endCall 方法。 如果我刪除計時器邏輯,它的工作正常。
實施未答復案例的最佳做法或推薦方法是什么? 我在哪里 go 錯了?
如果應用程序中沒有活動呼叫,我可以通過發起假呼叫來解決此問題。
private func showFakeCall(of session: String, callerName: String, completion: @escaping () -> Void) {
callCenter.showIncomingCall(of: session, callerName: callerName) { [unowned self] in
self.callCenter.endCall(of: session, at: nil, reason: .failed)
print("Print end call inside Fakecall")
completion()
}
}
為所有呼叫事件添加了以下檢查(拒絕、取消)
if !callCenter.hasActiveCall(of: channelName) {
print("No Active calls found. Initiating Fake call.")
showFakeCall(of: channelName, callerName: callerName, completion: completion)
return
}
額外提示:如果您對 CXProvider/CXCallController 配置進行了任何更改,您必須重新安裝(先卸載)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.