// // Copyright (c) 2019 Open Whisper Systems. All rights reserved. // import Foundation import SignalServiceKit import SignalMessaging /** * Manage call related UI in a pre-CallKit world. */ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { let notificationPresenter: NotificationPresenter let callService: CallService // Starting/Stopping incoming call ringing is our apps responsibility for the non CallKit interface. let hasManualRinger = true required init(callService: CallService, notificationPresenter: NotificationPresenter) { AssertIsOnMainThread() self.callService = callService self.notificationPresenter = notificationPresenter super.init() } // MARK: Dependencies var audioSession: OWSAudioSession { return Environment.shared.audioSession } // MARK: func startOutgoingCall(handle: String) -> SignalCall { AssertIsOnMainThread() let call = SignalCall.outgoingCall(localId: UUID(), remotePhoneNumber: handle) // make sure we don't terminate audio session during call let success = self.audioSession.startAudioActivity(call.audioActivity) assert(success) self.callService.handleOutgoingCall(call).retainUntilComplete() return call } func reportIncomingCall(_ call: SignalCall, callerName: String) { AssertIsOnMainThread() Logger.debug("") self.showCall(call) // present lock screen notification if UIApplication.shared.applicationState == .active { Logger.debug("skipping notification since app is already active.") } else { notificationPresenter.presentIncomingCall(call, callerName: callerName) } } func reportMissedCall(_ call: SignalCall, callerName: String) { AssertIsOnMainThread() notificationPresenter.presentMissedCall(call, callerName: callerName) } func answerCall(localId: UUID) { AssertIsOnMainThread() guard let call = self.callService.call else { owsFailDebug("No current call.") return } guard call.localId == localId else { owsFailDebug("localId does not match current call") return } self.answerCall(call) } func answerCall(_ call: SignalCall) { AssertIsOnMainThread() guard call.localId == self.callService.call?.localId else { owsFailDebug("localId does not match current call") return } self.audioSession.isRTCAudioEnabled = true self.callService.handleAnswerCall(call) } func declineCall(localId: UUID) { AssertIsOnMainThread() guard let call = self.callService.call else { owsFailDebug("No current call.") return } guard call.localId == localId else { owsFailDebug("localId does not match current call") return } self.declineCall(call) } func declineCall(_ call: SignalCall) { AssertIsOnMainThread() guard call.localId == self.callService.call?.localId else { owsFailDebug("localId does not match current call") return } self.callService.handleDeclineCall(call) } func recipientAcceptedCall(_ call: SignalCall) { AssertIsOnMainThread() self.audioSession.isRTCAudioEnabled = true } func localHangupCall(_ call: SignalCall) { AssertIsOnMainThread() // If both parties hang up at the same moment, // call might already be nil. guard self.callService.call == nil || call.localId == self.callService.call?.localId else { owsFailDebug("localId does not match current call") return } self.callService.handleLocalHungupCall(call) } internal func remoteDidHangupCall(_ call: SignalCall) { AssertIsOnMainThread() Logger.debug("is no-op") } internal func remoteBusy(_ call: SignalCall) { AssertIsOnMainThread() Logger.debug("is no-op") } internal func failCall(_ call: SignalCall, error: CallError) { AssertIsOnMainThread() Logger.debug("is no-op") } func setIsMuted(call: SignalCall, isMuted: Bool) { AssertIsOnMainThread() guard call.localId == self.callService.call?.localId else { owsFailDebug("localId does not match current call") return } self.callService.setIsMuted(call: call, isMuted: isMuted) } func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) { AssertIsOnMainThread() guard call.localId == self.callService.call?.localId else { owsFailDebug("localId does not match current call") return } self.callService.setHasLocalVideo(hasLocalVideo: hasLocalVideo) } }