Implement end call message

This commit is contained in:
Niels Andriesse 2021-08-18 10:33:33 +10:00
parent ae3cce97df
commit 6fdf544368
9 changed files with 65 additions and 8 deletions

View File

@ -42,7 +42,7 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
return result
}()
private lazy var titleView: UILabel = {
private lazy var titleLabel: UILabel = {
let result = UILabel()
result.textColor = .white
result.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
@ -50,6 +50,16 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
return result
}()
private lazy var callEndedLabel: UILabel = {
let result = UILabel()
result.textColor = .white
result.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
result.textAlignment = .center
result.text = "Call Ended"
result.alpha = 0
return result
}()
// MARK: Mode
enum Mode {
case offer
@ -78,7 +88,7 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
Storage.read { transaction in
contact = Storage.shared.getContact(with: self.sessionID)
}
titleView.text = contact?.displayName(for: Contact.Context.regular) ?? sessionID
titleLabel.text = contact?.displayName(for: Contact.Context.regular) ?? sessionID
if case .offer = mode {
Storage.write { transaction in
self.webRTCSession.sendOffer(to: self.sessionID, using: transaction).retainUntilComplete()
@ -116,10 +126,14 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
closeButton.pin(.left, to: .left, of: view)
closeButton.pin(.top, to: .top, of: view, withInset: 32)
// Title view
view.addSubview(titleView)
titleView.translatesAutoresizingMaskIntoConstraints = false
titleView.center(.vertical, in: closeButton)
titleView.center(.horizontal, in: view)
view.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.center(.vertical, in: closeButton)
titleLabel.center(.horizontal, in: view)
// Call ended label
view.addSubview(callEndedLabel)
callEndedLabel.translatesAutoresizingMaskIntoConstraints = false
callEndedLabel.center(in: view)
}
override func viewDidAppear(_ animated: Bool) {
@ -132,12 +146,22 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
cameraManager.stop()
}
deinit {
// MARK: Interaction
func handleEndCallMessage(_ message: CallMessage) {
WebRTCSession.current?.dropConnection()
WebRTCSession.current = nil
UIView.animate(withDuration: 0.25) {
self.callEndedLabel.alpha = 1
}
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
// MARK: Interaction
@objc private func close() {
Storage.write { transaction in
WebRTCSession.current?.endCall(with: self.sessionID, using: transaction)
}
presentingViewController?.dismiss(animated: true, completion: nil)
}
}

View File

@ -5,6 +5,7 @@ extension AppDelegate {
@objc
func setUpCallHandling() {
// Offer messages
MessageReceiver.handleOfferCallMessage = { message in
DispatchQueue.main.async {
let sdp = RTCSessionDescription(type: .offer, sdp: message.sdps![0])
@ -24,6 +25,13 @@ extension AppDelegate {
presentingVC.present(alert, animated: true, completion: nil)
}
}
// End call messages
MessageReceiver.handleEndCallMessage = { message in
DispatchQueue.main.async {
guard let callVC = CurrentAppContext().frontmostViewController() as? CallVC else { return }
callVC.handleEndCallMessage(message)
}
}
}
@objc(syncConfigurationIfNeeded)

View File

@ -190,6 +190,15 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
}
}
public func endCall(with sessionID: String, using transaction: YapDatabaseReadWriteTransaction) {
guard let thread = TSContactThread.fetch(for: sessionID, using: transaction) else { return }
let message = CallMessage()
message.kind = .endCall
MessageSender.sendNonDurably(message, in: thread, using: transaction).retainUntilComplete()
dropConnection()
WebRTCSession.current = nil
}
public func dropConnection() {
peerConnection.close()
}

View File

@ -15,6 +15,7 @@ public final class CallMessage : ControlMessage {
case answer
case provisionalAnswer
case iceCandidates(sdpMLineIndexes: [UInt32], sdpMids: [String])
case endCall
public var description: String {
switch self {
@ -22,6 +23,7 @@ public final class CallMessage : ControlMessage {
case .answer: return "answer"
case .provisionalAnswer: return "provisionalAnswer"
case .iceCandidates(_, _): return "iceCandidates"
case .endCall: return "endCall"
}
}
}
@ -54,6 +56,7 @@ public final class CallMessage : ControlMessage {
guard let sdpMLineIndexes = coder.decodeObject(forKey: "sdpMLineIndexes") as? [UInt32],
let sdpMids = coder.decodeObject(forKey: "sdpMids") as? [String] else { return nil }
kind = .iceCandidates(sdpMLineIndexes: sdpMLineIndexes, sdpMids: sdpMids)
case "endCall": kind = .endCall
default: preconditionFailure()
}
if let sdps = coder.decodeObject(forKey: "sdps") as! [String]? { self.sdps = sdps }
@ -69,6 +72,7 @@ public final class CallMessage : ControlMessage {
coder.encode("iceCandidates", forKey: "kind")
coder.encode(sdpMLineIndexes, forKey: "sdpMLineIndexes")
coder.encode(sdpMids, forKey: "sdpMids")
case .endCall: coder.encode("endCall", forKey: "kind")
default: preconditionFailure()
}
coder.encode(sdps, forKey: "sdps")
@ -86,6 +90,7 @@ public final class CallMessage : ControlMessage {
let sdpMLineIndexes = callMessageProto.sdpMlineIndexes
let sdpMids = callMessageProto.sdpMids
kind = .iceCandidates(sdpMLineIndexes: sdpMLineIndexes, sdpMids: sdpMids)
case .endCall: kind = .endCall
}
let sdps = callMessageProto.sdps
return CallMessage(kind: kind, sdps: sdps)
@ -102,6 +107,7 @@ public final class CallMessage : ControlMessage {
case .answer: type = .answer
case .provisionalAnswer: type = .provisionalAnswer
case .iceCandidates(_, _): type = .iceCandidates
case .endCall: type = .endCall
}
let callMessageProto = SNProtoCallMessage.builder(type: type)
callMessageProto.setSdps(sdps)

View File

@ -657,6 +657,7 @@ extension SNProtoContent.SNProtoContentBuilder {
case answer = 2
case provisionalAnswer = 3
case iceCandidates = 4
case endCall = 5
}
private class func SNProtoCallMessageTypeWrap(_ value: SessionProtos_CallMessage.TypeEnum) -> SNProtoCallMessageType {
@ -665,6 +666,7 @@ extension SNProtoContent.SNProtoContentBuilder {
case .answer: return .answer
case .provisionalAnswer: return .provisionalAnswer
case .iceCandidates: return .iceCandidates
case .endCall: return .endCall
}
}
@ -674,6 +676,7 @@ extension SNProtoContent.SNProtoContentBuilder {
case .answer: return .answer
case .provisionalAnswer: return .provisionalAnswer
case .iceCandidates: return .iceCandidates
case .endCall: return .endCall
}
}

View File

@ -333,6 +333,7 @@ struct SessionProtos_CallMessage {
case answer // = 2
case provisionalAnswer // = 3
case iceCandidates // = 4
case endCall // = 5
init() {
self = .offer
@ -344,6 +345,7 @@ struct SessionProtos_CallMessage {
case 2: self = .answer
case 3: self = .provisionalAnswer
case 4: self = .iceCandidates
case 5: self = .endCall
default: return nil
}
}
@ -354,6 +356,7 @@ struct SessionProtos_CallMessage {
case .answer: return 2
case .provisionalAnswer: return 3
case .iceCandidates: return 4
case .endCall: return 5
}
}
@ -1849,6 +1852,7 @@ extension SessionProtos_CallMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding
2: .same(proto: "ANSWER"),
3: .same(proto: "PROVISIONAL_ANSWER"),
4: .same(proto: "ICE_CANDIDATES"),
5: .same(proto: "END_CALL"),
]
}

View File

@ -58,6 +58,7 @@ message CallMessage {
ANSWER = 2;
PROVISIONAL_ANSWER = 3;
ICE_CANDIDATES = 4;
END_CALL = 5;
}
// Multiple ICE candidates may be batched together for performance

View File

@ -289,6 +289,7 @@ extension MessageReceiver {
candidates.append(candidate)
}
getWebRTCSession().handleICECandidates(candidates)
case .endCall: handleEndCallMessage?(message)
}
}

View File

@ -3,6 +3,7 @@ import SessionUtilitiesKit
public enum MessageReceiver {
private static var lastEncryptionKeyPairRequest: [String:Date] = [:]
public static var handleOfferCallMessage: ((CallMessage) -> Void)?
public static var handleEndCallMessage: ((CallMessage) -> Void)?
public enum Error : LocalizedError {
case duplicateMessage