diff --git a/Signal/src/call/CallService.swift b/Signal/src/call/CallService.swift index 4a28852a1..4c31e7c85 100644 --- a/Signal/src/call/CallService.swift +++ b/Signal/src/call/CallService.swift @@ -894,7 +894,7 @@ protocol CallServiceObserver: class { * For incoming call, when the local user has chosen to accept the call. */ func handleConnectedCall(_ call: SignalCall) { - Logger.debug("\(TAG) in \(#function)") + Logger.info("\(TAG) in \(#function)") AssertIsOnMainThread() guard let peerConnectionClient = self.peerConnectionClient else { @@ -911,6 +911,8 @@ protocol CallServiceObserver: class { call.state = .connected + self.startActiveCallTimer(call: call) + // We don't risk transmitting any media until the remote client has admitted to being connected. peerConnectionClient.setAudioEnabled(enabled: !call.isMuted) peerConnectionClient.setLocalVideoEnabled(enabled: shouldHaveLocalVideoTrack()) @@ -1430,6 +1432,7 @@ protocol CallServiceObserver: class { self.call?.removeAllObservers() self.call = nil + self.stopAnyActiveCallTimer() self.sendIceUpdatesImmediately = true Logger.info("\(TAG) clearing pendingIceUpdateMessages") self.pendingIceUpdateMessages = [] @@ -1567,6 +1570,52 @@ protocol CallServiceObserver: class { remoteVideoTrack:remoteVideoTrack) } } + + // MARK: CallViewController Timer + + var activeCallTimer: Timer? + func startActiveCallTimer(call: SignalCall) { + AssertIsOnMainThread() + assert(call.state == .connected) + + if self.activeCallTimer != nil { + owsFail("\(TAG) activeCallTimer should only be set once per call") + self.activeCallTimer!.invalidate() + self.activeCallTimer = nil + } + + self.activeCallTimer = WeakTimer.scheduledTimer(timeInterval: 1, target: self, userInfo: nil, repeats: true) { [weak self] timer in + guard let strongSelf = self else { + return + } + + guard call == strongSelf.call else { + owsFail("\(strongSelf.TAG) call has since ended. Timer should have been invalidated.") + timer.invalidate() + return + } + + strongSelf.ensureCallScreenVisible(call: call) + } + } + + func ensureCallScreenVisible(call: SignalCall) { + guard nil != UIApplication.shared.frontmostViewController as? CallViewController else { + owsFail("\(TAG) in \(#function) CallViewController should already be visible.") + self.callUIAdapter.showCall(call) + return + } + + Logger.debug("\(TAG) in \(#function) already visible.") + } + + func stopAnyActiveCallTimer() { + AssertIsOnMainThread() + assert(self.call == nil) + + self.activeCallTimer?.invalidate() + self.activeCallTimer = nil + } } fileprivate extension MessageSender { diff --git a/Signal/src/call/NonCallKitCallUIAdaptee.swift b/Signal/src/call/NonCallKitCallUIAdaptee.swift index 2a4861ca0..7f78e4c54 100644 --- a/Signal/src/call/NonCallKitCallUIAdaptee.swift +++ b/Signal/src/call/NonCallKitCallUIAdaptee.swift @@ -31,7 +31,7 @@ class NonCallKitCallUIAdaptee: CallUIAdaptee { Logger.debug("\(self.TAG) handleOutgoingCall succeeded") }.catch { error in Logger.error("\(self.TAG) handleOutgoingCall failed with error: \(error)") - } + }.retainUntilComplete() return call } diff --git a/Signal/src/call/UserInterface/CallUIAdapter.swift b/Signal/src/call/UserInterface/CallUIAdapter.swift index b472010ae..c458c5b60 100644 --- a/Signal/src/call/UserInterface/CallUIAdapter.swift +++ b/Signal/src/call/UserInterface/CallUIAdapter.swift @@ -34,7 +34,7 @@ extension CallUIAdaptee { internal func showCall(_ call: SignalCall) { AssertIsOnMainThread() - let callViewController = CallViewController(call:call) + let callViewController = CallViewController(call: call) callViewController.modalTransitionStyle = .crossDissolve guard let presentingViewController = Environment.getCurrent().signalsViewController else {