簡體   English   中英

當應用程序處於后台並觸發 endCall 方法時,VoIP 通話崩潰。 (為未答復的情況添加計時器后)

[英]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)

設想:

  • 當應用程序在前台時顯示來電。
  • 用戶什么都不做,呼叫被取消(定時器被觸發。)
  • 用戶最小化應用程序(應用程序在后台),然后收到新的 voip 呼叫更新。 應用程序崩潰,消息以 NSException 類型的未捕獲異常終止

*** 由於未捕獲的異常“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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM