diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index fb4e3740c..be803d2e3 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -201,6 +201,10 @@ B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */; }; + B877E24226CA12910007970A /* CallVCV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24126CA12910007970A /* CallVCV2.swift */; }; + B877E24426CA12F00007970A /* CallVCV2+MessageSending.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24326CA12F00007970A /* CallVCV2+MessageSending.swift */; }; + B877E24626CA13BA0007970A /* CallVCV2+Camera.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24526CA13BA0007970A /* CallVCV2+Camera.swift */; }; + B877E24826CA15170007970A /* CallVCV2+WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24726CA15170007970A /* CallVCV2+WebSocket.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; }; B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF17026367CF800124B3C /* FileServerAPIV2.swift */; }; @@ -253,7 +257,7 @@ B8B558F926C4CE6800693325 /* CallVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B558F826C4CE6800693325 /* CallVC.swift */; }; B8B558FB26C4D25C00693325 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B558FA26C4D25C00693325 /* WebSocket.swift */; }; B8B558FD26C4D35400693325 /* TestCallServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B558FC26C4D35400693325 /* TestCallServer.swift */; }; - B8B558FF26C4E05E00693325 /* CallManager+Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B558FE26C4E05E00693325 /* CallManager+Messages.swift */; }; + B8B558FF26C4E05E00693325 /* CallManager+MessageHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B558FE26C4E05E00693325 /* CallManager+MessageHandling.swift */; }; B8B5590126C4E2A400693325 /* SignalingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B5590026C4E2A400693325 /* SignalingMessage.swift */; }; B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BB82A4238F627000BA5194 /* HomeVC.swift */; }; B8BC00C0257D90E30032E807 /* General.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC00BF257D90E30032E807 /* General.swift */; }; @@ -1200,6 +1204,10 @@ B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B87588582644CA9D000E60D0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinOpenGroupModal.swift; sourceTree = ""; }; + B877E24126CA12910007970A /* CallVCV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVCV2.swift; sourceTree = ""; }; + B877E24326CA12F00007970A /* CallVCV2+MessageSending.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallVCV2+MessageSending.swift"; sourceTree = ""; }; + B877E24526CA13BA0007970A /* CallVCV2+Camera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallVCV2+Camera.swift"; sourceTree = ""; }; + B877E24726CA15170007970A /* CallVCV2+WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallVCV2+WebSocket.swift"; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; B879D448247E1BE300DB3608 /* PathVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathVC.swift; sourceTree = ""; }; B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; @@ -1229,7 +1237,7 @@ B8B558F826C4CE6800693325 /* CallVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVC.swift; sourceTree = ""; }; B8B558FA26C4D25C00693325 /* WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = ""; }; B8B558FC26C4D35400693325 /* TestCallServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestCallServer.swift; sourceTree = ""; }; - B8B558FE26C4E05E00693325 /* CallManager+Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallManager+Messages.swift"; sourceTree = ""; }; + B8B558FE26C4E05E00693325 /* CallManager+MessageHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallManager+MessageHandling.swift"; sourceTree = ""; }; B8B5590026C4E2A400693325 /* SignalingMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalingMessage.swift; sourceTree = ""; }; B8B5BCEB2394D869003823C9 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; B8BAC75B2695645400EA1759 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = ""; }; @@ -2190,6 +2198,18 @@ path = "Message Cells"; sourceTree = ""; }; + B877E24026CA11170007970A /* Temp */ = { + isa = PBXGroup; + children = ( + B8B5590026C4E2A400693325 /* SignalingMessage.swift */, + B8B558FA26C4D25C00693325 /* WebSocket.swift */, + B8B558F226C4CA4600693325 /* TestCallConfig.swift */, + B8B558FC26C4D35400693325 /* TestCallServer.swift */, + B80F469926C63DD000DCE243 /* RoomInfo.swift */, + ); + path = Temp; + sourceTree = ""; + }; B887C38125C7C79700E11DAE /* Input View */ = { isa = PBXGroup; children = ( @@ -2331,6 +2351,10 @@ B8B558ED26C4B55F00693325 /* Calls */ = { isa = PBXGroup; children = ( + B877E24126CA12910007970A /* CallVCV2.swift */, + B877E24326CA12F00007970A /* CallVCV2+MessageSending.swift */, + B877E24526CA13BA0007970A /* CallVCV2+Camera.swift */, + B877E24726CA15170007970A /* CallVCV2+WebSocket.swift */, B8B558F826C4CE6800693325 /* CallVC.swift */, B8B558EE26C4B56C00693325 /* VideoCallVC.swift */, B8B558F026C4BB0600693325 /* CameraManager.swift */, @@ -2367,14 +2391,10 @@ B8DE1FB226C22F1F0079C9CE /* Calls */ = { isa = PBXGroup; children = ( + B877E24026CA11170007970A /* Temp */, B8DE1FB326C22F2F0079C9CE /* CallManager.swift */, B806ECA026C4A7E4008BDA44 /* CallManager+UI.swift */, - B8B558FE26C4E05E00693325 /* CallManager+Messages.swift */, - B8B5590026C4E2A400693325 /* SignalingMessage.swift */, - B8B558FA26C4D25C00693325 /* WebSocket.swift */, - B8B558F226C4CA4600693325 /* TestCallConfig.swift */, - B8B558FC26C4D35400693325 /* TestCallServer.swift */, - B80F469926C63DD000DCE243 /* RoomInfo.swift */, + B8B558FE26C4E05E00693325 /* CallManager+MessageHandling.swift */, ); path = Calls; sourceTree = ""; @@ -4688,7 +4708,7 @@ C352A32F2557549C00338F3E /* NotifyPNServerJob.swift in Sources */, 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */, C300A5F22554B09800555489 /* MessageSender.swift in Sources */, - B8B558FF26C4E05E00693325 /* CallManager+Messages.swift in Sources */, + B8B558FF26C4E05E00693325 /* CallManager+MessageHandling.swift in Sources */, C3C2A74D2553A39700C340D1 /* VisibleMessage.swift in Sources */, C32C5AAD256DBE8F003C73A2 /* TSInfoMessage.m in Sources */, C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */, @@ -4842,6 +4862,7 @@ B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, B879D449247E1BE300DB3608 /* PathVC.swift in Sources */, + B877E24626CA13BA0007970A /* CallVCV2+Camera.swift in Sources */, 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */, 340FC8B4204DAC8D007AEB0F /* OWSBackupSettingsViewController.m in Sources */, 34D1F0871F8678AA0066283D /* ConversationViewItem.m in Sources */, @@ -4904,6 +4925,7 @@ B835246E25C38ABF0089A44F /* ConversationVC.swift in Sources */, B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */, B821494625D4D6FF009C0F2A /* URLModal.swift in Sources */, + B877E24226CA12910007970A /* CallVCV2.swift in Sources */, C374EEEB25DA3CA70073A857 /* ConversationTitleView.swift in Sources */, B88FA7F2260C3EB10049422F /* OpenGroupSuggestionGrid.swift in Sources */, 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */, @@ -4943,6 +4965,7 @@ B8041A9525C8FA1D003C2166 /* MediaLoaderView.swift in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, 34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */, + B877E24826CA15170007970A /* CallVCV2+WebSocket.swift in Sources */, 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */, C328253025CA55370062D0A7 /* ContextMenuWindow.swift in Sources */, 340FC8B7204DAC8D007AEB0F /* OWSConversationSettingsViewController.m in Sources */, @@ -4952,6 +4975,7 @@ C328250F25CA06020062D0A7 /* VoiceMessageView.swift in Sources */, B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */, 3488F9362191CC4000E524CC /* MediaView.swift in Sources */, + B877E24426CA12F00007970A /* CallVCV2+MessageSending.swift in Sources */, B8569AC325CB5D2900DBA3DB /* ConversationVC+Interaction.swift in Sources */, 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */, C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */, diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index c66ad7516..679da703f 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -1,215 +1,215 @@ -import UIKit -import AVFoundation -import WebRTC - -final class CallVC : UIViewController, CameraCaptureDelegate, CallManagerDelegate, WebSocketDelegate { - private var webSocket: WebSocket? - private let videoCallVC = VideoCallVC() - let videoCapturer: RTCVideoCapturer = RTCCameraVideoCapturer(delegate: CallManager.shared.localVideoSource) - private var messageQueue: [String] = [] - private var isConnected = false { - didSet { - let title = isConnected ? "Leave" : "Join" - joinOrLeaveButton.setTitle(title, for: UIControl.State.normal) - } - } - private var currentRoomInfo: RoomInfo? - - var isInitiator: Bool { - return currentRoomInfo?.isInitiator == true - } - - // MARK: UI Components - private lazy var previewView: UIImageView = { - return UIImageView() - }() - - private lazy var containerView: UIView = { - return UIView() - }() - - private lazy var joinOrLeaveButton: UIButton = { - let result = UIButton() - result.setTitle("Join", for: UIControl.State.normal) - result.addTarget(self, action: #selector(joinOrLeave), for: UIControl.Event.touchUpInside) - return result - }() - - private lazy var roomNumberTextField: UITextField = { - let result = UITextField() - result.set(.width, to: 120) - result.set(.height, to: 40) - result.backgroundColor = UIColor.white.withAlphaComponent(0.1) - return result - }() - - private lazy var infoTextView: UITextView = { - let result = UITextView() - result.backgroundColor = UIColor.white.withAlphaComponent(0.1) - return result - }() - - // MARK: Lifecycle - override func viewDidLoad() { - super.viewDidLoad() - touch(CallManager.shared) - CallManager.shared.delegate = self - CameraManager.shared.delegate = self - CameraManager.shared.prepare() - addChild(videoCallVC) - containerView.addSubview(videoCallVC.view) - videoCallVC.view.translatesAutoresizingMaskIntoConstraints = false - videoCallVC.view.pin(to: containerView) - view.addSubview(containerView) - containerView.pin(to: view) - view.addSubview(joinOrLeaveButton) - joinOrLeaveButton.translatesAutoresizingMaskIntoConstraints = false - joinOrLeaveButton.pin([ UIView.VerticalEdge.top, UIView.HorizontalEdge.right ], to: view) - view.addSubview(roomNumberTextField) - roomNumberTextField.translatesAutoresizingMaskIntoConstraints = false - roomNumberTextField.pin([ UIView.VerticalEdge.top, UIView.HorizontalEdge.left ], to: view) - view.addSubview(infoTextView) - infoTextView.translatesAutoresizingMaskIntoConstraints = false - infoTextView.pin([ UIView.HorizontalEdge.left, UIView.HorizontalEdge.right ], to: view) - infoTextView.center(.vertical, in: view) - infoTextView.set(.height, to: 200) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - CameraManager.shared.start() - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - CameraManager.shared.stop() - } - - // MARK: Interaction - @objc private func joinOrLeave() { - guard let roomID = roomNumberTextField.text, !roomID.isEmpty else { return } - if isConnected { - disconnect() - } else { - isConnected = true - TestCallServer.join(roomID: roomID).done2 { [weak self] info in - guard let self = self else { return } - self.log("Successfully joined room.") - self.currentRoomInfo = info - if let messages = info.messages { - self.handle(messages) - } - let webSocket = WebSocket(url: URL(string: info.wssURL)!) - webSocket.delegate = self - self.webSocket = webSocket - }.catch2 { [weak self] error in - guard let self = self else { return } - self.isConnected = false - self.log("Couldn't join room due to error: \(error).") - SNLog("Couldn't join room due to error: \(error).") - } - roomNumberTextField.resignFirstResponder() - } - } - - private func disconnect() { - guard let info = currentRoomInfo else { return } - TestCallServer.leave(roomID: info.roomID, userID: info.clientID).done2 { [weak self] in - guard let self = self else { return } - self.log("Disconnected.") - } - let message = [ "type": "bye" ] - guard let data = try? JSONSerialization.data(withJSONObject: message, options: [.prettyPrinted]) else { return } - webSocket?.send(data) - webSocket?.delegate = nil - webSocket = nil - currentRoomInfo = nil - isConnected = false - CallManager.shared.endCall() - } - - // MARK: Message Handling - func handle(_ messages: [String]) { - messageQueue.append(contentsOf: messages) - drainMessageQueue() - } - - func drainMessageQueue() { - guard isConnected else { return } - for message in messageQueue { - handle(message) - } - messageQueue.removeAll() - CallManager.shared.drainMessageQueue() - } - - func handle(_ message: String) { - let signalingMessage = SignalingMessage.from(message: message) - switch signalingMessage { - case .candidate(let candidate): - CallManager.shared.handleCandidateMessage(candidate) - log("Candidate received.") - case .answer(let answer): - CallManager.shared.handleRemoteDescription(answer) - log("Answer received.") - case .offer(let offer): - CallManager.shared.handleRemoteDescription(offer) - log("Offer received.") - case .bye: - disconnect() - default: - break - } - } - - // MARK: Streaming - func webSocketDidConnect(_ webSocket: WebSocket) { - guard let info = currentRoomInfo else { return } - log("Connected to web socket.") - let message = [ - "cmd": "register", - "roomid": info.roomID, - "clientid": info.clientID - ] - guard let data = try? JSONSerialization.data(withJSONObject: message, options: [.prettyPrinted]) else { return } - webSocket.send(data) - if isInitiator { - CallManager.shared.initiateCall().retainUntilComplete() - } - drainMessageQueue() - } - - func webSocket(_ webSocket: WebSocket, didReceive message: String) { - log("Received data from web socket.") - handle(message) - CallManager.shared.drainMessageQueue() - } - - func webSocketDidDisconnect(_ webSocket: WebSocket) { - webSocket.delegate = nil - log("Disconnecting from web socket.") - } - - func callManager(_ callManager: CallManager, sendData data: Data) { - guard let info = currentRoomInfo else { return } - TestCallServer.send(data, roomID: info.roomID, userID: info.clientID).retainUntilComplete() - } - - // MARK: Camera - func captureVideoOutput(sampleBuffer: CMSampleBuffer) { - guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } - let ciImage = CIImage(cvImageBuffer: pixelBuffer) - let image = UIImage(ciImage: ciImage) - DispatchQueue.main.async { [weak self] in - self?.previewView.image = image - } - } - - // MARK: Logging - private func log(_ string: String) { - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - self.infoTextView.text = self.infoTextView.text + "\n" + string - } - } -} +//import UIKit +//import AVFoundation +//import WebRTC +// +//final class CallVC : UIViewController, CameraCaptureDelegate, CallManagerDelegate, WebSocketDelegate { +// private var webSocket: WebSocket? +// private let videoCallVC = VideoCallVC() +// let videoCapturer: RTCVideoCapturer = RTCCameraVideoCapturer(delegate: CallManager.shared.localVideoSource) +// private var messageQueue: [String] = [] +// private var isConnected = false { +// didSet { +// let title = isConnected ? "Leave" : "Join" +// joinOrLeaveButton.setTitle(title, for: UIControl.State.normal) +// } +// } +// private var currentRoomInfo: RoomInfo? +// +// var isInitiator: Bool { +// return currentRoomInfo?.isInitiator == true +// } +// +// // MARK: UI Components +// private lazy var previewView: UIImageView = { +// return UIImageView() +// }() +// +// private lazy var containerView: UIView = { +// return UIView() +// }() +// +// private lazy var joinOrLeaveButton: UIButton = { +// let result = UIButton() +// result.setTitle("Join", for: UIControl.State.normal) +// result.addTarget(self, action: #selector(joinOrLeave), for: UIControl.Event.touchUpInside) +// return result +// }() +// +// private lazy var roomNumberTextField: UITextField = { +// let result = UITextField() +// result.set(.width, to: 120) +// result.set(.height, to: 40) +// result.backgroundColor = UIColor.white.withAlphaComponent(0.1) +// return result +// }() +// +// private lazy var infoTextView: UITextView = { +// let result = UITextView() +// result.backgroundColor = UIColor.white.withAlphaComponent(0.1) +// return result +// }() +// +// // MARK: Lifecycle +// override func viewDidLoad() { +// super.viewDidLoad() +// touch(CallManager.shared) +// CallManager.shared.delegate = self +// CameraManager.shared.delegate = self +// CameraManager.shared.prepare() +// addChild(videoCallVC) +// containerView.addSubview(videoCallVC.view) +// videoCallVC.view.translatesAutoresizingMaskIntoConstraints = false +// videoCallVC.view.pin(to: containerView) +// view.addSubview(containerView) +// containerView.pin(to: view) +// view.addSubview(joinOrLeaveButton) +// joinOrLeaveButton.translatesAutoresizingMaskIntoConstraints = false +// joinOrLeaveButton.pin([ UIView.VerticalEdge.top, UIView.HorizontalEdge.right ], to: view) +// view.addSubview(roomNumberTextField) +// roomNumberTextField.translatesAutoresizingMaskIntoConstraints = false +// roomNumberTextField.pin([ UIView.VerticalEdge.top, UIView.HorizontalEdge.left ], to: view) +// view.addSubview(infoTextView) +// infoTextView.translatesAutoresizingMaskIntoConstraints = false +// infoTextView.pin([ UIView.HorizontalEdge.left, UIView.HorizontalEdge.right ], to: view) +// infoTextView.center(.vertical, in: view) +// infoTextView.set(.height, to: 200) +// } +// +// override func viewDidAppear(_ animated: Bool) { +// super.viewDidAppear(animated) +// CameraManager.shared.start() +// } +// +// override func viewWillDisappear(_ animated: Bool) { +// super.viewWillDisappear(animated) +// CameraManager.shared.stop() +// } +// +// // MARK: Interaction +// @objc private func joinOrLeave() { +// guard let roomID = roomNumberTextField.text, !roomID.isEmpty else { return } +// if isConnected { +// disconnect() +// } else { +// isConnected = true +// TestCallServer.join(roomID: roomID).done2 { [weak self] info in +// guard let self = self else { return } +// self.log("Successfully joined room.") +// self.currentRoomInfo = info +// if let messages = info.messages { +// self.handle(messages) +// } +// let webSocket = WebSocket(url: URL(string: info.wssURL)!) +// webSocket.delegate = self +// self.webSocket = webSocket +// }.catch2 { [weak self] error in +// guard let self = self else { return } +// self.isConnected = false +// self.log("Couldn't join room due to error: \(error).") +// SNLog("Couldn't join room due to error: \(error).") +// } +// roomNumberTextField.resignFirstResponder() +// } +// } +// +// private func disconnect() { +// guard let info = currentRoomInfo else { return } +// TestCallServer.leave(roomID: info.roomID, userID: info.clientID).done2 { [weak self] in +// guard let self = self else { return } +// self.log("Disconnected.") +// } +// let message = [ "type": "bye" ] +// guard let data = try? JSONSerialization.data(withJSONObject: message, options: [.prettyPrinted]) else { return } +// webSocket?.send(data) +// webSocket?.delegate = nil +// webSocket = nil +// currentRoomInfo = nil +// isConnected = false +// CallManager.shared.endCall() +// } +// +// // MARK: Message Handling +// func handle(_ messages: [String]) { +// messageQueue.append(contentsOf: messages) +// drainMessageQueue() +// } +// +// func drainMessageQueue() { +// guard isConnected else { return } +// for message in messageQueue { +// handle(message) +// } +// messageQueue.removeAll() +// CallManager.shared.drainICECandidateQueue() +// } +// +// func handle(_ message: String) { +// let signalingMessage = SignalingMessage.from(message: message) +// switch signalingMessage { +// case .candidate(let candidate): +// CallManager.shared.handleCandidateMessage(candidate) +// log("Candidate received.") +// case .answer(let answer): +// CallManager.shared.handleRemoteDescription(answer) +// log("Answer received.") +// case .offer(let offer): +// CallManager.shared.handleRemoteDescription(offer) +// log("Offer received.") +// case .bye: +// disconnect() +// default: +// break +// } +// } +// +// // MARK: Streaming +// func webSocketDidConnect(_ webSocket: WebSocket) { +// guard let info = currentRoomInfo else { return } +// log("Connected to web socket.") +// let message = [ +// "cmd": "register", +// "roomid": info.roomID, +// "clientid": info.clientID +// ] +// guard let data = try? JSONSerialization.data(withJSONObject: message, options: [.prettyPrinted]) else { return } +// webSocket.send(data) +// if isInitiator { +// CallManager.shared.initiateCall().retainUntilComplete() +// } +// drainMessageQueue() +// } +// +// func webSocket(_ webSocket: WebSocket, didReceive message: String) { +// log("Received data from web socket.") +// handle(message) +// CallManager.shared.drainICECandidateQueue() +// } +// +// func webSocketDidDisconnect(_ webSocket: WebSocket) { +// webSocket.delegate = nil +// log("Disconnecting from web socket.") +// } +// +// func callManager(_ callManager: CallManager, sendData data: Data) { +// guard let info = currentRoomInfo else { return } +// TestCallServer.send(data, roomID: info.roomID, userID: info.clientID).retainUntilComplete() +// } +// +// // MARK: Camera +// func captureVideoOutput(sampleBuffer: CMSampleBuffer) { +// guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } +// let ciImage = CIImage(cvImageBuffer: pixelBuffer) +// let image = UIImage(ciImage: ciImage) +// DispatchQueue.main.async { [weak self] in +// self?.previewView.image = image +// } +// } +// +// // MARK: Logging +// private func log(_ string: String) { +// DispatchQueue.main.async { [weak self] in +// guard let self = self else { return } +// self.infoTextView.text = self.infoTextView.text + "\n" + string +// } +// } +//} diff --git a/Session/Calls/CallVCV2+Camera.swift b/Session/Calls/CallVCV2+Camera.swift new file mode 100644 index 000000000..030b8bc47 --- /dev/null +++ b/Session/Calls/CallVCV2+Camera.swift @@ -0,0 +1,14 @@ +import WebRTC + +extension CallVCV2 : CameraManagerDelegate { + + func handleVideoOutputCaptured(sampleBuffer: CMSampleBuffer) { + guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } + let rtcPixelBuffer = RTCCVPixelBuffer(pixelBuffer: pixelBuffer) + let timestamp = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) + let timestampNs = Int64(timestamp * 1000000000) + let frame = RTCVideoFrame(buffer: rtcPixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: timestampNs) + frame.timeStamp = Int32(timestamp) + callManager.handleLocalFrameCaptured(frame) + } +} diff --git a/Session/Calls/CallVCV2+MessageSending.swift b/Session/Calls/CallVCV2+MessageSending.swift new file mode 100644 index 000000000..11f0bcfe2 --- /dev/null +++ b/Session/Calls/CallVCV2+MessageSending.swift @@ -0,0 +1,31 @@ +import WebRTC + +extension CallVCV2 : CallManagerDelegate { + + /// Invoked by `CallManager` upon initiating or accepting a call. This method sends the SDP to the other + /// party before streaming starts. + func sendSDP(_ sdp: RTCSessionDescription) { + guard let room = room else { return } + let json = [ + "type" : RTCSessionDescription.string(for: sdp.type), + "sdp" : sdp.sdp + ] + guard let data = try? JSONSerialization.data(withJSONObject: json, options: [ .prettyPrinted ]) else { return } + print("[Calls] Sending SDP to test call server: \(json).") + TestCallServer.send(data, roomID: room.roomID, userID: room.clientID).retainUntilComplete() + } + + /// Invoked when the peer connection has generated an ICE candidate. + func sendICECandidate(_ candidate: RTCIceCandidate) { + guard let room = room else { return } + let json = [ + "type" : "candidate", + "label" : "\(candidate.sdpMLineIndex)", + "id" : candidate.sdpMid, + "candidate" : candidate.sdp + ] + guard let data = try? JSONSerialization.data(withJSONObject: json, options: [ .prettyPrinted ]) else { return } + print("[Calls] Sending ICE candidate to test call server: \(json).") + TestCallServer.send(data, roomID: room.roomID, userID: room.clientID).retainUntilComplete() + } +} diff --git a/Session/Calls/CallVCV2+WebSocket.swift b/Session/Calls/CallVCV2+WebSocket.swift new file mode 100644 index 000000000..26ca6e61f --- /dev/null +++ b/Session/Calls/CallVCV2+WebSocket.swift @@ -0,0 +1,28 @@ + +extension CallVCV2 : WebSocketDelegate { + + func webSocketDidConnect(_ webSocket: WebSocket) { + guard let room = room else { return } + let json = [ + "cmd" : "register", + "roomid" : room.roomID, + "clientid" : room.clientID + ] + guard let data = try? JSONSerialization.data(withJSONObject: json, options: [ .prettyPrinted ]) else { return } + print("[Calls] Web socket connected. Sending: \(json).") + webSocket.send(data) + print("[Calls] Is initiator: \(room.isInitiator).") + if room.isInitiator { + callManager.initiateCall().retainUntilComplete() + } + } + + func webSocketDidDisconnect(_ webSocket: WebSocket) { + webSocket.delegate = nil + } + + func webSocket(_ webSocket: WebSocket, didReceive message: String) { + print("[Calls] Message received through web socket: \(message).") + handle([ message ]) + } +} diff --git a/Session/Calls/CallVCV2.swift b/Session/Calls/CallVCV2.swift new file mode 100644 index 000000000..ab1ff8ccd --- /dev/null +++ b/Session/Calls/CallVCV2.swift @@ -0,0 +1,95 @@ +import WebRTC + +final class CallVCV2 : UIViewController { + let roomID = "37923672512" // NOTE: You need to change this every time to ensure the room isn't full + var room: RoomInfo? + var socket: WebSocket? + + lazy var callManager: CallManager = { + let result = CallManager() + result.delegate = self + return result + }() + + lazy var cameraManager: CameraManager = { + let result = CameraManager() + result.delegate = self + return result + }() + + lazy var videoCapturer: RTCVideoCapturer = { + return RTCCameraVideoCapturer(delegate: callManager.localVideoSource) + }() + + // MARK: Lifecycle + override func viewDidLoad() { + super.viewDidLoad() + setUpViewHierarchy() + cameraManager.prepare() + touch(videoCapturer) + autoConnectToTestRoom() + } + + func setUpViewHierarchy() { + // Create video views + let localVideoView = RTCMTLVideoView() + localVideoView.contentMode = .scaleAspectFill + let remoteVideoView = RTCMTLVideoView() + remoteVideoView.contentMode = .scaleAspectFill + // Set up stack view + let stackView = UIStackView(arrangedSubviews: [ localVideoView, remoteVideoView ]) + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.alignment = .fill + view.addSubview(stackView) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.pin(to: view) + // Attach video views + callManager.attachLocalRenderer(localVideoView) + callManager.attachRemoteRenderer(remoteVideoView) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + cameraManager.start() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + cameraManager.stop() + } + + // MARK: General + func autoConnectToTestRoom() { + // Connect to a random test room + TestCallServer.join(roomID: roomID).done2 { [weak self] room in + print("[Calls] Connected to test room.") + guard let self = self else { return } + self.room = room + if let messages = room.messages { + self.handle(messages) + } + let socket = WebSocket(url: URL(string: room.wssURL)!) + socket.delegate = self + socket.connect() + self.socket = socket + }.catch2 { error in + SNLog("Couldn't join room due to error: \(error).") + } + } + + func handle(_ messages: [String]) { + print("[Calls] Handling messages:") + messages.forEach { print("[Calls] \($0)") } + messages.forEach { message in + let signalingMessage = SignalingMessage.from(message: message) + switch signalingMessage { + case .candidate(let candidate): callManager.handleCandidateMessage(candidate) + case .answer(let answer): callManager.handleRemoteDescription(answer) + case .offer(let offer): callManager.handleRemoteDescription(offer) + default: break + } + } + callManager.drainICECandidateQueue() + } +} diff --git a/Session/Calls/CameraManager.swift b/Session/Calls/CameraManager.swift index 019efab22..e9af7ddc1 100644 --- a/Session/Calls/CameraManager.swift +++ b/Session/Calls/CameraManager.swift @@ -2,29 +2,26 @@ import Foundation import AVFoundation @objc -protocol CameraCaptureDelegate : AnyObject { +protocol CameraManagerDelegate : AnyObject { - func captureVideoOutput(sampleBuffer: CMSampleBuffer) + func handleVideoOutputCaptured(sampleBuffer: CMSampleBuffer) } final class CameraManager : NSObject { private let captureSession = AVCaptureSession() private let videoDataOutput = AVCaptureVideoDataOutput() + private let videoDataOutputQueue + = DispatchQueue(label: "CameraManager.videoDataOutputQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem) private let audioDataOutput = AVCaptureAudioDataOutput() - private let dataOutputQueue = DispatchQueue(label: "CameraManager.dataOutputQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem) private var isCapturing = false - weak var delegate: CameraCaptureDelegate? + weak var delegate: CameraManagerDelegate? private lazy var videoCaptureDevice: AVCaptureDevice? = { return AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) }() - static let shared = CameraManager() - - private override init() { } - func prepare() { - captureSession.sessionPreset = .low + print("[Calls] Preparing camera.") if let videoCaptureDevice = videoCaptureDevice, let videoInput = try? AVCaptureDeviceInput(device: videoCaptureDevice), captureSession.canAddInput(videoInput) { captureSession.addInput(videoInput) @@ -32,30 +29,28 @@ final class CameraManager : NSObject { if captureSession.canAddOutput(videoDataOutput) { captureSession.addOutput(videoDataOutput) videoDataOutput.videoSettings = [ kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA) ] - videoDataOutput.setSampleBufferDelegate(self, queue: dataOutputQueue) - videoDataOutput.connection(with: .video)?.videoOrientation = .portrait - videoDataOutput.connection(with: .video)?.automaticallyAdjustsVideoMirroring = false - videoDataOutput.connection(with: .video)?.isVideoMirrored = true + videoDataOutput.setSampleBufferDelegate(self, queue: videoDataOutputQueue) + guard let connection = videoDataOutput.connection(with: AVMediaType.video) else { return } + connection.videoOrientation = .portrait + connection.automaticallyAdjustsVideoMirroring = false + connection.isVideoMirrored = true } else { SNLog("Couldn't add video data output to capture session.") - captureSession.commitConfiguration() } } func start() { guard !isCapturing else { return } + print("[Calls] Starting camera.") isCapturing = true - #if arch(arm64) captureSession.startRunning() - #endif } func stop() { guard isCapturing else { return } + print("[Calls] Stopping camera.") isCapturing = false - #if arch(arm64) captureSession.stopRunning() - #endif } } @@ -63,7 +58,7 @@ extension CameraManager : AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptur func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard connection == videoDataOutput.connection(with: .video) else { return } - delegate?.captureVideoOutput(sampleBuffer: sampleBuffer) + delegate?.handleVideoOutputCaptured(sampleBuffer: sampleBuffer) } func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { } diff --git a/Session/Calls/VideoCallVC.swift b/Session/Calls/VideoCallVC.swift index 6e7caf8ca..de4523573 100644 --- a/Session/Calls/VideoCallVC.swift +++ b/Session/Calls/VideoCallVC.swift @@ -1,60 +1,60 @@ -import UIKit -import AVFoundation -import WebRTC - -final class VideoCallVC : UIViewController { - private var localVideoView = UIView() - private var remoteVideoView = UIView() - - override func viewDidLoad() { - super.viewDidLoad() - setUpViewHierarchy() - CameraManager.shared.delegate = self - } - - private func setUpViewHierarchy() { - // Create video views - #if arch(arm64) - // Use Metal - let localRenderer = RTCMTLVideoView(frame: self.localVideoView.frame) - localRenderer.contentMode = .scaleAspectFill - let remoteRenderer = RTCMTLVideoView(frame: self.remoteVideoView.frame) - remoteRenderer.contentMode = .scaleAspectFill - #else - // Use OpenGLES - let localRenderer = RTCEAGLVideoView(frame: self.localVideoView.frame) - let remoteRenderer = RTCEAGLVideoView(frame: self.remoteVideoView.frame) - #endif - // Set up stack view - let stackView = UIStackView(arrangedSubviews: [ localVideoView, remoteVideoView ]) - stackView.axis = .vertical - stackView.distribution = .fillEqually - stackView.alignment = .fill - view.addSubview(stackView) - stackView.translatesAutoresizingMaskIntoConstraints = false - stackView.pin(to: view) - // Attach video views - CallManager.shared.attachLocalRenderer(localRenderer) - CallManager.shared.attachRemoteRenderer(remoteRenderer) - localVideoView.addSubview(localRenderer) - localRenderer.translatesAutoresizingMaskIntoConstraints = false - localRenderer.pin(to: localVideoView) - remoteVideoView.addSubview(remoteRenderer) - remoteRenderer.translatesAutoresizingMaskIntoConstraints = false - remoteRenderer.pin(to: remoteVideoView) - } -} - -// MARK: Camera -extension VideoCallVC : CameraCaptureDelegate { - - func captureVideoOutput(sampleBuffer: CMSampleBuffer) { - guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } - let rtcpixelBuffer = RTCCVPixelBuffer(pixelBuffer: pixelBuffer) - let timestamp = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) - let timestampNs = Int64(timestamp * 1000000000) - let videoFrame = RTCVideoFrame(buffer: rtcpixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: timestampNs) - videoFrame.timeStamp = Int32(timestamp) - CallManager.shared.handleLocalFrameCaptured(videoFrame) - } -} +//import UIKit +//import AVFoundation +//import WebRTC +// +//final class VideoCallVC : UIViewController { +// private var localVideoView = UIView() +// private var remoteVideoView = UIView() +// +// override func viewDidLoad() { +// super.viewDidLoad() +// setUpViewHierarchy() +// CameraManager.shared.delegate = self +// } +// +// private func setUpViewHierarchy() { +// // Create video views +// #if arch(arm64) +// // Use Metal +// let localRenderer = RTCMTLVideoView(frame: self.localVideoView.frame) +// localRenderer.contentMode = .scaleAspectFill +// let remoteRenderer = RTCMTLVideoView(frame: self.remoteVideoView.frame) +// remoteRenderer.contentMode = .scaleAspectFill +// #else +// // Use OpenGLES +// let localRenderer = RTCEAGLVideoView(frame: self.localVideoView.frame) +// let remoteRenderer = RTCEAGLVideoView(frame: self.remoteVideoView.frame) +// #endif +// // Set up stack view +// let stackView = UIStackView(arrangedSubviews: [ localVideoView, remoteVideoView ]) +// stackView.axis = .vertical +// stackView.distribution = .fillEqually +// stackView.alignment = .fill +// view.addSubview(stackView) +// stackView.translatesAutoresizingMaskIntoConstraints = false +// stackView.pin(to: view) +// // Attach video views +// CallManager.shared.attachLocalRenderer(localRenderer) +// CallManager.shared.attachRemoteRenderer(remoteRenderer) +// localVideoView.addSubview(localRenderer) +// localRenderer.translatesAutoresizingMaskIntoConstraints = false +// localRenderer.pin(to: localVideoView) +// remoteVideoView.addSubview(remoteRenderer) +// remoteRenderer.translatesAutoresizingMaskIntoConstraints = false +// remoteRenderer.pin(to: remoteVideoView) +// } +//} +// +//// MARK: Camera +//extension VideoCallVC : CameraCaptureDelegate { +// +// func captureVideoOutput(sampleBuffer: CMSampleBuffer) { +// guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } +// let rtcpixelBuffer = RTCCVPixelBuffer(pixelBuffer: pixelBuffer) +// let timestamp = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) +// let timestampNs = Int64(timestamp * 1000000000) +// let videoFrame = RTCVideoFrame(buffer: rtcpixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: timestampNs) +// videoFrame.timeStamp = Int32(timestamp) +// CallManager.shared.handleLocalFrameCaptured(videoFrame) +// } +//} diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index e62d27dd8..dcd501085 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -158,7 +158,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv // Get default open group rooms if needed OpenGroupAPIV2.getDefaultRoomsIfNeeded() - let callVC = CallVC() + let callVC = CallVCV2() present(callVC, animated: true, completion: nil) } diff --git a/SessionMessagingKit/Calls/CallManager+Messages.swift b/SessionMessagingKit/Calls/CallManager+MessageHandling.swift similarity index 56% rename from SessionMessagingKit/Calls/CallManager+Messages.swift rename to SessionMessagingKit/Calls/CallManager+MessageHandling.swift index a4601d6e0..e2a2cd811 100644 --- a/SessionMessagingKit/Calls/CallManager+Messages.swift +++ b/SessionMessagingKit/Calls/CallManager+MessageHandling.swift @@ -3,26 +3,20 @@ import WebRTC extension CallManager { public func handleCandidateMessage(_ candidate: RTCIceCandidate) { + print("[Calls] Received ICE candidate message.") candidateQueue.append(candidate) } public func handleRemoteDescription(_ sdp: RTCSessionDescription) { + print("[Calls] Received remote SDP: \(sdp.sdp).") peerConnection.setRemoteDescription(sdp, completionHandler: { [weak self] error in if let error = error { SNLog("Couldn't set SDP due to error: \(error).") } else { - guard let self = self else { return } - if sdp.type == .offer, self.peerConnection.localDescription == nil { - self.acceptCall() - } + guard let self = self, + sdp.type == .offer, self.peerConnection.localDescription == nil else { return } + self.acceptCall().retainUntilComplete() } }) } - - public func drainMessageQueue() { - for candidate in candidateQueue { - peerConnection.add(candidate) - } - candidateQueue.removeAll() - } } diff --git a/SessionMessagingKit/Calls/CallManager.swift b/SessionMessagingKit/Calls/CallManager.swift index 5994c9a00..0c447a842 100644 --- a/SessionMessagingKit/Calls/CallManager.swift +++ b/SessionMessagingKit/Calls/CallManager.swift @@ -3,8 +3,9 @@ import WebRTC public protocol CallManagerDelegate : AnyObject { var videoCapturer: RTCVideoCapturer { get } - - func callManager(_ callManager: CallManager, sendData data: Data) + + func sendSDP(_ sdp: RTCSessionDescription) + func sendICECandidate(_ candidate: RTCIceCandidate) } /// See https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription for more information. @@ -78,7 +79,7 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { } // MARK: Initialization - internal override init() { + public override init() { super.init() let mediaStreamTrackIDS = ["ARDAMS"] peerConnection.add(audioTrack, streamIds: mediaStreamTrackIDS) @@ -97,10 +98,16 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { audioSession.unlockForConfiguration() } - public static let shared = CallManager() + // MARK: General + public func drainICECandidateQueue() { + print("[Calls] Draining ICE candidate queue.") + candidateQueue.forEach { peerConnection.add($0) } + candidateQueue.removeAll() + } // MARK: Call Management public func initiateCall() -> Promise { + print("[Calls] Initiating call.") /* guard let thread = TSContactThread.fetch(for: publicKey, using: transaction) else { return Promise(error: Error.noThread) } */ @@ -117,8 +124,7 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { } } - let message = sdp.serialize()! - self.delegate?.callManager(self, sendData: message) + self.delegate?.sendSDP(sdp) /* let message = CallMessage() @@ -133,6 +139,7 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { } public func acceptCall() -> Promise { + print("[Calls] Accepting call.") /* guard let thread = TSContactThread.fetch(for: publicKey, using: transaction) else { return Promise(error: Error.noThread) } */ @@ -149,8 +156,7 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { } } - let message = sdp.serialize()! - self.delegate?.callManager(self, sendData: message) + self.delegate?.sendSDP(sdp) /* let message = CallMessage() @@ -195,8 +201,7 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) { SNLog("ICE candidate generated.") - let message = candidate.serialize()! - delegate?.callManager(self, sendData: message) + delegate?.sendICECandidate(candidate) } public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) { @@ -207,16 +212,3 @@ public final class CallManager : NSObject, RTCPeerConnectionDelegate { SNLog("Data channel opened.") } } - -// MARK: Utilities - -extension RTCSessionDescription { - - func serialize() -> Data? { - let json = [ - "type": RTCSessionDescription.string(for: self.type), - "sdp": self.sdp - ] - return try? JSONSerialization.data(withJSONObject: json, options: [.prettyPrinted]) - } -} diff --git a/SessionMessagingKit/Calls/RoomInfo.swift b/SessionMessagingKit/Calls/Temp/RoomInfo.swift similarity index 100% rename from SessionMessagingKit/Calls/RoomInfo.swift rename to SessionMessagingKit/Calls/Temp/RoomInfo.swift diff --git a/SessionMessagingKit/Calls/SignalingMessage.swift b/SessionMessagingKit/Calls/Temp/SignalingMessage.swift similarity index 74% rename from SessionMessagingKit/Calls/SignalingMessage.swift rename to SessionMessagingKit/Calls/Temp/SignalingMessage.swift index 85744082b..3ca82215c 100644 --- a/SessionMessagingKit/Calls/SignalingMessage.swift +++ b/SessionMessagingKit/Calls/Temp/SignalingMessage.swift @@ -2,37 +2,36 @@ import Foundation import WebRTC public enum SignalingMessage { - case none case candidate(_ message: RTCIceCandidate) case answer(_ message: RTCSessionDescription) case offer(_ message: RTCSessionDescription) case bye - public static func from(message: String) -> SignalingMessage { - guard let data = message.data(using: String.Encoding.utf8) else { return .none } - guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON else { return .none } + public static func from(message: String) -> SignalingMessage? { + guard let data = message.data(using: String.Encoding.utf8), + let json = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON else { return nil } let messageAsJSON: JSON - if let foo = json["msg"] as? String { - guard let data = foo.data(using: String.Encoding.utf8) else { return .none } - guard let bar = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON else { return .none } - messageAsJSON = bar + if let string = json["msg"] as? String { + guard let data = string.data(using: String.Encoding.utf8), + let json = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON else { return nil } + messageAsJSON = json } else { messageAsJSON = json } - guard let type = messageAsJSON["type"] as? String else { return .none } + guard let type = messageAsJSON["type"] as? String else { return nil } switch type { case "candidate": - guard let candidate = RTCIceCandidate.candidate(from: messageAsJSON) else { return .none } + guard let candidate = RTCIceCandidate.candidate(from: messageAsJSON) else { return nil } return .candidate(candidate) case "answer": - guard let sdp = messageAsJSON["sdp"] as? String else { return .none } + guard let sdp = messageAsJSON["sdp"] as? String else { return nil } return .answer(RTCSessionDescription(type: .answer, sdp: sdp)) case "offer": - guard let sdp = messageAsJSON["sdp"] as? String else { return .none } + guard let sdp = messageAsJSON["sdp"] as? String else { return nil } return .offer(RTCSessionDescription(type: .offer, sdp: sdp)) case "bye": return .bye - default: return .none + default: return nil } } } @@ -46,7 +45,7 @@ extension RTCIceCandidate { "id": sdpMid, "candidate": sdp ] - return try? JSONSerialization.data(withJSONObject: json, options: [.prettyPrinted]) + return try? JSONSerialization.data(withJSONObject: json, options: [ .prettyPrinted ]) } static func candidate(from json: JSON) -> RTCIceCandidate? { diff --git a/SessionMessagingKit/Calls/TestCallConfig.swift b/SessionMessagingKit/Calls/Temp/TestCallConfig.swift similarity index 100% rename from SessionMessagingKit/Calls/TestCallConfig.swift rename to SessionMessagingKit/Calls/Temp/TestCallConfig.swift diff --git a/SessionMessagingKit/Calls/TestCallServer.swift b/SessionMessagingKit/Calls/Temp/TestCallServer.swift similarity index 100% rename from SessionMessagingKit/Calls/TestCallServer.swift rename to SessionMessagingKit/Calls/Temp/TestCallServer.swift diff --git a/SessionMessagingKit/Calls/WebSocket.swift b/SessionMessagingKit/Calls/Temp/WebSocket.swift similarity index 90% rename from SessionMessagingKit/Calls/WebSocket.swift rename to SessionMessagingKit/Calls/Temp/WebSocket.swift index e3139dff3..44009db99 100644 --- a/SessionMessagingKit/Calls/WebSocket.swift +++ b/SessionMessagingKit/Calls/Temp/WebSocket.swift @@ -18,7 +18,7 @@ public final class WebSocket : NSObject, SRWebSocketDelegate { socket.delegate = self } - public func connect(url: URL) { + public func connect() { socket.open() } @@ -26,6 +26,10 @@ public final class WebSocket : NSObject, SRWebSocketDelegate { socket.send(data) } + public func webSocketDidOpen(_ webSocket: SRWebSocket!) { + delegate?.webSocketDidConnect(self) + } + public func webSocket(_ webSocket: SRWebSocket!, didReceiveMessage message: Any!) { guard let message = message as? String else { return } delegate?.webSocket(self, didReceive: message)