mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Recover CallKit state when remote client fails to hangup
Distinguish between localHangup, remoteHangup, and call failure. This allows us to put CallKit in the proper state, ready to receive new calls without having a backlog of phantom calls which haven't been properly removed. Note the "call error" occurs at the point ICE fails, which takes a while. Anecdotally, like 10 seconds, which feels like a long to be talking into the ether. I briefly considered failing at 'disconnected', which happens much sooner, but that's actually a recoverable state. E.g. if you toggle airplane mode you can see that you bounce into `disconnected` and then back to `connected`, so I don't think we'd want to fail the call as long as WebRTC considers it "recoverable". // FREEBIE
This commit is contained in:
parent
6c14f2f500
commit
814aec6cdd
8 changed files with 51 additions and 15 deletions
|
@ -105,8 +105,8 @@
|
|||
45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */; };
|
||||
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||
45F170BC1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||
45F170D61E315310003FC1F2 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170D51E315310003FC1F2 /* Weak.swift */; };
|
||||
45F170CC1E310E22003FC1F2 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170CB1E310E22003FC1F2 /* WeakTimer.swift */; };
|
||||
45F170D61E315310003FC1F2 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170D51E315310003FC1F2 /* Weak.swift */; };
|
||||
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */; };
|
||||
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */; };
|
||||
45F2B1981D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */; };
|
||||
|
@ -704,8 +704,8 @@
|
|||
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallAudioSessionTest.swift; path = test/call/CallAudioSessionTest.swift; sourceTree = "<group>"; };
|
||||
45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; };
|
||||
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = "<group>"; };
|
||||
45F170D51E315310003FC1F2 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = "<group>"; };
|
||||
45F170CB1E310E22003FC1F2 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
|
||||
45F170D51E315310003FC1F2 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = "<group>"; };
|
||||
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingMessageCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingMessageCollectionViewCell.m; sourceTree = "<group>"; };
|
||||
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSIncomingMessageCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||
|
|
|
@ -499,7 +499,7 @@ fileprivate let timeoutSeconds = 60
|
|||
|
||||
call.state = .remoteHangup
|
||||
// Notify UI
|
||||
callUIAdapter.endCall(call)
|
||||
callUIAdapter.remoteDidHangupCall(call)
|
||||
|
||||
// self.call is nil'd in `terminateCall`, so it's important we update it's state *before* calling `terminateCall`
|
||||
terminateCall()
|
||||
|
@ -885,9 +885,14 @@ fileprivate let timeoutSeconds = 60
|
|||
assertOnSignalingQueue()
|
||||
Logger.error("\(TAG) call failed with error: \(error)")
|
||||
|
||||
// It's essential to set call.state before terminateCall, because terminateCall nils self.call
|
||||
call?.error = error
|
||||
call?.state = .localFailure
|
||||
if let call = self.call {
|
||||
// It's essential to set call.state before terminateCall, because terminateCall nils self.call
|
||||
call.error = error
|
||||
call.state = .localFailure
|
||||
callUIAdapter.failCall(call, error: error)
|
||||
} else {
|
||||
assertionFailure("\(TAG) in \(#function) but there was no call to fail.")
|
||||
}
|
||||
|
||||
terminateCall()
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ class NonCallKitCallUIAdaptee: CallUIAdaptee {
|
|||
PeerConnectionClient.startAudioSession()
|
||||
}
|
||||
|
||||
func endCall(_ call: SignalCall) {
|
||||
func localHangupCall(_ call: SignalCall) {
|
||||
CallService.signalingQueue.async {
|
||||
guard call.localId == self.callService.call?.localId else {
|
||||
assertionFailure("\(self.TAG) in \(#function) localId does not match current call")
|
||||
|
@ -125,6 +125,14 @@ class NonCallKitCallUIAdaptee: CallUIAdaptee {
|
|||
}
|
||||
}
|
||||
|
||||
internal func remoteDidHangupCall(_ call: SignalCall) {
|
||||
Logger.debug("\(TAG) in \(#function) is no-op")
|
||||
}
|
||||
|
||||
internal func failCall(_ call: SignalCall, error: CallError) {
|
||||
Logger.debug("\(TAG) in \(#function) is no-op")
|
||||
}
|
||||
|
||||
func setIsMuted(call: SignalCall, isMuted: Bool) {
|
||||
CallService.signalingQueue.async {
|
||||
guard call.localId == self.callService.call?.localId else {
|
||||
|
|
|
@ -371,6 +371,8 @@ class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelD
|
|||
case .failed:
|
||||
Logger.warn("\(self.TAG) RTCIceConnection failed.")
|
||||
self.delegate.peerConnectionClientIceFailed(self)
|
||||
case .disconnected:
|
||||
Logger.warn("\(self.TAG) RTCIceConnection disconnected.")
|
||||
default:
|
||||
Logger.debug("\(self.TAG) ignoring change IceConnectionState:\(newState.debugDescription)")
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ final class CallKitCallManager: NSObject {
|
|||
requestTransaction(transaction)
|
||||
}
|
||||
|
||||
func end(call: SignalCall) {
|
||||
func localHangup(call: SignalCall) {
|
||||
let endCallAction = CXEndCallAction(call: call.localId)
|
||||
let transaction = CXTransaction()
|
||||
transaction.addAction(endCallAction)
|
||||
|
|
|
@ -72,6 +72,12 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
|
|||
return call
|
||||
}
|
||||
|
||||
// Called from CallService after call has ended to clean up any remaining CallKit call state.
|
||||
func failCall(_ call: SignalCall, error: CallError) {
|
||||
provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.failed)
|
||||
self.callManager.removeCall(call)
|
||||
}
|
||||
|
||||
func reportIncomingCall(_ call: SignalCall, callerName: String) {
|
||||
// Construct a CXCallUpdate describing the incoming call, including the caller.
|
||||
let update = CXCallUpdate()
|
||||
|
@ -110,15 +116,20 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
|
|||
}
|
||||
|
||||
func declineCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
callManager.localHangup(call: call)
|
||||
}
|
||||
|
||||
func recipientAcceptedCall(_ call: SignalCall) {
|
||||
// no - op
|
||||
// TODO provider update call connected?
|
||||
}
|
||||
|
||||
func endCall(_ call: SignalCall) {
|
||||
callManager.end(call: call)
|
||||
func localHangupCall(_ call: SignalCall) {
|
||||
callManager.localHangup(call: call)
|
||||
}
|
||||
|
||||
func remoteDidHangupCall(_ call: SignalCall) {
|
||||
provider.reportCall(with: call.localId, endedAt: nil, reason: CXCallEndedReason.remoteEnded)
|
||||
}
|
||||
|
||||
func setIsMuted(call: SignalCall, isMuted: Bool) {
|
||||
|
|
|
@ -19,7 +19,9 @@ protocol CallUIAdaptee {
|
|||
func declineCall(localId: UUID)
|
||||
func declineCall(_ call: SignalCall)
|
||||
func recipientAcceptedCall(_ call: SignalCall)
|
||||
func endCall(_ call: SignalCall)
|
||||
func localHangupCall(_ call: SignalCall)
|
||||
func remoteDidHangupCall(_ call: SignalCall)
|
||||
func failCall(_ call: SignalCall, error: CallError)
|
||||
func setIsMuted(call: SignalCall, isMuted: Bool)
|
||||
func setHasVideo(call: SignalCall, hasVideo: Bool)
|
||||
func callBack(recipientId: String)
|
||||
|
@ -122,8 +124,16 @@ extension CallUIAdaptee {
|
|||
adaptee.recipientAcceptedCall(call)
|
||||
}
|
||||
|
||||
internal func endCall(_ call: SignalCall) {
|
||||
adaptee.endCall(call)
|
||||
internal func remoteDidHangupCall(_ call: SignalCall) {
|
||||
adaptee.remoteDidHangupCall(call)
|
||||
}
|
||||
|
||||
internal func localHangupCall(_ call: SignalCall) {
|
||||
adaptee.localHangupCall(call)
|
||||
}
|
||||
|
||||
internal func failCall(_ call: SignalCall, error: CallError) {
|
||||
adaptee.failCall(call, error: error)
|
||||
}
|
||||
|
||||
internal func showCall(_ call: SignalCall) {
|
||||
|
|
|
@ -464,7 +464,7 @@ class CallViewController: UIViewController, CallObserver {
|
|||
func didPressHangup(sender: UIButton) {
|
||||
Logger.info("\(TAG) called \(#function)")
|
||||
if let call = self.call {
|
||||
callUIAdapter.endCall(call)
|
||||
callUIAdapter.localHangupCall(call)
|
||||
} else {
|
||||
Logger.warn("\(TAG) hung up, but call was unexpectedly nil")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue