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

View File

@ -2,38 +2,50 @@ import SessionUtilitiesKit
public final class IndividualCallMessage : ControlMessage {
public var callID: UInt64?
public var opaque: Data?
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
public enum CallType : CustomStringConvertible {
public enum CallType : String {
case audio, video
public var description: String {
switch self {
case .audio: return "audio"
case .video: return "video"
fileprivate static func from(_ proto: SNProtoCallMessageOffer.SNProtoCallMessageOfferType) -> CallType {
switch proto {
case .offerAudioCall: return .audio
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
public enum Kind : CustomStringConvertible {
case offer(callType: CallType)
case answer
case offer(opaque: Data, callType: CallType)
case answer(opaque: Data)
case iceUpdate(candidates: [Data])
case hangup(type: HangupType)
case busy
public var description: String {
switch self {
case .offer(let callType): return "offer(callType: \(callType))"
case .answer: return "answer"
case .offer(let opaque, let callType): return "offer(opaque: \(opaque.count) bytes, callType: \(callType.rawValue))"
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
public override init() { super.init() }
internal init(callID: UInt64, opaque: Data, kind: Kind) {
internal init(callID: UInt64, kind: Kind) {
super.init()
self.callID = callID
self.opaque = opaque
self.kind = kind
}
@ -67,22 +78,30 @@ public final class IndividualCallMessage : ControlMessage {
public override class func fromProto(_ proto: SNProtoContent) -> IndividualCallMessage? {
guard let callMessage = proto.callMessage else { return nil }
let callID: UInt64
let opaqueOrNil: Data?
let kind: Kind
if let offer = callMessage.offer {
guard let opaque = offer.opaque else { return nil }
callID = offer.id
opaqueOrNil = offer.opaque
let callType: CallType = (offer.type == .offerAudioCall) ? .audio : .video
kind = .offer(callType: callType)
let callType = CallType.from(offer.type)
kind = .offer(opaque: opaque, callType: callType)
} else if let answer = callMessage.answer {
guard let opaque = answer.opaque else { return nil }
callID = answer.id
opaqueOrNil = answer.opaque
kind = .answer
kind = .answer(opaque: opaque)
} 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 {
return nil
}
guard let opaque = opaqueOrNil else { return nil }
return IndividualCallMessage(callID: callID, opaque: opaque, kind: kind)
return IndividualCallMessage(callID: callID, kind: kind)
}
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {