Batch send ICE candidates
This commit is contained in:
parent
525eb40d8d
commit
1ad42547b2
|
@ -37,6 +37,7 @@ final class CallVCV2 : UIViewController, WebRTCWrapperDelegate {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .black
|
||||
WebRTCWrapper.current = webRTCWrapper
|
||||
setUpViewHierarchy()
|
||||
cameraManager.prepare()
|
||||
|
|
|
@ -7,7 +7,7 @@ extension AppDelegate {
|
|||
func setUpCallHandling() {
|
||||
MessageReceiver.handleOfferCallMessage = { message in
|
||||
DispatchQueue.main.async {
|
||||
let sdp = RTCSessionDescription(type: .offer, sdp: message.sdp!)
|
||||
let sdp = RTCSessionDescription(type: .offer, sdp: message.sdps![0])
|
||||
guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // TODO: Handle more gracefully
|
||||
let alert = UIAlertController(title: "Incoming Call", message: nil, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "Accept", style: .default, handler: { _ in
|
||||
|
|
|
@ -2,9 +2,9 @@ import WebRTC
|
|||
|
||||
extension WebRTCWrapper {
|
||||
|
||||
public func handleICECandidate(_ candidate: RTCIceCandidate) {
|
||||
public func handleICECandidates(_ candidate: [RTCIceCandidate]) {
|
||||
print("[Calls] Received ICE candidate message.")
|
||||
peerConnection.add(candidate)
|
||||
candidate.forEach { peerConnection.add($0) }
|
||||
}
|
||||
|
||||
public func handleRemoteSDP(_ sdp: RTCSessionDescription, from sessionID: String) {
|
||||
|
@ -15,7 +15,6 @@ extension WebRTCWrapper {
|
|||
} else {
|
||||
guard let self = self,
|
||||
sdp.type == .offer, self.peerConnection.localDescription == nil else { return }
|
||||
// Automatically answer the call
|
||||
Storage.write { transaction in
|
||||
self.sendAnswer(to: sessionID, using: transaction).retainUntilComplete()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ public protocol WebRTCWrapperDelegate : AnyObject {
|
|||
public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
||||
public weak var delegate: WebRTCWrapperDelegate?
|
||||
private let contactSessionID: String
|
||||
private var queuedICECandidates: [RTCIceCandidate] = []
|
||||
private var iceCandidateSendTimer: Timer?
|
||||
|
||||
private let defaultICEServers = [
|
||||
"stun:stun.l.google.com:19302",
|
||||
|
@ -101,7 +103,7 @@ public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
|||
audioSession.unlockForConfiguration()
|
||||
}
|
||||
|
||||
// MARK: Call Management
|
||||
// MARK: Signaling
|
||||
public func sendOffer(to sessionID: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise<Void> {
|
||||
print("[Calls] Initiating call.")
|
||||
guard let thread = TSContactThread.fetch(for: sessionID, using: transaction) else { return Promise(error: Error.noThread) }
|
||||
|
@ -120,7 +122,7 @@ public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
|||
DispatchQueue.main.async {
|
||||
let message = CallMessage()
|
||||
message.kind = .offer
|
||||
message.sdp = sdp.sdp
|
||||
message.sdps = [ sdp.sdp ]
|
||||
MessageSender.send(message, in: thread, using: transaction)
|
||||
seal.fulfill(())
|
||||
}
|
||||
|
@ -147,7 +149,7 @@ public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
|||
DispatchQueue.main.async {
|
||||
let message = CallMessage()
|
||||
message.kind = .answer
|
||||
message.sdp = sdp.sdp
|
||||
message.sdps = [ sdp.sdp ]
|
||||
MessageSender.send(message, in: thread, using: transaction)
|
||||
seal.fulfill(())
|
||||
}
|
||||
|
@ -156,6 +158,29 @@ public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
|||
return promise
|
||||
}
|
||||
|
||||
private func queueICECandidateForSending(_ candidate: RTCIceCandidate) {
|
||||
queuedICECandidates.append(candidate)
|
||||
iceCandidateSendTimer?.invalidate()
|
||||
iceCandidateSendTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
|
||||
self.sendICECandidates()
|
||||
}
|
||||
}
|
||||
|
||||
private func sendICECandidates() {
|
||||
Storage.write { transaction in
|
||||
let candidates = self.queuedICECandidates
|
||||
guard let thread = TSContactThread.fetch(for: self.contactSessionID, using: transaction) else { return }
|
||||
let message = CallMessage()
|
||||
let sdps = candidates.map { $0.sdp }
|
||||
let sdpMLineIndexes = candidates.map { UInt32($0.sdpMLineIndex) }
|
||||
let sdpMids = candidates.map { $0.sdpMid! }
|
||||
message.kind = .iceCandidates(sdpMLineIndexes: sdpMLineIndexes, sdpMids: sdpMids)
|
||||
message.sdps = sdps
|
||||
self.queuedICECandidates.removeAll()
|
||||
MessageSender.send(message, in: thread, using: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
public func dropConnection() {
|
||||
peerConnection.close()
|
||||
}
|
||||
|
@ -187,13 +212,7 @@ public final class WebRTCWrapper : NSObject, RTCPeerConnectionDelegate {
|
|||
|
||||
public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) {
|
||||
print("[Calls] ICE candidate generated.")
|
||||
Storage.write { transaction in
|
||||
guard let thread = TSContactThread.fetch(for: self.contactSessionID, using: transaction) else { return }
|
||||
let message = CallMessage()
|
||||
message.kind = .iceCandidate(sdpMLineIndex: UInt32(candidate.sdpMLineIndex), sdpMid: candidate.sdpMid!)
|
||||
message.sdp = candidate.sdp
|
||||
MessageSender.send(message, in: thread, using: transaction)
|
||||
}
|
||||
queueICECandidateForSending(candidate)
|
||||
}
|
||||
|
||||
public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) {
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
import WebRTC
|
||||
|
||||
// NOTE: Multiple ICE candidates may be batched together for performance
|
||||
|
||||
/// See https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription for more information.
|
||||
@objc(SNCallMessage)
|
||||
public final class CallMessage : ControlMessage {
|
||||
public var kind: Kind?
|
||||
/// See https://developer.mozilla.org/en-US/docs/Glossary/SDP for more information.
|
||||
public var sdp: String?
|
||||
public var sdps: [String]?
|
||||
|
||||
// MARK: Kind
|
||||
public enum Kind : Codable, CustomStringConvertible {
|
||||
case offer
|
||||
case answer
|
||||
case provisionalAnswer
|
||||
case iceCandidate(sdpMLineIndex: UInt32, sdpMid: String)
|
||||
case iceCandidates(sdpMLineIndexes: [UInt32], sdpMids: [String])
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .offer: return "offer"
|
||||
case .answer: return "answer"
|
||||
case .provisionalAnswer: return "provisionalAnswer"
|
||||
case .iceCandidate(_, _): return "iceCandidate"
|
||||
case .iceCandidates(_, _): return "iceCandidates"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,16 +29,17 @@ public final class CallMessage : ControlMessage {
|
|||
// MARK: Initialization
|
||||
public override init() { super.init() }
|
||||
|
||||
internal init(kind: Kind, sdp: String) {
|
||||
internal init(kind: Kind, sdps: [String]) {
|
||||
super.init()
|
||||
self.kind = kind
|
||||
self.sdp = sdp
|
||||
self.sdps = sdps
|
||||
}
|
||||
|
||||
// MARK: Validation
|
||||
public override var isValid: Bool {
|
||||
guard super.isValid else { return false }
|
||||
return kind != nil && sdp != nil
|
||||
guard let sdps = sdps, !sdps.isEmpty else { return false }
|
||||
return kind != nil
|
||||
}
|
||||
|
||||
// MARK: Coding
|
||||
|
@ -47,13 +50,13 @@ public final class CallMessage : ControlMessage {
|
|||
case "offer": kind = .offer
|
||||
case "answer": kind = .answer
|
||||
case "provisionalAnswer": kind = .provisionalAnswer
|
||||
case "iceCandidate":
|
||||
guard let sdpMLineIndex = coder.decodeObject(forKey: "sdpMLineIndex") as? UInt32,
|
||||
let sdpMid = coder.decodeObject(forKey: "sdpMid") as? String else { return nil }
|
||||
kind = .iceCandidate(sdpMLineIndex: sdpMLineIndex, sdpMid: sdpMid)
|
||||
case "iceCandidates":
|
||||
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)
|
||||
default: preconditionFailure()
|
||||
}
|
||||
if let sdp = coder.decodeObject(forKey: "sdp") as! String? { self.sdp = sdp }
|
||||
if let sdps = coder.decodeObject(forKey: "sdps") as! [String]? { self.sdps = sdps }
|
||||
}
|
||||
|
||||
public override func encode(with coder: NSCoder) {
|
||||
|
@ -62,13 +65,13 @@ public final class CallMessage : ControlMessage {
|
|||
case .offer: coder.encode("offer", forKey: "kind")
|
||||
case .answer: coder.encode("answer", forKey: "kind")
|
||||
case .provisionalAnswer: coder.encode("provisionalAnswer", forKey: "kind")
|
||||
case let .iceCandidate(sdpMLineIndex, sdpMid):
|
||||
coder.encode("iceCandidate", forKey: "kind")
|
||||
coder.encode(sdpMLineIndex, forKey: "sdpMLineIndex")
|
||||
coder.encode(sdpMid, forKey: "sdpMid")
|
||||
case let .iceCandidates(sdpMLineIndexes, sdpMids):
|
||||
coder.encode("iceCandidates", forKey: "kind")
|
||||
coder.encode(sdpMLineIndexes, forKey: "sdpMLineIndexes")
|
||||
coder.encode(sdpMids, forKey: "sdpMids")
|
||||
default: preconditionFailure()
|
||||
}
|
||||
coder.encode(sdp, forKey: "sdp")
|
||||
coder.encode(sdps, forKey: "sdps")
|
||||
}
|
||||
|
||||
// MARK: Proto Conversion
|
||||
|
@ -79,17 +82,17 @@ public final class CallMessage : ControlMessage {
|
|||
case .offer: kind = .offer
|
||||
case .answer: kind = .answer
|
||||
case .provisionalAnswer: kind = .provisionalAnswer
|
||||
case .iceCandidate:
|
||||
let sdpMLineIndex = callMessageProto.sdpMlineIndex
|
||||
guard let sdpMid = callMessageProto.sdpMid else { return nil }
|
||||
kind = .iceCandidate(sdpMLineIndex: sdpMLineIndex, sdpMid: sdpMid)
|
||||
case .iceCandidates:
|
||||
let sdpMLineIndexes = callMessageProto.sdpMlineIndexes
|
||||
let sdpMids = callMessageProto.sdpMids
|
||||
kind = .iceCandidates(sdpMLineIndexes: sdpMLineIndexes, sdpMids: sdpMids)
|
||||
}
|
||||
let sdp = callMessageProto.sdp
|
||||
return CallMessage(kind: kind, sdp: sdp)
|
||||
let sdps = callMessageProto.sdps
|
||||
return CallMessage(kind: kind, sdps: sdps)
|
||||
}
|
||||
|
||||
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {
|
||||
guard let kind = kind, let sdp = sdp else {
|
||||
guard let kind = kind, let sdps = sdps, !sdps.isEmpty else {
|
||||
SNLog("Couldn't construct call message proto from: \(self).")
|
||||
return nil
|
||||
}
|
||||
|
@ -101,12 +104,13 @@ public final class CallMessage : ControlMessage {
|
|||
case .offer: type = .offer
|
||||
case .answer: type = .answer
|
||||
case .provisionalAnswer: type = .provisionalAnswer
|
||||
case .iceCandidate(_, _): type = .iceCandidate
|
||||
case .iceCandidates(_, _): type = .iceCandidates
|
||||
}
|
||||
let callMessageProto = SNProtoCallMessage.builder(type: type, sdp: sdp)
|
||||
if case let .iceCandidate(sdpMLineIndex, sdpMid) = kind {
|
||||
callMessageProto.setSdpMlineIndex(sdpMLineIndex)
|
||||
callMessageProto.setSdpMid(sdpMid)
|
||||
let callMessageProto = SNProtoCallMessage.builder(type: type)
|
||||
callMessageProto.setSdps(sdps)
|
||||
if case let .iceCandidates(sdpMLineIndexes, sdpMids) = kind {
|
||||
callMessageProto.setSdpMlineIndexes(sdpMLineIndexes)
|
||||
callMessageProto.setSdpMids(sdpMids)
|
||||
}
|
||||
let contentProto = SNProtoContent.builder()
|
||||
do {
|
||||
|
@ -123,7 +127,7 @@ public final class CallMessage : ControlMessage {
|
|||
"""
|
||||
CallMessage(
|
||||
kind: \(kind?.description ?? "null"),
|
||||
sdp: \(sdp ?? "null")
|
||||
sdps: \(sdps?.description ?? "null")
|
||||
)
|
||||
"""
|
||||
}
|
||||
|
|
|
@ -656,7 +656,7 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
case offer = 1
|
||||
case answer = 2
|
||||
case provisionalAnswer = 3
|
||||
case iceCandidate = 4
|
||||
case iceCandidates = 4
|
||||
}
|
||||
|
||||
private class func SNProtoCallMessageTypeWrap(_ value: SessionProtos_CallMessage.TypeEnum) -> SNProtoCallMessageType {
|
||||
|
@ -664,7 +664,7 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
case .offer: return .offer
|
||||
case .answer: return .answer
|
||||
case .provisionalAnswer: return .provisionalAnswer
|
||||
case .iceCandidate: return .iceCandidate
|
||||
case .iceCandidates: return .iceCandidates
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -673,25 +673,22 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
case .offer: return .offer
|
||||
case .answer: return .answer
|
||||
case .provisionalAnswer: return .provisionalAnswer
|
||||
case .iceCandidate: return .iceCandidate
|
||||
case .iceCandidates: return .iceCandidates
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SNProtoCallMessageBuilder
|
||||
|
||||
@objc public class func builder(type: SNProtoCallMessageType, sdp: String) -> SNProtoCallMessageBuilder {
|
||||
return SNProtoCallMessageBuilder(type: type, sdp: sdp)
|
||||
@objc public class func builder(type: SNProtoCallMessageType) -> SNProtoCallMessageBuilder {
|
||||
return SNProtoCallMessageBuilder(type: type)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SNProtoCallMessageBuilder {
|
||||
let builder = SNProtoCallMessageBuilder(type: type, sdp: sdp)
|
||||
if hasSdpMlineIndex {
|
||||
builder.setSdpMlineIndex(sdpMlineIndex)
|
||||
}
|
||||
if let _value = sdpMid {
|
||||
builder.setSdpMid(_value)
|
||||
}
|
||||
let builder = SNProtoCallMessageBuilder(type: type)
|
||||
builder.setSdps(sdps)
|
||||
builder.setSdpMlineIndexes(sdpMlineIndexes)
|
||||
builder.setSdpMids(sdpMids)
|
||||
return builder
|
||||
}
|
||||
|
||||
|
@ -701,27 +698,44 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(type: SNProtoCallMessageType, sdp: String) {
|
||||
@objc fileprivate init(type: SNProtoCallMessageType) {
|
||||
super.init()
|
||||
|
||||
setType(type)
|
||||
setSdp(sdp)
|
||||
}
|
||||
|
||||
@objc public func setType(_ valueParam: SNProtoCallMessageType) {
|
||||
proto.type = SNProtoCallMessageTypeUnwrap(valueParam)
|
||||
}
|
||||
|
||||
@objc public func setSdp(_ valueParam: String) {
|
||||
proto.sdp = valueParam
|
||||
@objc public func addSdps(_ valueParam: String) {
|
||||
var items = proto.sdps
|
||||
items.append(valueParam)
|
||||
proto.sdps = items
|
||||
}
|
||||
|
||||
@objc public func setSdpMlineIndex(_ valueParam: UInt32) {
|
||||
proto.sdpMlineIndex = valueParam
|
||||
@objc public func setSdps(_ wrappedItems: [String]) {
|
||||
proto.sdps = wrappedItems
|
||||
}
|
||||
|
||||
@objc public func setSdpMid(_ valueParam: String) {
|
||||
proto.sdpMid = valueParam
|
||||
@objc public func addSdpMlineIndexes(_ valueParam: UInt32) {
|
||||
var items = proto.sdpMlineIndexes
|
||||
items.append(valueParam)
|
||||
proto.sdpMlineIndexes = items
|
||||
}
|
||||
|
||||
@objc public func setSdpMlineIndexes(_ wrappedItems: [UInt32]) {
|
||||
proto.sdpMlineIndexes = wrappedItems
|
||||
}
|
||||
|
||||
@objc public func addSdpMids(_ valueParam: String) {
|
||||
var items = proto.sdpMids
|
||||
items.append(valueParam)
|
||||
proto.sdpMids = items
|
||||
}
|
||||
|
||||
@objc public func setSdpMids(_ wrappedItems: [String]) {
|
||||
proto.sdpMids = wrappedItems
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SNProtoCallMessage {
|
||||
|
@ -737,31 +751,22 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
|
||||
@objc public let type: SNProtoCallMessageType
|
||||
|
||||
@objc public let sdp: String
|
||||
|
||||
@objc public var sdpMlineIndex: UInt32 {
|
||||
return proto.sdpMlineIndex
|
||||
}
|
||||
@objc public var hasSdpMlineIndex: Bool {
|
||||
return proto.hasSdpMlineIndex
|
||||
@objc public var sdps: [String] {
|
||||
return proto.sdps
|
||||
}
|
||||
|
||||
@objc public var sdpMid: String? {
|
||||
guard proto.hasSdpMid else {
|
||||
return nil
|
||||
}
|
||||
return proto.sdpMid
|
||||
@objc public var sdpMlineIndexes: [UInt32] {
|
||||
return proto.sdpMlineIndexes
|
||||
}
|
||||
@objc public var hasSdpMid: Bool {
|
||||
return proto.hasSdpMid
|
||||
|
||||
@objc public var sdpMids: [String] {
|
||||
return proto.sdpMids
|
||||
}
|
||||
|
||||
private init(proto: SessionProtos_CallMessage,
|
||||
type: SNProtoCallMessageType,
|
||||
sdp: String) {
|
||||
type: SNProtoCallMessageType) {
|
||||
self.proto = proto
|
||||
self.type = type
|
||||
self.sdp = sdp
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -780,18 +785,12 @@ extension SNProtoContent.SNProtoContentBuilder {
|
|||
}
|
||||
let type = SNProtoCallMessageTypeWrap(proto.type)
|
||||
|
||||
guard proto.hasSdp else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: sdp")
|
||||
}
|
||||
let sdp = proto.sdp
|
||||
|
||||
// MARK: - Begin Validation Logic for SNProtoCallMessage -
|
||||
|
||||
// MARK: - End Validation Logic for SNProtoCallMessage -
|
||||
|
||||
let result = SNProtoCallMessage(proto: proto,
|
||||
type: type,
|
||||
sdp: sdp)
|
||||
type: type)
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -319,33 +319,11 @@ struct SessionProtos_CallMessage {
|
|||
/// Clears the value of `type`. Subsequent reads from it will return its default value.
|
||||
mutating func clearType() {self._type = nil}
|
||||
|
||||
/// @required
|
||||
var sdp: String {
|
||||
get {return _sdp ?? String()}
|
||||
set {_sdp = newValue}
|
||||
}
|
||||
/// Returns true if `sdp` has been explicitly set.
|
||||
var hasSdp: Bool {return self._sdp != nil}
|
||||
/// Clears the value of `sdp`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSdp() {self._sdp = nil}
|
||||
var sdps: [String] = []
|
||||
|
||||
var sdpMlineIndex: UInt32 {
|
||||
get {return _sdpMlineIndex ?? 0}
|
||||
set {_sdpMlineIndex = newValue}
|
||||
}
|
||||
/// Returns true if `sdpMlineIndex` has been explicitly set.
|
||||
var hasSdpMlineIndex: Bool {return self._sdpMlineIndex != nil}
|
||||
/// Clears the value of `sdpMlineIndex`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSdpMlineIndex() {self._sdpMlineIndex = nil}
|
||||
var sdpMlineIndexes: [UInt32] = []
|
||||
|
||||
var sdpMid: String {
|
||||
get {return _sdpMid ?? String()}
|
||||
set {_sdpMid = newValue}
|
||||
}
|
||||
/// Returns true if `sdpMid` has been explicitly set.
|
||||
var hasSdpMid: Bool {return self._sdpMid != nil}
|
||||
/// Clears the value of `sdpMid`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSdpMid() {self._sdpMid = nil}
|
||||
var sdpMids: [String] = []
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
|
@ -354,7 +332,7 @@ struct SessionProtos_CallMessage {
|
|||
case offer // = 1
|
||||
case answer // = 2
|
||||
case provisionalAnswer // = 3
|
||||
case iceCandidate // = 4
|
||||
case iceCandidates // = 4
|
||||
|
||||
init() {
|
||||
self = .offer
|
||||
|
@ -365,7 +343,7 @@ struct SessionProtos_CallMessage {
|
|||
case 1: self = .offer
|
||||
case 2: self = .answer
|
||||
case 3: self = .provisionalAnswer
|
||||
case 4: self = .iceCandidate
|
||||
case 4: self = .iceCandidates
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +353,7 @@ struct SessionProtos_CallMessage {
|
|||
case .offer: return 1
|
||||
case .answer: return 2
|
||||
case .provisionalAnswer: return 3
|
||||
case .iceCandidate: return 4
|
||||
case .iceCandidates: return 4
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,9 +362,6 @@ struct SessionProtos_CallMessage {
|
|||
init() {}
|
||||
|
||||
fileprivate var _type: SessionProtos_CallMessage.TypeEnum? = nil
|
||||
fileprivate var _sdp: String? = nil
|
||||
fileprivate var _sdpMlineIndex: UInt32? = nil
|
||||
fileprivate var _sdpMid: String? = nil
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
@ -1817,14 +1792,13 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
static let protoMessageName: String = _protobuf_package + ".CallMessage"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "type"),
|
||||
2: .same(proto: "sdp"),
|
||||
3: .same(proto: "sdpMLineIndex"),
|
||||
4: .same(proto: "sdpMid"),
|
||||
2: .same(proto: "sdps"),
|
||||
3: .same(proto: "sdpMLineIndexes"),
|
||||
4: .same(proto: "sdpMids"),
|
||||
]
|
||||
|
||||
public var isInitialized: Bool {
|
||||
if self._type == nil {return false}
|
||||
if self._sdp == nil {return false}
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1835,9 +1809,9 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularEnumField(value: &self._type) }()
|
||||
case 2: try { try decoder.decodeSingularStringField(value: &self._sdp) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self._sdpMlineIndex) }()
|
||||
case 4: try { try decoder.decodeSingularStringField(value: &self._sdpMid) }()
|
||||
case 2: try { try decoder.decodeRepeatedStringField(value: &self.sdps) }()
|
||||
case 3: try { try decoder.decodeRepeatedUInt32Field(value: &self.sdpMlineIndexes) }()
|
||||
case 4: try { try decoder.decodeRepeatedStringField(value: &self.sdpMids) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -1847,23 +1821,23 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
if let v = self._type {
|
||||
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
|
||||
}
|
||||
if let v = self._sdp {
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 2)
|
||||
if !self.sdps.isEmpty {
|
||||
try visitor.visitRepeatedStringField(value: self.sdps, fieldNumber: 2)
|
||||
}
|
||||
if let v = self._sdpMlineIndex {
|
||||
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 3)
|
||||
if !self.sdpMlineIndexes.isEmpty {
|
||||
try visitor.visitRepeatedUInt32Field(value: self.sdpMlineIndexes, fieldNumber: 3)
|
||||
}
|
||||
if let v = self._sdpMid {
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 4)
|
||||
if !self.sdpMids.isEmpty {
|
||||
try visitor.visitRepeatedStringField(value: self.sdpMids, fieldNumber: 4)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SessionProtos_CallMessage, rhs: SessionProtos_CallMessage) -> Bool {
|
||||
if lhs._type != rhs._type {return false}
|
||||
if lhs._sdp != rhs._sdp {return false}
|
||||
if lhs._sdpMlineIndex != rhs._sdpMlineIndex {return false}
|
||||
if lhs._sdpMid != rhs._sdpMid {return false}
|
||||
if lhs.sdps != rhs.sdps {return false}
|
||||
if lhs.sdpMlineIndexes != rhs.sdpMlineIndexes {return false}
|
||||
if lhs.sdpMids != rhs.sdpMids {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
@ -1874,7 +1848,7 @@ extension SessionProtos_CallMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding
|
|||
1: .same(proto: "OFFER"),
|
||||
2: .same(proto: "ANSWER"),
|
||||
3: .same(proto: "PROVISIONAL_ANSWER"),
|
||||
4: .same(proto: "ICE_CANDIDATE"),
|
||||
4: .same(proto: "ICE_CANDIDATES"),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -57,15 +57,16 @@ message CallMessage {
|
|||
OFFER = 1;
|
||||
ANSWER = 2;
|
||||
PROVISIONAL_ANSWER = 3;
|
||||
ICE_CANDIDATE = 4;
|
||||
ICE_CANDIDATES = 4;
|
||||
}
|
||||
|
||||
// Multiple ICE candidates may be batched together for performance
|
||||
|
||||
// @required
|
||||
required Type type = 1;
|
||||
// @required
|
||||
required string sdp = 2;
|
||||
optional uint32 sdpMLineIndex = 3;
|
||||
optional string sdpMid = 4;
|
||||
required Type type = 1;
|
||||
repeated string sdps = 2;
|
||||
repeated uint32 sdpMLineIndexes = 3;
|
||||
repeated string sdpMids = 4;
|
||||
}
|
||||
|
||||
message KeyPair {
|
||||
|
|
|
@ -269,12 +269,20 @@ extension MessageReceiver {
|
|||
handleOfferCallMessage?(message)
|
||||
case .answer:
|
||||
print("[Calls] Received answer message.")
|
||||
let sdp = RTCSessionDescription(type: .answer, sdp: message.sdp!)
|
||||
let sdp = RTCSessionDescription(type: .answer, sdp: message.sdps![0])
|
||||
webRTCWrapper.handleRemoteSDP(sdp, from: message.sender!)
|
||||
case .provisionalAnswer: break // TODO: Implement
|
||||
case let .iceCandidate(sdpMLineIndex, sdpMid):
|
||||
let candidate = RTCIceCandidate(sdp: message.sdp!, sdpMLineIndex: Int32(sdpMLineIndex), sdpMid: sdpMid)
|
||||
webRTCWrapper.handleICECandidate(candidate)
|
||||
case let .iceCandidates(sdpMLineIndexes, sdpMids):
|
||||
var candidates: [RTCIceCandidate] = []
|
||||
let sdps = message.sdps!
|
||||
for i in 0..<sdps.count {
|
||||
let sdp = sdps[i]
|
||||
let sdpMLineIndex = sdpMLineIndexes[i]
|
||||
let sdpMid = sdpMids[i]
|
||||
let candidate = RTCIceCandidate(sdp: sdp, sdpMLineIndex: Int32(sdpMLineIndex), sdpMid: sdpMid)
|
||||
candidates.append(candidate)
|
||||
}
|
||||
webRTCWrapper.handleICECandidates(candidates)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ public enum HTTP {
|
|||
}
|
||||
}
|
||||
|
||||
public static func execute(_ verb: Verb, _ url: String, body: Data?, headers: [String:String] = [:], timeout: TimeInterval = HTTP.timeout, useSeedNodeURLSession: Bool = false) -> Promise<JSON> {
|
||||
public static func execute(_ verb: Verb, _ url: String, body: Data?, timeout: TimeInterval = HTTP.timeout, useSeedNodeURLSession: Bool = false) -> Promise<JSON> {
|
||||
var request = URLRequest(url: URL(string: url)!)
|
||||
request.httpMethod = verb.rawValue
|
||||
request.httpBody = body
|
||||
|
@ -117,9 +117,6 @@ public enum HTTP {
|
|||
request.allHTTPHeaderFields?.removeValue(forKey: "User-Agent")
|
||||
request.setValue("WhatsApp", forHTTPHeaderField: "User-Agent") // Set a fake value
|
||||
request.setValue("en-us", forHTTPHeaderField: "Accept-Language") // Set a fake value
|
||||
headers.forEach { (key, value) in
|
||||
request.setValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
let (promise, seal) = Promise<JSON>.pending()
|
||||
let urlSession = useSeedNodeURLSession ? seedNodeURLSession : snodeURLSession
|
||||
let task = urlSession.dataTask(with: request) { data, response, error in
|
||||
|
|
Loading…
Reference in New Issue