Further implement IndividualCallMessage

This commit is contained in:
Niels Andriesse 2021-07-30 16:30:43 +10:00
parent 92730961fe
commit 5ca7b08cf6
2 changed files with 77 additions and 72 deletions

View File

@ -800,10 +800,9 @@ import SessionMessagingKit
firstly { () throws -> Promise<Void> in firstly { () throws -> Promise<Void> in
let message = IndividualCallMessage() let message = IndividualCallMessage()
message.callID = callId message.callID = callId
message.opaque = opaque
switch callMediaType { switch callMediaType {
case .audioCall: message.kind = .offer(callType: .audio) case .audioCall: message.kind = .offer(opaque: opaque, callType: .audio)
case .videoCall: message.kind = .offer(callType: .video) case .videoCall: message.kind = .offer(opaque: opaque, callType: .video)
} }
Storage.write { transaction in Storage.write { transaction in
MessageSender.send(message, in: call.individualCall.thread, using: transaction) MessageSender.send(message, in: call.individualCall.thread, using: transaction)
@ -825,8 +824,7 @@ import SessionMessagingKit
firstly { () throws -> Promise<Void> in firstly { () throws -> Promise<Void> in
let message = IndividualCallMessage() let message = IndividualCallMessage()
message.callID = callId message.callID = callId
message.opaque = opaque message.kind = .answer(opaque: opaque)
message.kind = .answer
Storage.write { transaction in Storage.write { transaction in
MessageSender.send(message, in: call.individualCall.thread, using: transaction) MessageSender.send(message, in: call.individualCall.thread, using: transaction)
} }
@ -844,24 +842,18 @@ import SessionMessagingKit
owsAssertDebug(call.isIndividualCall) owsAssertDebug(call.isIndividualCall)
Logger.info("shouldSendIceCandidates") Logger.info("shouldSendIceCandidates")
guard !candidates.isEmpty else {
Logger.error("no ice updates to send")
return callManager.signalingMessageDidFail(callId: callId)
}
firstly { () throws -> Promise<Void> in firstly { () throws -> Promise<Void> in
var iceUpdateProtos = [SNProtoCallMessageIceUpdate]() let message = IndividualCallMessage()
message.callID = callId
for iceCandidate in candidates { message.kind = .iceUpdate(candidates: candidates)
let iceUpdateProto: SNProtoCallMessageIceUpdate Storage.write { transaction in
let iceUpdateBuilder = SNProtoCallMessageIceUpdate.builder(id: callId) MessageSender.send(message, in: call.individualCall.thread, using: transaction)
iceUpdateBuilder.setOpaque(iceCandidate)
iceUpdateProto = try iceUpdateBuilder.build()
iceUpdateProtos.append(iceUpdateProto)
} }
guard !iceUpdateProtos.isEmpty else {
throw OWSAssertionError("no ice updates to send")
}
let callMessage = OWSOutgoingCallMessage(thread: call.individualCall.thread, iceUpdateMessages: iceUpdateProtos, destinationDeviceId: NSNumber(value: destinationDeviceId))
return messageSender.sendMessage(.promise, callMessage.asPreparer)
}.done { }.done {
Logger.debug("sent ice update message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")") Logger.debug("sent ice update message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")")
try self.callManager.signalingMessageDidSend(callId: callId) try self.callManager.signalingMessageDidSend(callId: callId)
@ -877,29 +869,20 @@ import SessionMessagingKit
Logger.info("shouldSendHangup") Logger.info("shouldSendHangup")
firstly { () throws -> Promise<Void> in firstly { () throws -> Promise<Void> in
let hangupBuilder = SNProtoCallMessageHangup.builder(id: callId) let type: IndividualCallMessage.HangupType
switch hangupType { switch hangupType {
case .normal: hangupBuilder.setType(.hangupNormal) case .normal: type = .normal
case .accepted: hangupBuilder.setType(.hangupAccepted) case .accepted: type = .accepted
case .declined: hangupBuilder.setType(.hangupDeclined) case .declined: type = .declined
case .busy: hangupBuilder.setType(.hangupBusy) case .busy: type = .busy
case .needPermission: hangupBuilder.setType(.hangupNeedPermission) case .needPermission: type = .needPermission
} }
let message = IndividualCallMessage()
if hangupType != .normal { message.callID = callId
// deviceId is optional and only used when indicated by a hangup due to message.kind = .hangup(type: type)
// a call being accepted elsewhere. Storage.write { transaction in
hangupBuilder.setDeviceID(deviceId) MessageSender.send(message, in: call.individualCall.thread, using: transaction)
} }
let callMessage: OWSOutgoingCallMessage
if useLegacyHangupMessage {
callMessage = OWSOutgoingCallMessage(thread: call.individualCall.thread, legacyHangupMessage: try hangupBuilder.build(), destinationDeviceId: NSNumber(value: destinationDeviceId))
} else {
callMessage = OWSOutgoingCallMessage(thread: call.individualCall.thread, hangupMessage: try hangupBuilder.build(), destinationDeviceId: NSNumber(value: destinationDeviceId))
}
return messageSender.sendMessage(.promise, callMessage.asPreparer)
}.done { }.done {
Logger.debug("sent hangup message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")") Logger.debug("sent hangup message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")")
try self.callManager.signalingMessageDidSend(callId: callId) try self.callManager.signalingMessageDidSend(callId: callId)
@ -915,9 +898,12 @@ import SessionMessagingKit
Logger.info("shouldSendBusy") Logger.info("shouldSendBusy")
firstly { () throws -> Promise<Void> in firstly { () throws -> Promise<Void> in
let busyBuilder = SNProtoCallMessageBusy.builder(id: callId) let message = IndividualCallMessage()
let callMessage = OWSOutgoingCallMessage(thread: call.individualCall.thread, busyMessage: try busyBuilder.build(), destinationDeviceId: NSNumber(value: destinationDeviceId)) message.callID = callId
return messageSender.sendMessage(.promise, callMessage.asPreparer) message.kind = .busy
Storage.write { transaction in
MessageSender.send(message, in: call.individualCall.thread, using: transaction)
}
}.done { }.done {
Logger.debug("sent busy message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")") Logger.debug("sent busy message to \(call.individualCall.thread.contactSessionID()) device: \((destinationDeviceId != nil) ? String(destinationDeviceId!) : "nil")")
try self.callManager.signalingMessageDidSend(callId: callId) try self.callManager.signalingMessageDidSend(callId: callId)

View File

@ -2,38 +2,50 @@ import SessionUtilitiesKit
public final class IndividualCallMessage : ControlMessage { public final class IndividualCallMessage : ControlMessage {
public var callID: UInt64? public var callID: UInt64?
public var opaque: Data?
public var kind: Kind? public var kind: Kind?
// let offerBuilder = SNProtoCallMessageOffer.builder(id: callId)
// offerBuilder.setOpaque(opaque)
// switch callMediaType {
// case .audioCall: offerBuilder.setType(.offerAudioCall)
// case .videoCall: offerBuilder.setType(.offerVideoCall)
// }
// let callMessage = OWSOutgoingCallMessage(thread: call.individualCall.thread, offerMessage: try offerBuilder.build(), destinationDeviceId: NSNumber(value: destinationDeviceId))
// MARK: Call Type // MARK: Call Type
public enum CallType : CustomStringConvertible { public enum CallType : String {
case audio, video case audio, video
public var description: String { fileprivate static func from(_ proto: SNProtoCallMessageOffer.SNProtoCallMessageOfferType) -> CallType {
switch self { switch proto {
case .audio: return "audio" case .offerAudioCall: return .audio
case .video: return "video" case .offerVideoCall: return .video
}
}
}
// MARK: Hangup Type
public enum HangupType : String {
case normal, accepted, declined, busy, needPermission
fileprivate static func from(_ proto: SNProtoCallMessageHangup.SNProtoCallMessageHangupType) -> HangupType {
switch proto {
case .hangupNormal: return .normal
case .hangupAccepted: return .accepted
case .hangupDeclined: return .declined
case .hangupBusy: return .busy
case .hangupNeedPermission: return .needPermission
} }
} }
} }
// MARK: Kind // MARK: Kind
public enum Kind : CustomStringConvertible { public enum Kind : CustomStringConvertible {
case offer(callType: CallType) case offer(opaque: Data, callType: CallType)
case answer case answer(opaque: Data)
case iceUpdate(candidates: [Data])
case hangup(type: HangupType)
case busy
public var description: String { public var description: String {
switch self { switch self {
case .offer(let callType): return "offer(callType: \(callType))" case .offer(let opaque, let callType): return "offer(opaque: \(opaque.count) bytes, callType: \(callType.rawValue))"
case .answer: return "answer" case .answer(let opaque): return "answer(opaque: \(opaque.count) bytes)"
case .iceUpdate(let candidates): return "iceUpdate(candidates: \(candidates.count) candidates)"
case .hangup(let type): return "hangup(type: \(type.rawValue)"
case .busy: return "busy"
} }
} }
} }
@ -41,10 +53,9 @@ public final class IndividualCallMessage : ControlMessage {
// MARK: Initialization // MARK: Initialization
public override init() { super.init() } public override init() { super.init() }
internal init(callID: UInt64, opaque: Data, kind: Kind) { internal init(callID: UInt64, kind: Kind) {
super.init() super.init()
self.callID = callID self.callID = callID
self.opaque = opaque
self.kind = kind self.kind = kind
} }
@ -67,22 +78,30 @@ public final class IndividualCallMessage : ControlMessage {
public override class func fromProto(_ proto: SNProtoContent) -> IndividualCallMessage? { public override class func fromProto(_ proto: SNProtoContent) -> IndividualCallMessage? {
guard let callMessage = proto.callMessage else { return nil } guard let callMessage = proto.callMessage else { return nil }
let callID: UInt64 let callID: UInt64
let opaqueOrNil: Data?
let kind: Kind let kind: Kind
if let offer = callMessage.offer { if let offer = callMessage.offer {
guard let opaque = offer.opaque else { return nil }
callID = offer.id callID = offer.id
opaqueOrNil = offer.opaque let callType = CallType.from(offer.type)
let callType: CallType = (offer.type == .offerAudioCall) ? .audio : .video kind = .offer(opaque: opaque, callType: callType)
kind = .offer(callType: callType)
} else if let answer = callMessage.answer { } else if let answer = callMessage.answer {
guard let opaque = answer.opaque else { return nil }
callID = answer.id callID = answer.id
opaqueOrNil = answer.opaque kind = .answer(opaque: opaque)
kind = .answer } else if !callMessage.iceUpdate.isEmpty {
callID = callMessage.iceUpdate.first!.id // TODO: Is this how it's supposed to work?
kind = .iceUpdate(candidates: callMessage.iceUpdate.compactMap { $0.opaque }) // Should never contain entries with a `nil` `opaque`
} else if let hangup = callMessage.hangup {
callID = hangup.id
let type = HangupType.from(hangup.type)
kind = .hangup(type: type)
} else if let busy = callMessage.busy {
callID = busy.id
kind = .busy
} else { } else {
return nil return nil
} }
guard let opaque = opaqueOrNil else { return nil } return IndividualCallMessage(callID: callID, kind: kind)
return IndividualCallMessage(callID: callID, opaque: opaque, kind: kind)
} }
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {