use CallKit for all cases

This commit is contained in:
ryanzhao 2021-11-09 11:53:38 +11:00
parent 86aced218a
commit f019fe7733
8 changed files with 94 additions and 39 deletions

View File

@ -128,6 +128,11 @@ public final class SessionCall: NSObject, WebRTCSessionDelegate {
WebRTCSession.current = self.webRTCSession
super.init()
self.webRTCSession.delegate = self
if AppEnvironment.shared.callManager.currentCall == nil {
AppEnvironment.shared.callManager.currentCall = self
} else {
SNLog("[Calls] A call is ongoing.")
}
}
func reportIncomingCallIfNeeded(completion: @escaping (Error?) -> Void) {
@ -147,7 +152,7 @@ public final class SessionCall: NSObject, WebRTCSessionDelegate {
}
// MARK: Actions
func startSessionCall(completion: (() -> Void)?) {
func startSessionCall() {
guard case .offer = mode else { return }
var promise: Promise<Void>!
Storage.write(with: { transaction in
@ -161,10 +166,9 @@ public final class SessionCall: NSObject, WebRTCSessionDelegate {
}
}
})
completion?()
}
func answerSessionCall(completion: (() -> Void)?) {
func answerSessionCall() {
guard case .answer = mode else { return }
hasStartedConnecting = true
if let sdp = remoteSDP {
@ -172,7 +176,6 @@ public final class SessionCall: NSObject, WebRTCSessionDelegate {
} else {
isWaitingForRemoteSDP = true
}
completion?()
}
func endSessionCall() {

View File

@ -2,7 +2,7 @@ import CallKit
import SessionUtilitiesKit
extension SessionCallManager {
public func startCall(_ call: SessionCall, completion: (() -> Void)?) {
public func startCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
guard case .offer = call.mode else { return }
let handle = CXHandle(type: .generic, value: call.sessionID)
let startCallAction = CXStartCallAction(call: call.uuid, handle: handle)
@ -13,17 +13,23 @@ extension SessionCallManager {
transaction.addAction(startCallAction)
reportOutgoingCall(call)
requestTransaction(transaction)
completion?()
requestTransaction(transaction, completion: completion)
}
public func endCall(_ call: SessionCall, completion: (() -> Void)?) {
public func answerCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
let answerCallAction = CXAnswerCallAction(call: call.uuid)
let transaction = CXTransaction()
transaction.addAction(answerCallAction)
requestTransaction(transaction, completion: completion)
}
public func endCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
let endCallAction = CXEndCallAction(call: call.uuid)
let transaction = CXTransaction()
transaction.addAction(endCallAction)
requestTransaction(transaction)
completion?()
requestTransaction(transaction, completion: completion)
}
// Not currently in use
@ -35,13 +41,14 @@ extension SessionCallManager {
requestTransaction(transaction)
}
private func requestTransaction(_ transaction: CXTransaction) {
private func requestTransaction(_ transaction: CXTransaction, completion: ((Error?) -> Void)? = nil) {
callController.request(transaction) { error in
if let error = error {
SNLog("Error requesting transaction: \(error)")
} else {
SNLog("Requested transaction successfully")
}
completion?(error)
}
}
}

View File

@ -9,18 +9,22 @@ extension SessionCallManager: CXProviderDelegate {
public func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
AssertIsOnMainThread()
guard let call = self.currentCall else { return action.fail() }
call.startSessionCall(completion: nil)
call.startSessionCall()
action.fulfill()
}
public func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
AssertIsOnMainThread()
guard let _ = self.currentCall else { return action.fail() }
let userDefaults = UserDefaults.standard
if userDefaults[.hasSeenCallIPExposureWarning] {
showCallVC()
guard let call = self.currentCall else { return action.fail() }
if let _ = CurrentAppContext().frontmostViewController() as? CallVC {
call.answerSessionCall()
} else {
showCallModal()
let userDefaults = UserDefaults.standard
if userDefaults[.hasSeenCallIPExposureWarning] {
showCallVC()
} else {
showCallModal()
}
}
action.fulfill()
}

View File

@ -4,7 +4,19 @@ import SessionMessagingKit
public final class SessionCallManager: NSObject {
let provider: CXProvider
let callController = CXCallController()
var currentCall: SessionCall?
var currentCall: SessionCall? = nil {
willSet {
if (newValue != nil) {
DispatchQueue.main.async {
UIApplication.shared.isIdleTimerDisabled = true
}
} else {
DispatchQueue.main.async {
UIApplication.shared.isIdleTimerDisabled = false
}
}
}
}
private static var _sharedProvider: CXProvider?
class func sharedProvider(useSystemCallLog: Bool) -> CXProvider {
@ -46,12 +58,13 @@ public final class SessionCallManager: NSObject {
public func reportOutgoingCall(_ call: SessionCall) {
AssertIsOnMainThread()
self.currentCall = call
call.hasStartedConnectingDidChange = {
self.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)
}
call.hasConnectedDidChange = {
self.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectedDate)
call.stateDidChange = {
if call.hasStartedConnecting {
self.provider.reportOutgoingCall(with: call.uuid, startedConnectingAt: call.connectingDate)
}
if call.hasConnected {
self.provider.reportOutgoingCall(with: call.uuid, connectedAt: call.connectedDate)
}
}
}
@ -69,11 +82,11 @@ public final class SessionCallManager: NSObject {
// Report the incoming call to the system
self.provider.reportNewIncomingCall(with: call.uuid, update: update) { error in
guard error == nil else {
self.currentCall = nil
completion(error)
Logger.error("failed to report new incoming call, error: \(error!)")
return
}
self.currentCall = call
completion(nil)
}
}

View File

@ -167,6 +167,15 @@ final class CallVC : UIViewController, VideoPreviewDelegate {
}
}
}
self.call.hasStartedConnectingDidChange = {
DispatchQueue.main.async {
self.callInfoLabel.text = "Connecting..."
self.answerButton.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.answerButton.isHidden = true
}, completion: nil)
}
}
self.call.hasConnectedDidChange = {
DispatchQueue.main.async {
self.callInfoLabel.text = "Connected"
@ -180,8 +189,10 @@ final class CallVC : UIViewController, VideoPreviewDelegate {
}
}
self.call.hasEndedDidChange = {
self.conversationVC?.showInputAccessoryView()
self.presentingViewController?.dismiss(animated: true, completion: nil)
DispatchQueue.main.async {
self.conversationVC?.showInputAccessoryView()
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
}
@ -194,9 +205,16 @@ final class CallVC : UIViewController, VideoPreviewDelegate {
if shouldRestartCamera { cameraManager.prepare() }
touch(call.videoCapturer)
titleLabel.text = self.call.contactName
AppEnvironment.shared.callManager.startCall(call) {
self.callInfoLabel.text = "Ringing..."
self.answerButton.isHidden = true
AppEnvironment.shared.callManager.startCall(call) { error in
DispatchQueue.main.async {
if let _ = error {
self.callInfoLabel.text = "Can't start a call."
self.endCall()
} else {
self.callInfoLabel.text = "Ringing..."
self.answerButton.isHidden = true
}
}
}
if shouldAnswer { answerCall() }
}
@ -305,12 +323,13 @@ final class CallVC : UIViewController, VideoPreviewDelegate {
@objc private func answerCall() {
let userDefaults = UserDefaults.standard
if userDefaults[.hasSeenCallIPExposureWarning] {
self.call.answerSessionCall{
self.callInfoLabel.text = "Connecting..."
self.answerButton.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.answerButton.isHidden = true
}, completion: nil)
AppEnvironment.shared.callManager.answerCall(call) { error in
DispatchQueue.main.async {
if let _ = error {
self.callInfoLabel.text = "Can't answer the call."
self.endCall()
}
}
}
} else {
userDefaults[.hasSeenCallIPExposureWarning] = true
@ -319,7 +338,12 @@ final class CallVC : UIViewController, VideoPreviewDelegate {
}
@objc private func endCall() {
AppEnvironment.shared.callManager.endCall(call, completion: nil)
AppEnvironment.shared.callManager.endCall(call) { error in
if let _ = error {
self.call.endSessionCall()
AppEnvironment.shared.callManager.reportCurrentCallEnded(reason: nil)
}
}
}
@objc private func minimize() {

View File

@ -155,7 +155,11 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
}
@objc private func endCall() {
AppEnvironment.shared.callManager.endCall(call) {
AppEnvironment.shared.callManager.endCall(call) { error in
if let _ = error {
self.call.endSessionCall()
AppEnvironment.shared.callManager.reportCurrentCallEnded(reason: nil)
}
self.dismiss()
}
}

View File

@ -31,6 +31,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
let userDefaults = UserDefaults.standard
if userDefaults[.hasSeenCallIPExposureWarning] {
guard let contactSessionID = (thread as? TSContactThread)?.contactSessionID() else { return }
guard AppEnvironment.shared.callManager.currentCall == nil else { return }
let call = SessionCall(for: contactSessionID, uuid: UUID().uuidString, mode: .offer)
let callVC = CallVC(for: call)
callVC.conversationVC = self

View File

@ -17,7 +17,6 @@ extension AppDelegate {
conversationVC.inputAccessoryView?.isHidden = true
conversationVC.inputAccessoryView?.alpha = 0
presentingVC.present(callVC, animated: true, completion: nil)
return
}
}
call.reportIncomingCallIfNeeded{ error in