update call protobuf

pull/560/head
ryanzhao 3 years ago
parent 3b545ca618
commit 219440f444

@ -165,7 +165,7 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
init(for sessionID: String, mode: Mode) {
self.sessionID = sessionID
self.mode = mode
self.webRTCSession = WebRTCSession.current ?? WebRTCSession(for: sessionID)
self.webRTCSession = WebRTCSession.current ?? WebRTCSession(for: sessionID, with: UUID().uuidString)
super.init(nibName: nil, bundle: nil)
self.webRTCSession.delegate = self
}
@ -187,7 +187,9 @@ final class CallVC : UIViewController, WebRTCSessionDelegate {
if case .offer = mode {
callInfoLabel.text = "Ringing..."
Storage.write { transaction in
self.webRTCSession.sendOffer(to: self.sessionID, using: transaction).retainUntilComplete()
self.webRTCSession.sendPreOffer(to: self.sessionID, using: transaction).done {
self.webRTCSession.sendOffer(to: self.sessionID, using: transaction).retainUntilComplete()
}
}
answerButton.isHidden = true
}

@ -11,6 +11,7 @@ public protocol WebRTCSessionDelegate : AnyObject {
public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
public weak var delegate: WebRTCSessionDelegate?
private let contactSessionID: String
private let uuid: String
private var queuedICECandidates: [RTCIceCandidate] = []
private var iceCandidateSendTimer: Timer?
@ -88,8 +89,9 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
// MARK: Initialization
public static var current: WebRTCSession?
public init(for contactSessionID: String) {
public init(for contactSessionID: String, with uuid: String) {
self.contactSessionID = contactSessionID
self.uuid = uuid
super.init()
let mediaStreamTrackIDS = ["ARDAMS"]
createDataChannel()
@ -100,6 +102,24 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
}
// MARK: Signaling
public func sendPreOffer(to sessionID: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise<Void> {
print("[Calls] Sending pre-offer message.")
guard let thread = TSContactThread.fetch(for: sessionID, using: transaction) else { return Promise(error: Error.noThread) }
let (promise, seal) = Promise<Void>.pending()
DispatchQueue.main.async {
let message = CallMessage()
message.uuid = self.uuid
message.kind = .preOffer
MessageSender.sendNonDurably(message, in: thread, using: transaction).done2 {
print("[Calls] Pre-offer message has been sent.")
seal.fulfill(())
}.catch2 { error in
seal.reject(error)
}
}
return promise
}
public func sendOffer(to sessionID: String, using transaction: YapDatabaseReadWriteTransaction) -> Promise<Void> {
print("[Calls] Sending offer message.")
guard let thread = TSContactThread.fetch(for: sessionID, using: transaction) else { return Promise(error: Error.noThread) }
@ -117,6 +137,7 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
}
DispatchQueue.main.async {
let message = CallMessage()
message.uuid = self.uuid
message.kind = .offer
message.sdps = [ sdp.sdp ]
let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread)

@ -3,6 +3,7 @@ import WebRTC
/// See https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription for more information.
@objc(SNCallMessage)
public final class CallMessage : ControlMessage {
public var uuid: String?
public var kind: Kind?
/// See https://developer.mozilla.org/en-US/docs/Glossary/SDP for more information.
public var sdps: [String]?
@ -13,6 +14,7 @@ public final class CallMessage : ControlMessage {
// MARK: Kind
public enum Kind : Codable, CustomStringConvertible {
case preOffer
case offer
case answer
case provisionalAnswer
@ -21,6 +23,7 @@ public final class CallMessage : ControlMessage {
public var description: String {
switch self {
case .preOffer: return "preOffer"
case .offer: return "offer"
case .answer: return "answer"
case .provisionalAnswer: return "provisionalAnswer"
@ -33,8 +36,9 @@ public final class CallMessage : ControlMessage {
// MARK: Initialization
public override init() { super.init() }
internal init(kind: Kind, sdps: [String]) {
internal init(uuid: String, kind: Kind, sdps: [String]) {
super.init()
self.uuid = uuid
self.kind = kind
self.sdps = sdps
}
@ -42,7 +46,7 @@ public final class CallMessage : ControlMessage {
// MARK: Validation
public override var isValid: Bool {
guard super.isValid else { return false }
return kind != nil
return kind != nil && uuid != nil
}
// MARK: Coding
@ -50,6 +54,7 @@ public final class CallMessage : ControlMessage {
super.init(coder: coder)
guard let rawKind = coder.decodeObject(forKey: "kind") as! String? else { return nil }
switch rawKind {
case "preOffer": kind = .preOffer
case "offer": kind = .offer
case "answer": kind = .answer
case "provisionalAnswer": kind = .provisionalAnswer
@ -61,11 +66,13 @@ public final class CallMessage : ControlMessage {
default: preconditionFailure()
}
if let sdps = coder.decodeObject(forKey: "sdps") as! [String]? { self.sdps = sdps }
if let uuid = coder.decodeObject(forKey: "uuid") as! String? { self.uuid = uuid }
}
public override func encode(with coder: NSCoder) {
super.encode(with: coder)
switch kind {
case .preOffer: coder.encode("preOffer", forKey: "kind")
case .offer: coder.encode("offer", forKey: "kind")
case .answer: coder.encode("answer", forKey: "kind")
case .provisionalAnswer: coder.encode("provisionalAnswer", forKey: "kind")
@ -77,6 +84,7 @@ public final class CallMessage : ControlMessage {
default: preconditionFailure()
}
coder.encode(sdps, forKey: "sdps")
coder.encode(uuid, forKey: "uuid")
}
// MARK: Proto Conversion
@ -84,6 +92,7 @@ public final class CallMessage : ControlMessage {
guard let callMessageProto = proto.callMessage else { return nil }
let kind: Kind
switch callMessageProto.type {
case .preOffer: kind = .preOffer
case .offer: kind = .offer
case .answer: kind = .answer
case .provisionalAnswer: kind = .provisionalAnswer
@ -94,23 +103,25 @@ public final class CallMessage : ControlMessage {
case .endCall: kind = .endCall
}
let sdps = callMessageProto.sdps
return CallMessage(kind: kind, sdps: sdps)
let uuid = callMessageProto.uuid
return CallMessage(uuid: uuid, kind: kind, sdps: sdps)
}
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {
guard let kind = kind else {
guard let kind = kind, let uuid = uuid else {
SNLog("Couldn't construct call message proto from: \(self).")
return nil
}
let type: SNProtoCallMessage.SNProtoCallMessageType
switch kind {
case .preOffer: type = .preOffer
case .offer: type = .offer
case .answer: type = .answer
case .provisionalAnswer: type = .provisionalAnswer
case .iceCandidates(_, _): type = .iceCandidates
case .endCall: type = .endCall
}
let callMessageProto = SNProtoCallMessage.builder(type: type)
let callMessageProto = SNProtoCallMessage.builder(type: type, uuid: uuid)
if let sdps = sdps, !sdps.isEmpty {
callMessageProto.setSdps(sdps)
}
@ -132,6 +143,7 @@ public final class CallMessage : ControlMessage {
public override var description: String {
"""
CallMessage(
uuid: \(uuid ?? "null"),
kind: \(kind?.description ?? "null"),
sdps: \(sdps?.description ?? "null")
)

@ -658,6 +658,7 @@ extension SNProtoContent.SNProtoContentBuilder {
case provisionalAnswer = 3
case iceCandidates = 4
case endCall = 5
case preOffer = 6
}
private class func SNProtoCallMessageTypeWrap(_ value: SessionProtos_CallMessage.TypeEnum) -> SNProtoCallMessageType {
@ -667,6 +668,7 @@ extension SNProtoContent.SNProtoContentBuilder {
case .provisionalAnswer: return .provisionalAnswer
case .iceCandidates: return .iceCandidates
case .endCall: return .endCall
case .preOffer: return .preOffer
}
}
@ -677,18 +679,19 @@ extension SNProtoContent.SNProtoContentBuilder {
case .provisionalAnswer: return .provisionalAnswer
case .iceCandidates: return .iceCandidates
case .endCall: return .endCall
case .preOffer: return .preOffer
}
}
// MARK: - SNProtoCallMessageBuilder
@objc public class func builder(type: SNProtoCallMessageType) -> SNProtoCallMessageBuilder {
return SNProtoCallMessageBuilder(type: type)
@objc public class func builder(type: SNProtoCallMessageType, uuid: String) -> SNProtoCallMessageBuilder {
return SNProtoCallMessageBuilder(type: type, uuid: uuid)
}
// asBuilder() constructs a builder that reflects the proto's contents.
@objc public func asBuilder() -> SNProtoCallMessageBuilder {
let builder = SNProtoCallMessageBuilder(type: type)
let builder = SNProtoCallMessageBuilder(type: type, uuid: uuid)
builder.setSdps(sdps)
builder.setSdpMlineIndexes(sdpMlineIndexes)
builder.setSdpMids(sdpMids)
@ -701,10 +704,11 @@ extension SNProtoContent.SNProtoContentBuilder {
@objc fileprivate override init() {}
@objc fileprivate init(type: SNProtoCallMessageType) {
@objc fileprivate init(type: SNProtoCallMessageType, uuid: String) {
super.init()
setType(type)
setUuid(uuid)
}
@objc public func setType(_ valueParam: SNProtoCallMessageType) {
@ -741,6 +745,10 @@ extension SNProtoContent.SNProtoContentBuilder {
proto.sdpMids = wrappedItems
}
@objc public func setUuid(_ valueParam: String) {
proto.uuid = valueParam
}
@objc public func build() throws -> SNProtoCallMessage {
return try SNProtoCallMessage.parseProto(proto)
}
@ -754,6 +762,8 @@ extension SNProtoContent.SNProtoContentBuilder {
@objc public let type: SNProtoCallMessageType
@objc public let uuid: String
@objc public var sdps: [String] {
return proto.sdps
}
@ -767,9 +777,11 @@ extension SNProtoContent.SNProtoContentBuilder {
}
private init(proto: SessionProtos_CallMessage,
type: SNProtoCallMessageType) {
type: SNProtoCallMessageType,
uuid: String) {
self.proto = proto
self.type = type
self.uuid = uuid
}
@objc
@ -788,12 +800,18 @@ extension SNProtoContent.SNProtoContentBuilder {
}
let type = SNProtoCallMessageTypeWrap(proto.type)
guard proto.hasUuid else {
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: uuid")
}
let uuid = proto.uuid
// MARK: - Begin Validation Logic for SNProtoCallMessage -
// MARK: - End Validation Logic for SNProtoCallMessage -
let result = SNProtoCallMessage(proto: proto,
type: type)
type: type,
uuid: uuid)
return result
}

@ -311,7 +311,7 @@ struct SessionProtos_CallMessage {
/// @required
var type: SessionProtos_CallMessage.TypeEnum {
get {return _type ?? .offer}
get {return _type ?? .preOffer}
set {_type = newValue}
}
/// Returns true if `type` has been explicitly set.
@ -325,10 +325,21 @@ struct SessionProtos_CallMessage {
var sdpMids: [String] = []
/// @required
var uuid: String {
get {return _uuid ?? String()}
set {_uuid = newValue}
}
/// Returns true if `uuid` has been explicitly set.
var hasUuid: Bool {return self._uuid != nil}
/// Clears the value of `uuid`. Subsequent reads from it will return its default value.
mutating func clearUuid() {self._uuid = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum TypeEnum: SwiftProtobuf.Enum {
typealias RawValue = Int
case preOffer // = 6
case offer // = 1
case answer // = 2
case provisionalAnswer // = 3
@ -336,7 +347,7 @@ struct SessionProtos_CallMessage {
case endCall // = 5
init() {
self = .offer
self = .preOffer
}
init?(rawValue: Int) {
@ -346,6 +357,7 @@ struct SessionProtos_CallMessage {
case 3: self = .provisionalAnswer
case 4: self = .iceCandidates
case 5: self = .endCall
case 6: self = .preOffer
default: return nil
}
}
@ -357,6 +369,7 @@ struct SessionProtos_CallMessage {
case .provisionalAnswer: return 3
case .iceCandidates: return 4
case .endCall: return 5
case .preOffer: return 6
}
}
@ -365,6 +378,7 @@ struct SessionProtos_CallMessage {
init() {}
fileprivate var _type: SessionProtos_CallMessage.TypeEnum? = nil
fileprivate var _uuid: String? = nil
}
#if swift(>=4.2)
@ -1798,10 +1812,12 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
2: .same(proto: "sdps"),
3: .same(proto: "sdpMLineIndexes"),
4: .same(proto: "sdpMids"),
5: .same(proto: "uuid"),
]
public var isInitialized: Bool {
if self._type == nil {return false}
if self._uuid == nil {return false}
return true
}
@ -1815,6 +1831,7 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
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) }()
case 5: try { try decoder.decodeSingularStringField(value: &self._uuid) }()
default: break
}
}
@ -1833,6 +1850,9 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
if !self.sdpMids.isEmpty {
try visitor.visitRepeatedStringField(value: self.sdpMids, fieldNumber: 4)
}
if let v = self._uuid {
try visitor.visitSingularStringField(value: v, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -1841,6 +1861,7 @@ extension SessionProtos_CallMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
if lhs.sdps != rhs.sdps {return false}
if lhs.sdpMlineIndexes != rhs.sdpMlineIndexes {return false}
if lhs.sdpMids != rhs.sdpMids {return false}
if lhs._uuid != rhs._uuid {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
@ -1853,6 +1874,7 @@ extension SessionProtos_CallMessage.TypeEnum: SwiftProtobuf._ProtoNameProviding
3: .same(proto: "PROVISIONAL_ANSWER"),
4: .same(proto: "ICE_CANDIDATES"),
5: .same(proto: "END_CALL"),
6: .same(proto: "PRE_OFFER"),
]
}

@ -54,6 +54,7 @@ message Content {
message CallMessage {
enum Type {
PRE_OFFER = 6;
OFFER = 1;
ANSWER = 2;
PROVISIONAL_ANSWER = 3;
@ -68,6 +69,8 @@ message CallMessage {
repeated string sdps = 2;
repeated uint32 sdpMLineIndexes = 3;
repeated string sdpMids = 4;
// @required
required string uuid = 5;
}
message KeyPair {

@ -269,17 +269,17 @@ extension MessageReceiver {
if let current = WebRTCSession.current {
result = current
} else {
WebRTCSession.current = WebRTCSession(for: message.sender!)
WebRTCSession.current = WebRTCSession(for: message.sender!, with: message.uuid!)
result = WebRTCSession.current!
}
return result
}
switch message.kind! {
case .preOffer:
print("[Calls] Received pre-offer message.")
// TODO: Notify incoming call
case .offer:
print("[Calls] Received offer message.")
// Delegate to the main app, which is expected to show a dialog confirming
// that the user wants to pick up the call. When they do, the SDP contained
// in the offer message will be passed to WebRTCSession.handleRemoteSDP(_:from:).
let storage = SNMessagingKitConfiguration.shared.storage
let transaction = transaction as! YapDatabaseReadWriteTransaction
if let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, openGroupID: nil, using: transaction),
@ -287,6 +287,9 @@ extension MessageReceiver {
let tsMessage = TSIncomingMessage.from(message, associatedWith: thread)
tsMessage.save(with: transaction)
}
// Delegate to the main app, which is expected to show a dialog confirming
// that the user wants to pick up the call. When they do, the SDP contained
// in the offer message will be passed to WebRTCSession.handleRemoteSDP(_:from:).
handleOfferCallMessage?(message)
case .answer:
print("[Calls] Received answer message.")

Loading…
Cancel
Save