mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
[WIP] Conference calls
This commit is contained in:
parent
e18795980e
commit
2b9f5ed541
@ -283,6 +283,9 @@
|
|||||||
"LOCAL_CHANNEL_MESSAGE_FWDS" = "%1$@ posted %2$d forwarded messages";
|
"LOCAL_CHANNEL_MESSAGE_FWDS" = "%1$@ posted %2$d forwarded messages";
|
||||||
"LOCAL_CHAT_MESSAGE_FWDS" = "%1$@ forwarded %2$d messages";
|
"LOCAL_CHAT_MESSAGE_FWDS" = "%1$@ forwarded %2$d messages";
|
||||||
|
|
||||||
|
"PUSH_STORY_HIDDEN_AUTHOR" = "New story was posted";
|
||||||
|
"PUSH_MESSAGE_STARGIFT" = "%1$@|sent you a Gift worth of %2$@ stars";
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
"Common.OK" = "OK";
|
"Common.OK" = "OK";
|
||||||
"Common.Cancel" = "Cancel";
|
"Common.Cancel" = "Cancel";
|
||||||
|
|||||||
@ -535,7 +535,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
|
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
|
||||||
dict[1235637404] = { return Api.MediaArea.parse_mediaAreaWeather($0) }
|
dict[1235637404] = { return Api.MediaArea.parse_mediaAreaWeather($0) }
|
||||||
dict[-808853502] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) }
|
dict[-808853502] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) }
|
||||||
dict[-1808510398] = { return Api.Message.parse_message($0) }
|
dict[-1761756183] = { return Api.Message.parse_message($0) }
|
||||||
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
|
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
|
||||||
dict[-741178048] = { return Api.Message.parse_messageService($0) }
|
dict[-741178048] = { return Api.Message.parse_messageService($0) }
|
||||||
dict[-872240531] = { return Api.MessageAction.parse_messageActionBoostApply($0) }
|
dict[-872240531] = { return Api.MessageAction.parse_messageActionBoostApply($0) }
|
||||||
@ -723,11 +723,12 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1395233698] = { return Api.PeerSettings.parse_peerSettings($0) }
|
dict[-1395233698] = { return Api.PeerSettings.parse_peerSettings($0) }
|
||||||
dict[-1707742823] = { return Api.PeerStories.parse_peerStories($0) }
|
dict[-1707742823] = { return Api.PeerStories.parse_peerStories($0) }
|
||||||
dict[1000707084] = { return Api.PhoneCall.parse_phoneCall($0) }
|
dict[1000707084] = { return Api.PhoneCall.parse_phoneCall($0) }
|
||||||
dict[912311057] = { return Api.PhoneCall.parse_phoneCallAccepted($0) }
|
dict[587035009] = { return Api.PhoneCall.parse_phoneCallAccepted($0) }
|
||||||
dict[1355435489] = { return Api.PhoneCall.parse_phoneCallDiscarded($0) }
|
dict[-103656189] = { return Api.PhoneCall.parse_phoneCallDiscarded($0) }
|
||||||
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
|
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
|
||||||
dict[347139340] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
|
dict[1161174115] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
|
||||||
dict[-987599081] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
|
dict[-288085928] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
|
||||||
|
dict[-1344096199] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonAllowGroupCall($0) }
|
||||||
dict[-84416311] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonBusy($0) }
|
dict[-84416311] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonBusy($0) }
|
||||||
dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) }
|
dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) }
|
||||||
dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) }
|
dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) }
|
||||||
|
|||||||
@ -60,15 +60,15 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
indirect enum Message: TypeConstructorDescription {
|
indirect enum Message: TypeConstructorDescription {
|
||||||
case message(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?, effect: Int64?, factcheck: Api.FactCheck?)
|
case message(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?, effect: Int64?, factcheck: Api.FactCheck?, reportDeliveryUntilDate: Int32?)
|
||||||
case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?)
|
case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?)
|
||||||
case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction, reactions: Api.MessageReactions?, ttlPeriod: Int32?)
|
case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction, reactions: Api.MessageReactions?, ttlPeriod: Int32?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect, let factcheck):
|
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect, let factcheck, let reportDeliveryUntilDate):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1808510398)
|
buffer.appendInt32(-1761756183)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(flags2, buffer: buffer, boxed: false)
|
serializeInt32(flags2, buffer: buffer, boxed: false)
|
||||||
@ -106,6 +106,7 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 30) != 0 {serializeInt32(quickReplyShortcutId!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 30) != 0 {serializeInt32(quickReplyShortcutId!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags2) & Int(1 << 2) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
if Int(flags2) & Int(1 << 2) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags2) & Int(1 << 3) != 0 {factcheck!.serialize(buffer, true)}
|
if Int(flags2) & Int(1 << 3) != 0 {factcheck!.serialize(buffer, true)}
|
||||||
|
if Int(flags2) & Int(1 << 5) != 0 {serializeInt32(reportDeliveryUntilDate!, buffer: buffer, boxed: false)}
|
||||||
break
|
break
|
||||||
case .messageEmpty(let flags, let id, let peerId):
|
case .messageEmpty(let flags, let id, let peerId):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -134,8 +135,8 @@ public extension Api {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect, let factcheck):
|
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect, let factcheck, let reportDeliveryUntilDate):
|
||||||
return ("message", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("viaBusinessBotId", viaBusinessBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any), ("quickReplyShortcutId", quickReplyShortcutId as Any), ("effect", effect as Any), ("factcheck", factcheck as Any)])
|
return ("message", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("viaBusinessBotId", viaBusinessBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any), ("quickReplyShortcutId", quickReplyShortcutId as Any), ("effect", effect as Any), ("factcheck", factcheck as Any), ("reportDeliveryUntilDate", reportDeliveryUntilDate as Any)])
|
||||||
case .messageEmpty(let flags, let id, let peerId):
|
case .messageEmpty(let flags, let id, let peerId):
|
||||||
return ("messageEmpty", [("flags", flags as Any), ("id", id as Any), ("peerId", peerId as Any)])
|
return ("messageEmpty", [("flags", flags as Any), ("id", id as Any), ("peerId", peerId as Any)])
|
||||||
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action, let reactions, let ttlPeriod):
|
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action, let reactions, let ttlPeriod):
|
||||||
@ -224,6 +225,8 @@ public extension Api {
|
|||||||
if Int(_2!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
if Int(_2!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
||||||
_28 = Api.parse(reader, signature: signature) as? Api.FactCheck
|
_28 = Api.parse(reader, signature: signature) as? Api.FactCheck
|
||||||
} }
|
} }
|
||||||
|
var _29: Int32?
|
||||||
|
if Int(_2!) & Int(1 << 5) != 0 {_29 = reader.readInt32() }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -252,8 +255,9 @@ public extension Api {
|
|||||||
let _c26 = (Int(_1!) & Int(1 << 30) == 0) || _26 != nil
|
let _c26 = (Int(_1!) & Int(1 << 30) == 0) || _26 != nil
|
||||||
let _c27 = (Int(_2!) & Int(1 << 2) == 0) || _27 != nil
|
let _c27 = (Int(_2!) & Int(1 << 2) == 0) || _27 != nil
|
||||||
let _c28 = (Int(_2!) & Int(1 << 3) == 0) || _28 != nil
|
let _c28 = (Int(_2!) & Int(1 << 3) == 0) || _28 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 {
|
let _c29 = (Int(_2!) & Int(1 << 5) == 0) || _29 != nil
|
||||||
return Api.Message.message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, peerId: _6!, savedPeerId: _7, fwdFrom: _8, viaBotId: _9, viaBusinessBotId: _10, replyTo: _11, date: _12!, message: _13!, media: _14, replyMarkup: _15, entities: _16, views: _17, forwards: _18, replies: _19, editDate: _20, postAuthor: _21, groupedId: _22, reactions: _23, restrictionReason: _24, ttlPeriod: _25, quickReplyShortcutId: _26, effect: _27, factcheck: _28)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 {
|
||||||
|
return Api.Message.message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, peerId: _6!, savedPeerId: _7, fwdFrom: _8, viaBotId: _9, viaBusinessBotId: _10, replyTo: _11, date: _12!, message: _13!, media: _14, replyMarkup: _15, entities: _16, views: _17, forwards: _18, replies: _19, editDate: _20, postAuthor: _21, groupedId: _22, reactions: _23, restrictionReason: _24, ttlPeriod: _25, quickReplyShortcutId: _26, effect: _27, factcheck: _28, reportDeliveryUntilDate: _29)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -1011,11 +1011,11 @@ public extension Api {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
enum PhoneCall: TypeConstructorDescription {
|
enum PhoneCall: TypeConstructorDescription {
|
||||||
case phoneCall(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAOrB: Buffer, keyFingerprint: Int64, protocol: Api.PhoneCallProtocol, connections: [Api.PhoneConnection], startDate: Int32, customParameters: Api.DataJSON?, conferenceCall: Api.InputGroupCall?)
|
case phoneCall(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAOrB: Buffer, keyFingerprint: Int64, protocol: Api.PhoneCallProtocol, connections: [Api.PhoneConnection], startDate: Int32, customParameters: Api.DataJSON?, conferenceCall: Api.InputGroupCall?)
|
||||||
case phoneCallAccepted(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gB: Buffer, protocol: Api.PhoneCallProtocol)
|
case phoneCallAccepted(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gB: Buffer, protocol: Api.PhoneCallProtocol, conferenceCall: Api.InputGroupCall?)
|
||||||
case phoneCallDiscarded(flags: Int32, id: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?)
|
case phoneCallDiscarded(flags: Int32, id: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?, conferenceCall: Api.InputGroupCall?)
|
||||||
case phoneCallEmpty(id: Int64)
|
case phoneCallEmpty(id: Int64)
|
||||||
case phoneCallRequested(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAHash: Buffer, protocol: Api.PhoneCallProtocol)
|
case phoneCallRequested(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAHash: Buffer, protocol: Api.PhoneCallProtocol, conferenceCall: Api.InputGroupCall?)
|
||||||
case phoneCallWaiting(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, protocol: Api.PhoneCallProtocol, receiveDate: Int32?)
|
case phoneCallWaiting(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, protocol: Api.PhoneCallProtocol, receiveDate: Int32?, conferenceCall: Api.InputGroupCall?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -1041,9 +1041,9 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 7) != 0 {customParameters!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 7) != 0 {customParameters!.serialize(buffer, true)}
|
||||||
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`):
|
case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`, let conferenceCall):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(912311057)
|
buffer.appendInt32(587035009)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
@ -1053,15 +1053,17 @@ public extension Api {
|
|||||||
serializeInt64(participantId, buffer: buffer, boxed: false)
|
serializeInt64(participantId, buffer: buffer, boxed: false)
|
||||||
serializeBytes(gB, buffer: buffer, boxed: false)
|
serializeBytes(gB, buffer: buffer, boxed: false)
|
||||||
`protocol`.serialize(buffer, true)
|
`protocol`.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .phoneCallDiscarded(let flags, let id, let reason, let duration):
|
case .phoneCallDiscarded(let flags, let id, let reason, let duration, let conferenceCall):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1355435489)
|
buffer.appendInt32(-103656189)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 0) != 0 {reason!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 0) != 0 {reason!.serialize(buffer, true)}
|
||||||
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .phoneCallEmpty(let id):
|
case .phoneCallEmpty(let id):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -1069,9 +1071,9 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`):
|
case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`, let conferenceCall):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(347139340)
|
buffer.appendInt32(1161174115)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
@ -1081,10 +1083,11 @@ public extension Api {
|
|||||||
serializeInt64(participantId, buffer: buffer, boxed: false)
|
serializeInt64(participantId, buffer: buffer, boxed: false)
|
||||||
serializeBytes(gAHash, buffer: buffer, boxed: false)
|
serializeBytes(gAHash, buffer: buffer, boxed: false)
|
||||||
`protocol`.serialize(buffer, true)
|
`protocol`.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate):
|
case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate, let conferenceCall):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-987599081)
|
buffer.appendInt32(-288085928)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
@ -1094,6 +1097,7 @@ public extension Api {
|
|||||||
serializeInt64(participantId, buffer: buffer, boxed: false)
|
serializeInt64(participantId, buffer: buffer, boxed: false)
|
||||||
`protocol`.serialize(buffer, true)
|
`protocol`.serialize(buffer, true)
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(receiveDate!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(receiveDate!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1102,16 +1106,16 @@ public extension Api {
|
|||||||
switch self {
|
switch self {
|
||||||
case .phoneCall(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint, let `protocol`, let connections, let startDate, let customParameters, let conferenceCall):
|
case .phoneCall(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint, let `protocol`, let connections, let startDate, let customParameters, let conferenceCall):
|
||||||
return ("phoneCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAOrB", gAOrB as Any), ("keyFingerprint", keyFingerprint as Any), ("`protocol`", `protocol` as Any), ("connections", connections as Any), ("startDate", startDate as Any), ("customParameters", customParameters as Any), ("conferenceCall", conferenceCall as Any)])
|
return ("phoneCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAOrB", gAOrB as Any), ("keyFingerprint", keyFingerprint as Any), ("`protocol`", `protocol` as Any), ("connections", connections as Any), ("startDate", startDate as Any), ("customParameters", customParameters as Any), ("conferenceCall", conferenceCall as Any)])
|
||||||
case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`):
|
case .phoneCallAccepted(let flags, let id, let accessHash, let date, let adminId, let participantId, let gB, let `protocol`, let conferenceCall):
|
||||||
return ("phoneCallAccepted", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gB", gB as Any), ("`protocol`", `protocol` as Any)])
|
return ("phoneCallAccepted", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gB", gB as Any), ("`protocol`", `protocol` as Any), ("conferenceCall", conferenceCall as Any)])
|
||||||
case .phoneCallDiscarded(let flags, let id, let reason, let duration):
|
case .phoneCallDiscarded(let flags, let id, let reason, let duration, let conferenceCall):
|
||||||
return ("phoneCallDiscarded", [("flags", flags as Any), ("id", id as Any), ("reason", reason as Any), ("duration", duration as Any)])
|
return ("phoneCallDiscarded", [("flags", flags as Any), ("id", id as Any), ("reason", reason as Any), ("duration", duration as Any), ("conferenceCall", conferenceCall as Any)])
|
||||||
case .phoneCallEmpty(let id):
|
case .phoneCallEmpty(let id):
|
||||||
return ("phoneCallEmpty", [("id", id as Any)])
|
return ("phoneCallEmpty", [("id", id as Any)])
|
||||||
case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`):
|
case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`, let conferenceCall):
|
||||||
return ("phoneCallRequested", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAHash", gAHash as Any), ("`protocol`", `protocol` as Any)])
|
return ("phoneCallRequested", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAHash", gAHash as Any), ("`protocol`", `protocol` as Any), ("conferenceCall", conferenceCall as Any)])
|
||||||
case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate):
|
case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate, let conferenceCall):
|
||||||
return ("phoneCallWaiting", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("`protocol`", `protocol` as Any), ("receiveDate", receiveDate as Any)])
|
return ("phoneCallWaiting", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("`protocol`", `protocol` as Any), ("receiveDate", receiveDate as Any), ("conferenceCall", conferenceCall as Any)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1189,6 +1193,10 @@ public extension Api {
|
|||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol
|
_8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol
|
||||||
}
|
}
|
||||||
|
var _9: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_9 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -1197,8 +1205,9 @@ public extension Api {
|
|||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = _7 != nil
|
let _c7 = _7 != nil
|
||||||
let _c8 = _8 != nil
|
let _c8 = _8 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
|
||||||
return Api.PhoneCall.phoneCallAccepted(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gB: _7!, protocol: _8!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||||
|
return Api.PhoneCall.phoneCallAccepted(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gB: _7!, protocol: _8!, conferenceCall: _9)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1215,12 +1224,17 @@ public extension Api {
|
|||||||
} }
|
} }
|
||||||
var _4: Int32?
|
var _4: Int32?
|
||||||
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
|
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
|
||||||
|
var _5: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_5 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
||||||
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
|
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
|
||||||
return Api.PhoneCall.phoneCallDiscarded(flags: _1!, id: _2!, reason: _3, duration: _4)
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.PhoneCall.phoneCallDiscarded(flags: _1!, id: _2!, reason: _3, duration: _4, conferenceCall: _5)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1256,6 +1270,10 @@ public extension Api {
|
|||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol
|
_8 = Api.parse(reader, signature: signature) as? Api.PhoneCallProtocol
|
||||||
}
|
}
|
||||||
|
var _9: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_9 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -1264,8 +1282,9 @@ public extension Api {
|
|||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = _7 != nil
|
let _c7 = _7 != nil
|
||||||
let _c8 = _8 != nil
|
let _c8 = _8 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
|
||||||
return Api.PhoneCall.phoneCallRequested(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gAHash: _7!, protocol: _8!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||||
|
return Api.PhoneCall.phoneCallRequested(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gAHash: _7!, protocol: _8!, conferenceCall: _9)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1290,6 +1309,10 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
var _8: Int32?
|
var _8: Int32?
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_8 = reader.readInt32() }
|
if Int(_1!) & Int(1 << 0) != 0 {_8 = reader.readInt32() }
|
||||||
|
var _9: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 8) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_9 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -1298,8 +1321,9 @@ public extension Api {
|
|||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = _7 != nil
|
let _c7 = _7 != nil
|
||||||
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
|
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
|
||||||
return Api.PhoneCall.phoneCallWaiting(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, protocol: _7!, receiveDate: _8)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||||
|
return Api.PhoneCall.phoneCallWaiting(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, protocol: _7!, receiveDate: _8, conferenceCall: _9)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1310,6 +1334,7 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum PhoneCallDiscardReason: TypeConstructorDescription {
|
enum PhoneCallDiscardReason: TypeConstructorDescription {
|
||||||
|
case phoneCallDiscardReasonAllowGroupCall(encryptedKey: Buffer)
|
||||||
case phoneCallDiscardReasonBusy
|
case phoneCallDiscardReasonBusy
|
||||||
case phoneCallDiscardReasonDisconnect
|
case phoneCallDiscardReasonDisconnect
|
||||||
case phoneCallDiscardReasonHangup
|
case phoneCallDiscardReasonHangup
|
||||||
@ -1317,6 +1342,12 @@ public extension Api {
|
|||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .phoneCallDiscardReasonAllowGroupCall(let encryptedKey):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1344096199)
|
||||||
|
}
|
||||||
|
serializeBytes(encryptedKey, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
case .phoneCallDiscardReasonBusy:
|
case .phoneCallDiscardReasonBusy:
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-84416311)
|
buffer.appendInt32(-84416311)
|
||||||
@ -1346,6 +1377,8 @@ public extension Api {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .phoneCallDiscardReasonAllowGroupCall(let encryptedKey):
|
||||||
|
return ("phoneCallDiscardReasonAllowGroupCall", [("encryptedKey", encryptedKey as Any)])
|
||||||
case .phoneCallDiscardReasonBusy:
|
case .phoneCallDiscardReasonBusy:
|
||||||
return ("phoneCallDiscardReasonBusy", [])
|
return ("phoneCallDiscardReasonBusy", [])
|
||||||
case .phoneCallDiscardReasonDisconnect:
|
case .phoneCallDiscardReasonDisconnect:
|
||||||
@ -1357,6 +1390,17 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func parse_phoneCallDiscardReasonAllowGroupCall(_ reader: BufferReader) -> PhoneCallDiscardReason? {
|
||||||
|
var _1: Buffer?
|
||||||
|
_1 = parseBytes(reader)
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.PhoneCallDiscardReason.phoneCallDiscardReasonAllowGroupCall(encryptedKey: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
public static func parse_phoneCallDiscardReasonBusy(_ reader: BufferReader) -> PhoneCallDiscardReason? {
|
public static func parse_phoneCallDiscardReasonBusy(_ reader: BufferReader) -> PhoneCallDiscardReason? {
|
||||||
return Api.PhoneCallDiscardReason.phoneCallDiscardReasonBusy
|
return Api.PhoneCallDiscardReason.phoneCallDiscardReasonBusy
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7483,6 +7483,27 @@ public extension Api.functions.messages {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api.functions.messages {
|
||||||
|
static func reportMessagesDelivery(flags: Int32, peer: Api.InputPeer, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1517122453)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(id.count))
|
||||||
|
for item in id {
|
||||||
|
serializeInt32(item, buffer: buffer, boxed: false)
|
||||||
|
}
|
||||||
|
return (FunctionDescription(name: "messages.reportMessagesDelivery", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Bool?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api.functions.messages {
|
public extension Api.functions.messages {
|
||||||
static func reportReaction(peer: Api.InputPeer, id: Int32, reactionPeer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
static func reportReaction(peer: Api.InputPeer, id: Int32, reactionPeer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
@ -9587,11 +9608,12 @@ public extension Api.functions.phone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.functions.phone {
|
public extension Api.functions.phone {
|
||||||
static func createConferenceCall(peer: Api.InputPhoneCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.PhoneCall>) {
|
static func createConferenceCall(peer: Api.InputPhoneCall, keyFingerprint: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.PhoneCall>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-1828162221)
|
buffer.appendInt32(-540472917)
|
||||||
peer.serialize(buffer, true)
|
peer.serialize(buffer, true)
|
||||||
return (FunctionDescription(name: "phone.createConferenceCall", parameters: [("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in
|
serializeInt64(keyFingerprint, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "phone.createConferenceCall", parameters: [("peer", String(describing: peer)), ("keyFingerprint", String(describing: keyFingerprint))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.phone.PhoneCall?
|
var result: Api.phone.PhoneCall?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
@ -9834,15 +9856,16 @@ public extension Api.functions.phone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.functions.phone {
|
public extension Api.functions.phone {
|
||||||
static func joinGroupCall(flags: Int32, call: Api.InputGroupCall, joinAs: Api.InputPeer, inviteHash: String?, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
static func joinGroupCall(flags: Int32, call: Api.InputGroupCall, joinAs: Api.InputPeer, inviteHash: String?, keyFingerprint: Int64?, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-1322057861)
|
buffer.appendInt32(-702669325)
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
joinAs.serialize(buffer, true)
|
joinAs.serialize(buffer, true)
|
||||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(inviteHash!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 1) != 0 {serializeString(inviteHash!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(keyFingerprint!, buffer: buffer, boxed: false)}
|
||||||
params.serialize(buffer, true)
|
params.serialize(buffer, true)
|
||||||
return (FunctionDescription(name: "phone.joinGroupCall", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("joinAs", String(describing: joinAs)), ("inviteHash", String(describing: inviteHash)), ("params", String(describing: params))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
return (FunctionDescription(name: "phone.joinGroupCall", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("joinAs", String(describing: joinAs)), ("inviteHash", String(describing: inviteHash)), ("keyFingerprint", String(describing: keyFingerprint)), ("params", String(describing: params))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.Updates?
|
var result: Api.Updates?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
@ -9915,15 +9938,16 @@ public extension Api.functions.phone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.functions.phone {
|
public extension Api.functions.phone {
|
||||||
static func requestCall(flags: Int32, userId: Api.InputUser, randomId: Int32, gAHash: Buffer, `protocol`: Api.PhoneCallProtocol) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.PhoneCall>) {
|
static func requestCall(flags: Int32, userId: Api.InputUser, conferenceCall: Api.InputGroupCall?, randomId: Int32, gAHash: Buffer, `protocol`: Api.PhoneCallProtocol) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.PhoneCall>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1124046573)
|
buffer.appendInt32(-1497079796)
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
userId.serialize(buffer, true)
|
userId.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {conferenceCall!.serialize(buffer, true)}
|
||||||
serializeInt32(randomId, buffer: buffer, boxed: false)
|
serializeInt32(randomId, buffer: buffer, boxed: false)
|
||||||
serializeBytes(gAHash, buffer: buffer, boxed: false)
|
serializeBytes(gAHash, buffer: buffer, boxed: false)
|
||||||
`protocol`.serialize(buffer, true)
|
`protocol`.serialize(buffer, true)
|
||||||
return (FunctionDescription(name: "phone.requestCall", parameters: [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("randomId", String(describing: randomId)), ("gAHash", String(describing: gAHash)), ("`protocol`", String(describing: `protocol`))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in
|
return (FunctionDescription(name: "phone.requestCall", parameters: [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("conferenceCall", String(describing: conferenceCall)), ("randomId", String(describing: randomId)), ("gAHash", String(describing: gAHash)), ("`protocol`", String(describing: `protocol`))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.PhoneCall? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.phone.PhoneCall?
|
var result: Api.phone.PhoneCall?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
|||||||
@ -522,6 +522,13 @@ public final class CallController: ViewController {
|
|||||||
let _ = self?.dismiss()
|
let _ = self?.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayNode.conferenceAddParticipant = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.conferenceAddParticipant()
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.presentCallRating = { [weak self] callId, isVideo in
|
self.controllerNode.presentCallRating = { [weak self] callId, isVideo in
|
||||||
if let strongSelf = self, !strongSelf.presentedCallRating {
|
if let strongSelf = self, !strongSelf.presentedCallRating {
|
||||||
strongSelf.presentedCallRating = true
|
strongSelf.presentedCallRating = true
|
||||||
@ -667,6 +674,35 @@ public final class CallController: ViewController {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func conferenceAddParticipant() {
|
||||||
|
let controller = self.call.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(
|
||||||
|
context: self.call.context,
|
||||||
|
filter: [.onlyWriteable],
|
||||||
|
hasChatListSelector: true,
|
||||||
|
hasContactSelector: true,
|
||||||
|
hasGlobalSearch: true,
|
||||||
|
title: "Add Participant",
|
||||||
|
pretendPresentedInModal: false
|
||||||
|
))
|
||||||
|
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
||||||
|
controller?.dismiss()
|
||||||
|
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard case let .call(call) = self.call else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let call = call as? PresentationCallImpl else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = call.requestAddToConference(peerId: peer.id)
|
||||||
|
}
|
||||||
|
self.dismiss()
|
||||||
|
|
||||||
|
(self.call.context.sharedContext.mainWindow?.viewController as? NavigationController)?.pushViewController(controller)
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func backPressed() {
|
@objc private func backPressed() {
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,6 +60,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
|||||||
var dismissedInteractively: (() -> Void)?
|
var dismissedInteractively: (() -> Void)?
|
||||||
var dismissAllTooltips: (() -> Void)?
|
var dismissAllTooltips: (() -> Void)?
|
||||||
var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
|
var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
|
||||||
|
var conferenceAddParticipant: (() -> Void)?
|
||||||
|
|
||||||
private var emojiKey: (data: Data, resolvedKey: [String])?
|
private var emojiKey: (data: Data, resolvedKey: [String])?
|
||||||
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat)?
|
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat)?
|
||||||
@ -129,6 +130,14 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if self.sharedContext.immediateExperimentalUISettings.conferenceCalls {
|
||||||
|
self.conferenceAddParticipant?()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
self.call.toggleIsMuted()
|
self.call.toggleIsMuted()
|
||||||
}
|
}
|
||||||
self.callScreen.endCallAction = { [weak self] in
|
self.callScreen.endCallAction = { [weak self] in
|
||||||
@ -157,6 +166,12 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
|||||||
}
|
}
|
||||||
self.restoreUIForPictureInPicture?(completion)
|
self.restoreUIForPictureInPicture?(completion)
|
||||||
}
|
}
|
||||||
|
self.callScreen.conferenceAddParticipant = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.conferenceAddParticipant?()
|
||||||
|
}
|
||||||
|
|
||||||
self.callScreenState = PrivateCallScreen.State(
|
self.callScreenState = PrivateCallScreen.State(
|
||||||
strings: presentationData.strings,
|
strings: presentationData.strings,
|
||||||
|
|||||||
@ -550,9 +550,9 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
presentationState = PresentationCallState(state: .terminating(reason), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
presentationState = PresentationCallState(state: .terminating(reason), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
||||||
case let .terminated(id, reason, options):
|
case let .terminated(id, reason, options):
|
||||||
presentationState = PresentationCallState(state: .terminated(id, reason, self.callWasActive && (options.contains(.reportRating) || self.shouldPresentCallRating)), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
presentationState = PresentationCallState(state: .terminated(id, reason, self.callWasActive && (options.contains(.reportRating) || self.shouldPresentCallRating)), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
||||||
case let .requesting(ringing):
|
case let .requesting(ringing, _):
|
||||||
presentationState = PresentationCallState(state: .requesting(ringing), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
presentationState = PresentationCallState(state: .requesting(ringing), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
||||||
case let .active(_, _, keyVisualHash, _, _, _, _, _, _):
|
case let .active(_, _, keyVisualHash, _, _, _, _, _, _), let .switchedToConference(_, keyVisualHash, _):
|
||||||
self.callWasActive = true
|
self.callWasActive = true
|
||||||
if let callContextState = callContextState {
|
if let callContextState = callContextState {
|
||||||
switch callContextState.state {
|
switch callContextState.state {
|
||||||
@ -585,216 +585,233 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var conferenceCallData: (key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)?
|
||||||
|
var conferenceFromCallId: CallId?
|
||||||
|
switch sessionState.state {
|
||||||
|
case let .active(id, key, keyVisualHash, _, _, _, _, _, conferenceCall):
|
||||||
|
if let conferenceCall {
|
||||||
|
conferenceFromCallId = id
|
||||||
|
conferenceCallData = (key, keyVisualHash, conferenceCall)
|
||||||
|
}
|
||||||
|
case let .switchedToConference(key, keyVisualHash, conferenceCall):
|
||||||
|
conferenceCallData = (key, keyVisualHash, conferenceCall)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (key, keyVisualHash, conferenceCall) = conferenceCallData {
|
||||||
|
if self.conferenceCallDisposable == nil {
|
||||||
|
presentationState = PresentationCallState(state: .connecting(nil), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
||||||
|
|
||||||
|
self.conferenceCallDisposable = (self.context.engine.calls.getCurrentGroupCall(callId: conferenceCall.id, accessHash: conferenceCall.accessHash)
|
||||||
|
|> delay(sessionState.isOutgoing ? 0.0 : 2.0, queue: .mainQueue())
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||||
|
guard let self, let result else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let conferenceCall = PresentationGroupCallImpl(
|
||||||
|
accountContext: self.context,
|
||||||
|
audioSession: self.audioSession,
|
||||||
|
callKitIntegration: self.callKitIntegration,
|
||||||
|
getDeviceAccessData: self.getDeviceAccessData,
|
||||||
|
initialCall: EngineGroupCallDescription(
|
||||||
|
id: result.info.id,
|
||||||
|
accessHash: result.info.accessHash,
|
||||||
|
title: nil,
|
||||||
|
scheduleTimestamp: nil,
|
||||||
|
subscribedToScheduled: false,
|
||||||
|
isStream: false
|
||||||
|
),
|
||||||
|
internalId: CallSessionInternalId(),
|
||||||
|
peerId: nil,
|
||||||
|
isChannel: false,
|
||||||
|
invite: nil,
|
||||||
|
joinAsPeerId: nil,
|
||||||
|
isStream: false,
|
||||||
|
encryptionKey: (key, 1),
|
||||||
|
conferenceFromCallId: conferenceFromCallId,
|
||||||
|
isConference: true,
|
||||||
|
sharedAudioDevice: self.sharedAudioDevice
|
||||||
|
)
|
||||||
|
self.conferenceCall = conferenceCall
|
||||||
|
|
||||||
|
conferenceCall.setIsMuted(action: .muted(isPushToTalkActive: !self.isMutedValue))
|
||||||
|
|
||||||
|
let accountPeerId = conferenceCall.account.peerId
|
||||||
|
let videoEndpoints: Signal<(local: String?, remote: PresentationGroupCallRequestedVideo?), NoError> = conferenceCall.members
|
||||||
|
|> map { members -> (local: String?, remote: PresentationGroupCallRequestedVideo?) in
|
||||||
|
guard let members else {
|
||||||
|
return (nil, nil)
|
||||||
|
}
|
||||||
|
var local: String?
|
||||||
|
var remote: PresentationGroupCallRequestedVideo?
|
||||||
|
for participant in members.participants {
|
||||||
|
if let video = participant.requestedPresentationVideoChannel(minQuality: .thumbnail, maxQuality: .full) ?? participant.requestedVideoChannel(minQuality: .thumbnail, maxQuality: .full) {
|
||||||
|
if participant.peer.id == accountPeerId {
|
||||||
|
local = video.endpointId
|
||||||
|
} else {
|
||||||
|
if remote == nil {
|
||||||
|
remote = video
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (local, remote)
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||||
|
return lhs == rhs
|
||||||
|
})
|
||||||
|
|
||||||
|
let remoteIsConnectedAggregated = combineLatest(queue: .mainQueue(),
|
||||||
|
self.remoteConferenceIsConnected.get(),
|
||||||
|
conferenceCall.hasActiveIncomingData
|
||||||
|
)
|
||||||
|
|> map { remoteConferenceIsConnected, hasActiveIncomingData -> Bool in
|
||||||
|
//return remoteConferenceIsConnected || hasActiveIncomingData
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
var startTimestamp: Double?
|
||||||
|
self.ongoingContextStateDisposable = (combineLatest(queue: .mainQueue(),
|
||||||
|
conferenceCall.state,
|
||||||
|
videoEndpoints,
|
||||||
|
conferenceCall.signalBars,
|
||||||
|
conferenceCall.isFailed,
|
||||||
|
remoteIsConnectedAggregated
|
||||||
|
)
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] callState, videoEndpoints, signalBars, isFailed, remoteIsConnectedAggregated in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mappedLocalVideoState: PresentationCallState.VideoState = .inactive
|
||||||
|
var mappedRemoteVideoState: PresentationCallState.RemoteVideoState = .inactive
|
||||||
|
|
||||||
|
if let local = videoEndpoints.local {
|
||||||
|
mappedLocalVideoState = .active(isScreencast: false, endpointId: local)
|
||||||
|
}
|
||||||
|
if let remote = videoEndpoints.remote {
|
||||||
|
mappedRemoteVideoState = .active(endpointId: remote.endpointId)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.localVideoEndpointId = videoEndpoints.local
|
||||||
|
self.remoteVideoEndpointId = videoEndpoints.remote?.endpointId
|
||||||
|
|
||||||
|
if let conferenceCall = self.conferenceCall {
|
||||||
|
var requestedVideo: [PresentationGroupCallRequestedVideo] = []
|
||||||
|
if let remote = videoEndpoints.remote {
|
||||||
|
requestedVideo.append(remote)
|
||||||
|
}
|
||||||
|
conferenceCall.setRequestedVideoList(items: requestedVideo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isConnected = false
|
||||||
|
let mappedState: PresentationCallState.State
|
||||||
|
if isFailed {
|
||||||
|
mappedState = .terminating(.error(.disconnected))
|
||||||
|
} else {
|
||||||
|
switch callState.networkState {
|
||||||
|
case .connecting:
|
||||||
|
mappedState = .connecting(keyVisualHash)
|
||||||
|
case .connected:
|
||||||
|
isConnected = true
|
||||||
|
if remoteIsConnectedAggregated {
|
||||||
|
let timestamp = startTimestamp ?? CFAbsoluteTimeGetCurrent()
|
||||||
|
startTimestamp = timestamp
|
||||||
|
mappedState = .active(timestamp, signalBars, keyVisualHash)
|
||||||
|
} else {
|
||||||
|
mappedState = .connecting(keyVisualHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.updateConferenceIsConnected(isConnected: isConnected)
|
||||||
|
|
||||||
|
if !self.didDropCall && !self.droppedCall {
|
||||||
|
let presentationState = PresentationCallState(
|
||||||
|
state: mappedState,
|
||||||
|
videoState: mappedLocalVideoState,
|
||||||
|
remoteVideoState: mappedRemoteVideoState,
|
||||||
|
remoteAudioState: .active,
|
||||||
|
remoteBatteryLevel: .normal
|
||||||
|
)
|
||||||
|
self.statePromise.set(presentationState)
|
||||||
|
self.updateTone(presentationState, callContextState: nil, previous: nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.ongoingContextIsFailedDisposable = (conferenceCall.isFailed
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !self.didDropCall {
|
||||||
|
self.didDropCall = true
|
||||||
|
self.callSessionManager.drop(internalId: self.internalId, reason: .disconnect, debugLog: .single(nil))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.ongoingContextIsDroppedDisposable = (conferenceCall.canBeRemoved
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !self.didDropCall {
|
||||||
|
self.didDropCall = true
|
||||||
|
self.callSessionManager.drop(internalId: self.internalId, reason: .disconnect, debugLog: .single(nil))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var audioLevelId: UInt32?
|
||||||
|
let audioLevel = conferenceCall.audioLevels |> map { audioLevels -> Float in
|
||||||
|
var result: Float = 0
|
||||||
|
for item in audioLevels {
|
||||||
|
if let audioLevelId {
|
||||||
|
if item.1 == audioLevelId {
|
||||||
|
result = item.2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if item.1 != 0 {
|
||||||
|
audioLevelId = item.1
|
||||||
|
result = item.2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
self.audioLevelDisposable = (audioLevel
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] level in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.audioLevelPromise.set(level)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch sessionState.state {
|
switch sessionState.state {
|
||||||
case .requesting:
|
case .requesting:
|
||||||
if let _ = audioSessionControl {
|
if let _ = audioSessionControl {
|
||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
}
|
}
|
||||||
case let .active(id, key, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
|
case let .active(id, key, _, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
|
||||||
if let conferenceCall, self.conferenceCallDisposable == nil {
|
|
||||||
presentationState = PresentationCallState(state: .connecting(nil), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
|
||||||
|
|
||||||
self.conferenceCallDisposable = (self.context.engine.calls.getCurrentGroupCall(callId: conferenceCall.id, accessHash: conferenceCall.accessHash)
|
|
||||||
|> delay(sessionState.isOutgoing ? 0.0 : 2.0, queue: .mainQueue())
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
|
||||||
guard let self, let result else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let conferenceCall = PresentationGroupCallImpl(
|
|
||||||
accountContext: self.context,
|
|
||||||
audioSession: self.audioSession,
|
|
||||||
callKitIntegration: self.callKitIntegration,
|
|
||||||
getDeviceAccessData: self.getDeviceAccessData,
|
|
||||||
initialCall: EngineGroupCallDescription(
|
|
||||||
id: result.info.id,
|
|
||||||
accessHash: result.info.accessHash,
|
|
||||||
title: nil,
|
|
||||||
scheduleTimestamp: nil,
|
|
||||||
subscribedToScheduled: false,
|
|
||||||
isStream: false
|
|
||||||
),
|
|
||||||
internalId: CallSessionInternalId(),
|
|
||||||
peerId: nil,
|
|
||||||
isChannel: false,
|
|
||||||
invite: nil,
|
|
||||||
joinAsPeerId: nil,
|
|
||||||
isStream: false,
|
|
||||||
encryptionKey: key,
|
|
||||||
conferenceFromCallId: id,
|
|
||||||
isConference: true,
|
|
||||||
sharedAudioDevice: self.sharedAudioDevice
|
|
||||||
)
|
|
||||||
self.conferenceCall = conferenceCall
|
|
||||||
|
|
||||||
conferenceCall.setIsMuted(action: .muted(isPushToTalkActive: !self.isMutedValue))
|
|
||||||
|
|
||||||
let accountPeerId = conferenceCall.account.peerId
|
|
||||||
let videoEndpoints: Signal<(local: String?, remote: PresentationGroupCallRequestedVideo?), NoError> = conferenceCall.members
|
|
||||||
|> map { members -> (local: String?, remote: PresentationGroupCallRequestedVideo?) in
|
|
||||||
guard let members else {
|
|
||||||
return (nil, nil)
|
|
||||||
}
|
|
||||||
var local: String?
|
|
||||||
var remote: PresentationGroupCallRequestedVideo?
|
|
||||||
for participant in members.participants {
|
|
||||||
if let video = participant.requestedPresentationVideoChannel(minQuality: .thumbnail, maxQuality: .full) ?? participant.requestedVideoChannel(minQuality: .thumbnail, maxQuality: .full) {
|
|
||||||
if participant.peer.id == accountPeerId {
|
|
||||||
local = video.endpointId
|
|
||||||
} else {
|
|
||||||
if remote == nil {
|
|
||||||
remote = video
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (local, remote)
|
|
||||||
}
|
|
||||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
|
||||||
return lhs == rhs
|
|
||||||
})
|
|
||||||
|
|
||||||
let remoteIsConnectedAggregated = combineLatest(queue: .mainQueue(),
|
|
||||||
self.remoteConferenceIsConnected.get(),
|
|
||||||
conferenceCall.hasActiveIncomingData
|
|
||||||
)
|
|
||||||
|> map { remoteConferenceIsConnected, hasActiveIncomingData -> Bool in
|
|
||||||
return remoteConferenceIsConnected || hasActiveIncomingData
|
|
||||||
}
|
|
||||||
|> distinctUntilChanged
|
|
||||||
|
|
||||||
var startTimestamp: Double?
|
|
||||||
self.ongoingContextStateDisposable = (combineLatest(queue: .mainQueue(),
|
|
||||||
conferenceCall.state,
|
|
||||||
videoEndpoints,
|
|
||||||
conferenceCall.signalBars,
|
|
||||||
conferenceCall.isFailed,
|
|
||||||
remoteIsConnectedAggregated
|
|
||||||
)
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] callState, videoEndpoints, signalBars, isFailed, remoteIsConnectedAggregated in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var mappedLocalVideoState: PresentationCallState.VideoState = .inactive
|
|
||||||
var mappedRemoteVideoState: PresentationCallState.RemoteVideoState = .inactive
|
|
||||||
|
|
||||||
if let local = videoEndpoints.local {
|
|
||||||
mappedLocalVideoState = .active(isScreencast: false, endpointId: local)
|
|
||||||
}
|
|
||||||
if let remote = videoEndpoints.remote {
|
|
||||||
mappedRemoteVideoState = .active(endpointId: remote.endpointId)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.localVideoEndpointId = videoEndpoints.local
|
|
||||||
self.remoteVideoEndpointId = videoEndpoints.remote?.endpointId
|
|
||||||
|
|
||||||
if let conferenceCall = self.conferenceCall {
|
|
||||||
var requestedVideo: [PresentationGroupCallRequestedVideo] = []
|
|
||||||
if let remote = videoEndpoints.remote {
|
|
||||||
requestedVideo.append(remote)
|
|
||||||
}
|
|
||||||
conferenceCall.setRequestedVideoList(items: requestedVideo)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isConnected = false
|
|
||||||
let mappedState: PresentationCallState.State
|
|
||||||
if isFailed {
|
|
||||||
mappedState = .terminating(.error(.disconnected))
|
|
||||||
} else {
|
|
||||||
switch callState.networkState {
|
|
||||||
case .connecting:
|
|
||||||
mappedState = .connecting(keyVisualHash)
|
|
||||||
case .connected:
|
|
||||||
isConnected = true
|
|
||||||
if remoteIsConnectedAggregated {
|
|
||||||
let timestamp = startTimestamp ?? CFAbsoluteTimeGetCurrent()
|
|
||||||
startTimestamp = timestamp
|
|
||||||
mappedState = .active(timestamp, signalBars, keyVisualHash)
|
|
||||||
} else {
|
|
||||||
mappedState = .connecting(keyVisualHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.updateConferenceIsConnected(isConnected: isConnected)
|
|
||||||
|
|
||||||
if !self.didDropCall && !self.droppedCall {
|
|
||||||
let presentationState = PresentationCallState(
|
|
||||||
state: mappedState,
|
|
||||||
videoState: mappedLocalVideoState,
|
|
||||||
remoteVideoState: mappedRemoteVideoState,
|
|
||||||
remoteAudioState: .active,
|
|
||||||
remoteBatteryLevel: .normal
|
|
||||||
)
|
|
||||||
self.statePromise.set(presentationState)
|
|
||||||
self.updateTone(presentationState, callContextState: nil, previous: nil)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.ongoingContextIsFailedDisposable = (conferenceCall.isFailed
|
|
||||||
|> filter { $0 }
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] _ in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !self.didDropCall {
|
|
||||||
self.didDropCall = true
|
|
||||||
self.callSessionManager.drop(internalId: self.internalId, reason: .disconnect, debugLog: .single(nil))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.ongoingContextIsDroppedDisposable = (conferenceCall.canBeRemoved
|
|
||||||
|> filter { $0 }
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] _ in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !self.didDropCall {
|
|
||||||
self.didDropCall = true
|
|
||||||
self.callSessionManager.drop(internalId: self.internalId, reason: .disconnect, debugLog: .single(nil))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var audioLevelId: UInt32?
|
|
||||||
let audioLevel = conferenceCall.audioLevels |> map { audioLevels -> Float in
|
|
||||||
var result: Float = 0
|
|
||||||
for item in audioLevels {
|
|
||||||
if let audioLevelId {
|
|
||||||
if item.1 == audioLevelId {
|
|
||||||
result = item.2
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if item.1 != 0 {
|
|
||||||
audioLevelId = item.1
|
|
||||||
result = item.2
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
self.audioLevelDisposable = (audioLevel
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] level in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.audioLevelPromise.set(level)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if conferenceCall == nil, self.isExpectedToBeConference {
|
if conferenceCall == nil, self.isExpectedToBeConference {
|
||||||
self.createConferenceIfPossible()
|
self.createConferenceIfPossible()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
|
|
||||||
if self.isExpectedToBeConference {
|
if self.isExpectedToBeConference || conferenceCallData != nil {
|
||||||
if sessionState.isOutgoing {
|
if sessionState.isOutgoing {
|
||||||
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
||||||
}
|
}
|
||||||
@ -861,6 +878,8 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case .switchedToConference:
|
||||||
|
self.audioSessionShouldBeActive.set(true)
|
||||||
case let .terminated(_, _, options):
|
case let .terminated(_, _, options):
|
||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
if wasActive {
|
if wasActive {
|
||||||
@ -1093,9 +1112,9 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func sendConferenceSignalingMessage(dict: [String: Any]) {
|
private func sendConferenceSignalingMessage(dict: [String: Any]) {
|
||||||
if let data = try? JSONSerialization.data(withJSONObject: dict) {
|
/*if let data = try? JSONSerialization.data(withJSONObject: dict) {
|
||||||
self.context.account.callSessionManager.sendSignalingData(internalId: self.internalId, data: data)
|
self.context.account.callSessionManager.sendSignalingData(internalId: self.internalId, data: data)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateIsAudioSessionActive(_ value: Bool) {
|
private func updateIsAudioSessionActive(_ value: Bool) {
|
||||||
@ -1272,6 +1291,32 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.videoCapturer?.setIsVideoEnabled(!isPaused)
|
self.videoCapturer?.setIsVideoEnabled(!isPaused)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func requestAddToConference(peerId: EnginePeer.Id) -> Disposable {
|
||||||
|
var conferenceCall: (conference: GroupCallReference, encryptionKey: Data)?
|
||||||
|
if let sessionState = self.sessionState {
|
||||||
|
switch sessionState.state {
|
||||||
|
case let .active(_, key, _, _, _, _, _, _, conferenceCallValue):
|
||||||
|
if let conferenceCallValue {
|
||||||
|
conferenceCall = (conferenceCallValue, key)
|
||||||
|
}
|
||||||
|
case let .switchedToConference(key, _, conferenceCallValue):
|
||||||
|
conferenceCall = (conferenceCallValue, key)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard let conferenceCall else {
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
|
return (self.callSessionManager.request(peerId: peerId, isVideo: false, enableVideo: true, conferenceCall: conferenceCall)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak self] requestedInternalId in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = self
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
||||||
guard self.currentAudioOutputValue != output else {
|
guard self.currentAudioOutputValue != output else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -536,7 +536,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
|> mapToSignal { areVideoCallsAvailable -> Signal<CallSessionInternalId, NoError> in
|
|> mapToSignal { areVideoCallsAvailable -> Signal<CallSessionInternalId, NoError> in
|
||||||
let isVideoPossible: Bool = areVideoCallsAvailable
|
let isVideoPossible: Bool = areVideoCallsAvailable
|
||||||
|
|
||||||
return context.account.callSessionManager.request(peerId: peerId, isVideo: isVideo, enableVideo: isVideoPossible, internalId: internalId)
|
return context.account.callSessionManager.request(peerId: peerId, isVideo: isVideo, enableVideo: isVideoPossible, conferenceCall: nil, internalId: internalId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (combineLatest(queue: .mainQueue(), request, networkType |> take(1), context.account.postbox.peerView(id: peerId) |> map { peerView -> Bool in
|
return (combineLatest(queue: .mainQueue(), request, networkType |> take(1), context.account.postbox.peerView(id: peerId) |> map { peerView -> Bool in
|
||||||
|
|||||||
@ -865,7 +865,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
private var screencastStateDisposable: Disposable?
|
private var screencastStateDisposable: Disposable?
|
||||||
|
|
||||||
public let isStream: Bool
|
public let isStream: Bool
|
||||||
private let encryptionKey: Data?
|
private let encryptionKey: (key: Data, fingerprint: Int64)?
|
||||||
private let sharedAudioDevice: OngoingCallContext.AudioDevice?
|
private let sharedAudioDevice: OngoingCallContext.AudioDevice?
|
||||||
|
|
||||||
private let conferenceFromCallId: CallId?
|
private let conferenceFromCallId: CallId?
|
||||||
@ -885,7 +885,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
invite: String?,
|
invite: String?,
|
||||||
joinAsPeerId: EnginePeer.Id?,
|
joinAsPeerId: EnginePeer.Id?,
|
||||||
isStream: Bool,
|
isStream: Bool,
|
||||||
encryptionKey: Data?,
|
encryptionKey: (key: Data, fingerprint: Int64)?,
|
||||||
conferenceFromCallId: CallId?,
|
conferenceFromCallId: CallId?,
|
||||||
isConference: Bool,
|
isConference: Bool,
|
||||||
sharedAudioDevice: OngoingCallContext.AudioDevice?
|
sharedAudioDevice: OngoingCallContext.AudioDevice?
|
||||||
@ -1711,16 +1711,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var encryptionKey: Data?
|
var encryptionKey: Data?
|
||||||
encryptionKey = self.encryptionKey
|
encryptionKey = self.encryptionKey?.key
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
if encryptionKey == nil {
|
|
||||||
encryptionKey = Data(count: 256)
|
|
||||||
}
|
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
encryptionKey = nil
|
encryptionKey = nil
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
genericCallContext = .call(OngoingGroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in
|
genericCallContext = .call(OngoingGroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
@ -1860,7 +1854,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
preferMuted: true,
|
preferMuted: true,
|
||||||
joinPayload: joinPayload,
|
joinPayload: joinPayload,
|
||||||
peerAdminIds: peerAdminIds,
|
peerAdminIds: peerAdminIds,
|
||||||
inviteHash: strongSelf.invite
|
inviteHash: strongSelf.invite,
|
||||||
|
keyFingerprint: strongSelf.encryptionKey?.fingerprint
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue).start(next: { joinCallResult in
|
|> deliverOnMainQueue).start(next: { joinCallResult in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|||||||
@ -126,7 +126,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
|
|||||||
|
|
||||||
func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
|
func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
|
||||||
switch messsage {
|
switch messsage {
|
||||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
let chatPeerId = messagePeerId
|
let chatPeerId = messagePeerId
|
||||||
return chatPeerId.peerId
|
return chatPeerId.peerId
|
||||||
case let .messageEmpty(_, _, peerId):
|
case let .messageEmpty(_, _, peerId):
|
||||||
@ -142,7 +142,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
|
|||||||
|
|
||||||
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||||
switch message {
|
switch message {
|
||||||
case let .message(_, _, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, viaBusinessBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, viaBusinessBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
let peerId: PeerId = chatPeerId.peerId
|
let peerId: PeerId = chatPeerId.peerId
|
||||||
|
|
||||||
var result = [peerId]
|
var result = [peerId]
|
||||||
@ -270,7 +270,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
|||||||
|
|
||||||
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? {
|
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? {
|
||||||
switch message {
|
switch message {
|
||||||
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
if let replyTo = replyTo {
|
if let replyTo = replyTo {
|
||||||
let peerId: PeerId = chatPeerId.peerId
|
let peerId: PeerId = chatPeerId.peerId
|
||||||
|
|
||||||
@ -654,7 +654,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
|
|||||||
extension StoreMessage {
|
extension StoreMessage {
|
||||||
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
|
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
|
||||||
switch apiMessage {
|
switch apiMessage {
|
||||||
case let .message(flags, flags2, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId, messageEffectId, factCheck):
|
case let .message(flags, flags2, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId, messageEffectId, factCheck, _):
|
||||||
var attributes: [MessageAttribute] = []
|
var attributes: [MessageAttribute] = []
|
||||||
|
|
||||||
if (flags2 & (1 << 4)) != 0 {
|
if (flags2 & (1 << 4)) != 0 {
|
||||||
|
|||||||
@ -200,6 +200,8 @@ extension PhoneCallDiscardReason {
|
|||||||
self = .hangup
|
self = .hangup
|
||||||
case .phoneCallDiscardReasonMissed:
|
case .phoneCallDiscardReasonMissed:
|
||||||
self = .missed
|
self = .missed
|
||||||
|
case .phoneCallDiscardReasonAllowGroupCall:
|
||||||
|
self = .hangup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,19 +134,22 @@ public final class AccountStateManager {
|
|||||||
public let timestamp: Int32
|
public let timestamp: Int32
|
||||||
public let peer: EnginePeer
|
public let peer: EnginePeer
|
||||||
public let isVideo: Bool
|
public let isVideo: Bool
|
||||||
|
public let isConference: Bool
|
||||||
|
|
||||||
init(
|
init(
|
||||||
callId: Int64,
|
callId: Int64,
|
||||||
callAccessHash: Int64,
|
callAccessHash: Int64,
|
||||||
timestamp: Int32,
|
timestamp: Int32,
|
||||||
peer: EnginePeer,
|
peer: EnginePeer,
|
||||||
isVideo: Bool
|
isVideo: Bool,
|
||||||
|
isConference: Bool
|
||||||
) {
|
) {
|
||||||
self.callId = callId
|
self.callId = callId
|
||||||
self.callAccessHash = callAccessHash
|
self.callAccessHash = callAccessHash
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.isVideo = isVideo
|
self.isVideo = isVideo
|
||||||
|
self.isConference = isConference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2160,7 +2163,7 @@ public final class AccountStateManager {
|
|||||||
switch update {
|
switch update {
|
||||||
case let .updatePhoneCall(phoneCall):
|
case let .updatePhoneCall(phoneCall):
|
||||||
switch phoneCall {
|
switch phoneCall {
|
||||||
case let .phoneCallRequested(flags, id, accessHash, date, adminId, _, _, _):
|
case let .phoneCallRequested(flags, id, accessHash, date, adminId, _, _, _, conferenceCall):
|
||||||
guard let peer = peers.first(where: { $0.id == PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)) }) else {
|
guard let peer = peers.first(where: { $0.id == PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)) }) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -2169,7 +2172,8 @@ public final class AccountStateManager {
|
|||||||
callAccessHash: accessHash,
|
callAccessHash: accessHash,
|
||||||
timestamp: date,
|
timestamp: date,
|
||||||
peer: EnginePeer(peer),
|
peer: EnginePeer(peer),
|
||||||
isVideo: (flags & (1 << 6)) != 0
|
isVideo: (flags & (1 << 6)) != 0,
|
||||||
|
isConference: conferenceCall != nil
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -104,7 +104,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||||||
var updatedTimestamp: Int32?
|
var updatedTimestamp: Int32?
|
||||||
if let apiMessage = apiMessage {
|
if let apiMessage = apiMessage {
|
||||||
switch apiMessage {
|
switch apiMessage {
|
||||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
updatedTimestamp = date
|
updatedTimestamp = date
|
||||||
case .messageEmpty:
|
case .messageEmpty:
|
||||||
break
|
break
|
||||||
@ -400,7 +400,7 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
|
|||||||
} else if let message = messages.first, let apiMessage = result.messages.first {
|
} else if let message = messages.first, let apiMessage = result.messages.first {
|
||||||
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
||||||
namespace = Namespaces.Message.ScheduledCloud
|
namespace = Namespaces.Message.ScheduledCloud
|
||||||
} else if let apiMessage = result.messages.first, case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage, (flags2 & (1 << 4)) != 0 {
|
} else if let apiMessage = result.messages.first, case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage, (flags2 & (1 << 4)) != 0 {
|
||||||
namespace = Namespaces.Message.ScheduledCloud
|
namespace = Namespaces.Message.ScheduledCloud
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,32 +73,35 @@ extension GroupCallReference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum CallSessionInternalState {
|
enum CallSessionInternalState {
|
||||||
case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data, versions: [String])
|
case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data, versions: [String], conferenceCall: GroupCallReference?)
|
||||||
case accepting(id: Int64, accessHash: Int64, gAHash: Data, b: Data, disposable: Disposable)
|
case accepting(id: Int64, accessHash: Int64, gAHash: Data, b: Data, conferenceCall: GroupCallReference?, disposable: Disposable)
|
||||||
case awaitingConfirmation(id: Int64, accessHash: Int64, gAHash: Data, b: Data, config: SecretChatEncryptionConfig)
|
case awaitingConfirmation(id: Int64, accessHash: Int64, gAHash: Data, b: Data, config: SecretChatEncryptionConfig)
|
||||||
case requesting(a: Data, disposable: Disposable)
|
case requesting(a: Data, conferenceCall: GroupCallReference?, disposable: Disposable)
|
||||||
case requested(id: Int64, accessHash: Int64, a: Data, gA: Data, config: SecretChatEncryptionConfig, remoteConfirmationTimestamp: Int32?)
|
case requested(id: Int64, accessHash: Int64, a: Data, gA: Data, config: SecretChatEncryptionConfig, remoteConfirmationTimestamp: Int32?, conferenceCall: GroupCallReference?)
|
||||||
case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: Data, disposable: Disposable)
|
case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: Data, conferenceCall: GroupCallReference?, disposable: Disposable)
|
||||||
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
|
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
|
||||||
|
case switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
|
||||||
case dropping(reason: CallSessionTerminationReason, disposable: Disposable)
|
case dropping(reason: CallSessionTerminationReason, disposable: Disposable)
|
||||||
case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool)
|
case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool)
|
||||||
|
|
||||||
var stableId: Int64? {
|
var stableId: Int64? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .ringing(id, _, _, _, _):
|
case let .ringing(id, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case let .accepting(id, _, _, _, _):
|
case let .accepting(id, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case let .awaitingConfirmation(id, _, _, _, _):
|
case let .awaitingConfirmation(id, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case .requesting:
|
case .requesting:
|
||||||
return nil
|
return nil
|
||||||
case let .requested(id, _, _, _, _, _):
|
case let .requested(id, _, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case let .confirming(id, _, _, _, _, _):
|
case let .confirming(id, _, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case let .active(id, _, _, _, _, _, _, _, _, _, _, _):
|
case let .active(id, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
|
case .switchedToConference:
|
||||||
|
return nil
|
||||||
case .dropping:
|
case .dropping:
|
||||||
return nil
|
return nil
|
||||||
case let .terminated(id, _, _, _, _):
|
case let .terminated(id, _, _, _, _):
|
||||||
@ -161,8 +164,9 @@ public struct CallTerminationOptions: OptionSet {
|
|||||||
public enum CallSessionState {
|
public enum CallSessionState {
|
||||||
case ringing
|
case ringing
|
||||||
case accepting
|
case accepting
|
||||||
case requesting(ringing: Bool)
|
case requesting(ringing: Bool, conferenceCall: GroupCallReference?)
|
||||||
case active(id: CallId, key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
|
case active(id: CallId, key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
|
||||||
|
case switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
|
||||||
case dropping(reason: CallSessionTerminationReason)
|
case dropping(reason: CallSessionTerminationReason)
|
||||||
case terminated(id: CallId?, reason: CallSessionTerminationReason, options: CallTerminationOptions)
|
case terminated(id: CallId?, reason: CallSessionTerminationReason, options: CallTerminationOptions)
|
||||||
|
|
||||||
@ -172,12 +176,12 @@ public enum CallSessionState {
|
|||||||
self = .ringing
|
self = .ringing
|
||||||
case .accepting, .awaitingConfirmation:
|
case .accepting, .awaitingConfirmation:
|
||||||
self = .accepting
|
self = .accepting
|
||||||
case .requesting:
|
case let .requesting(_, conferenceCall, _):
|
||||||
self = .requesting(ringing: false)
|
self = .requesting(ringing: false, conferenceCall: conferenceCall)
|
||||||
case .confirming:
|
case let .confirming(_, _, _, _, _, conferenceCall, _):
|
||||||
self = .requesting(ringing: true)
|
self = .requesting(ringing: true, conferenceCall: conferenceCall)
|
||||||
case let .requested(_, _, _, _, _, remoteConfirmationTimestamp):
|
case let .requested(_, _, _, _, _, remoteConfirmationTimestamp, conferenceCall):
|
||||||
self = .requesting(ringing: remoteConfirmationTimestamp != nil)
|
self = .requesting(ringing: remoteConfirmationTimestamp != nil, conferenceCall: conferenceCall)
|
||||||
case let .active(id, accessHash, _, key, _, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
|
case let .active(id, accessHash, _, key, _, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
|
||||||
self = .active(id: CallId(id: id, accessHash: accessHash), key: key, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall)
|
self = .active(id: CallId(id: id, accessHash: accessHash), key: key, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall)
|
||||||
case let .dropping(reason, _):
|
case let .dropping(reason, _):
|
||||||
@ -197,6 +201,8 @@ public enum CallSessionState {
|
|||||||
callId = nil
|
callId = nil
|
||||||
}
|
}
|
||||||
self = .terminated(id: callId, reason: reason, options: options)
|
self = .terminated(id: callId, reason: reason, options: options)
|
||||||
|
case let .switchedToConference(key, keyVisualHash, conferenceCall):
|
||||||
|
self = .switchedToConference(key: key, keyVisualHash: keyVisualHash, conferenceCall: conferenceCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,6 +336,7 @@ private final class CallSessionContext {
|
|||||||
let isOutgoing: Bool
|
let isOutgoing: Bool
|
||||||
var type: CallSession.CallType
|
var type: CallSession.CallType
|
||||||
var isVideoPossible: Bool
|
var isVideoPossible: Bool
|
||||||
|
let pendingConference: (conference: GroupCallReference, encryptionKey: Data)?
|
||||||
var state: CallSessionInternalState
|
var state: CallSessionInternalState
|
||||||
let subscribers = Bag<(CallSession) -> Void>()
|
let subscribers = Bag<(CallSession) -> Void>()
|
||||||
var signalingReceiver: (([Data]) -> Void)?
|
var signalingReceiver: (([Data]) -> Void)?
|
||||||
@ -346,11 +353,12 @@ private final class CallSessionContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(peerId: PeerId, isOutgoing: Bool, type: CallSession.CallType, isVideoPossible: Bool, state: CallSessionInternalState) {
|
init(peerId: PeerId, isOutgoing: Bool, type: CallSession.CallType, isVideoPossible: Bool, pendingConference: (conference: GroupCallReference, encryptionKey: Data)?, state: CallSessionInternalState) {
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.isOutgoing = isOutgoing
|
self.isOutgoing = isOutgoing
|
||||||
self.type = type
|
self.type = type
|
||||||
self.isVideoPossible = isVideoPossible
|
self.isVideoPossible = isVideoPossible
|
||||||
|
self.pendingConference = pendingConference
|
||||||
self.state = state
|
self.state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,7 +574,7 @@ private final class CallSessionManagerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addIncoming(peerId: PeerId, stableId: CallSessionStableId, accessHash: Int64, timestamp: Int32, gAHash: Data, versions: [String], isVideo: Bool) -> CallSessionInternalId? {
|
private func addIncoming(peerId: PeerId, stableId: CallSessionStableId, accessHash: Int64, timestamp: Int32, gAHash: Data, versions: [String], isVideo: Bool, conferenceCall: GroupCallReference?) -> CallSessionInternalId? {
|
||||||
if self.contextIdByStableId[stableId] != nil {
|
if self.contextIdByStableId[stableId] != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -582,7 +590,7 @@ private final class CallSessionManagerContext {
|
|||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
let internalId = CallSessionManager.getStableIncomingUUID(stableId: stableId)
|
let internalId = CallSessionManager.getStableIncomingUUID(stableId: stableId)
|
||||||
let context = CallSessionContext(peerId: peerId, isOutgoing: false, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions))
|
let context = CallSessionContext(peerId: peerId, isOutgoing: false, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, pendingConference: nil, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions, conferenceCall: conferenceCall))
|
||||||
self.contexts[internalId] = context
|
self.contexts[internalId] = context
|
||||||
let queue = self.queue
|
let queue = self.queue
|
||||||
|
|
||||||
@ -619,7 +627,7 @@ private final class CallSessionManagerContext {
|
|||||||
var wasRinging = false
|
var wasRinging = false
|
||||||
let isVideo = context.type == .video
|
let isVideo = context.type == .video
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case let .ringing(id, accessHash, _, _, _):
|
case let .ringing(id, accessHash, _, _, _, _):
|
||||||
wasRinging = true
|
wasRinging = true
|
||||||
let internalReason: DropCallSessionReason
|
let internalReason: DropCallSessionReason
|
||||||
switch reason {
|
switch reason {
|
||||||
@ -633,7 +641,7 @@ private final class CallSessionManagerContext {
|
|||||||
internalReason = .missed
|
internalReason = .missed
|
||||||
}
|
}
|
||||||
dropData = (id, accessHash, internalReason)
|
dropData = (id, accessHash, internalReason)
|
||||||
case let .accepting(id, accessHash, _, _, disposable):
|
case let .accepting(id, accessHash, _, _, _, disposable):
|
||||||
dropData = (id, accessHash, .abort)
|
dropData = (id, accessHash, .abort)
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _, _, _, _):
|
case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _, _, _, _):
|
||||||
@ -648,14 +656,16 @@ private final class CallSessionManagerContext {
|
|||||||
internalReason = .missed
|
internalReason = .missed
|
||||||
}
|
}
|
||||||
dropData = (id, accessHash, internalReason)
|
dropData = (id, accessHash, internalReason)
|
||||||
|
case .switchedToConference:
|
||||||
|
break
|
||||||
case .dropping, .terminated:
|
case .dropping, .terminated:
|
||||||
break
|
break
|
||||||
case let .awaitingConfirmation(id, accessHash, _, _, _):
|
case let .awaitingConfirmation(id, accessHash, _, _, _):
|
||||||
dropData = (id, accessHash, .abort)
|
dropData = (id, accessHash, .abort)
|
||||||
case let .confirming(id, accessHash, _, _, _, disposable):
|
case let .confirming(id, accessHash, _, _, _, _, disposable):
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
dropData = (id, accessHash, .abort)
|
dropData = (id, accessHash, .abort)
|
||||||
case let .requested(id, accessHash, _, _, _, _):
|
case let .requested(id, accessHash, _, _, _, _, _):
|
||||||
let internalReason: DropCallSessionReason
|
let internalReason: DropCallSessionReason
|
||||||
switch reason {
|
switch reason {
|
||||||
case .busy, .hangUp:
|
case .busy, .hangUp:
|
||||||
@ -666,7 +676,7 @@ private final class CallSessionManagerContext {
|
|||||||
internalReason = .missed
|
internalReason = .missed
|
||||||
}
|
}
|
||||||
dropData = (id, accessHash, internalReason)
|
dropData = (id, accessHash, internalReason)
|
||||||
case let .requesting(_, disposable):
|
case let .requesting(_, _, disposable):
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
context.state = .terminated(id: nil, accessHash: nil, reason: .ended(.hungUp), reportRating: false, sendDebugLogs: false)
|
context.state = .terminated(id: nil, accessHash: nil, reason: .ended(.hungUp), reportRating: false, sendDebugLogs: false)
|
||||||
self.contextUpdated(internalId: internalId)
|
self.contextUpdated(internalId: internalId)
|
||||||
@ -689,6 +699,8 @@ private final class CallSessionManagerContext {
|
|||||||
mappedReason = .ended(.hungUp)
|
mappedReason = .ended(.hungUp)
|
||||||
case .missed:
|
case .missed:
|
||||||
mappedReason = .ended(.missed)
|
mappedReason = .ended(.missed)
|
||||||
|
case .switchToConference:
|
||||||
|
mappedReason = .ended(.hungUp)
|
||||||
}
|
}
|
||||||
context.state = .dropping(reason: mappedReason, disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: reason)
|
context.state = .dropping(reason: mappedReason, disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: reason)
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in
|
|> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in
|
||||||
@ -729,6 +741,38 @@ private final class CallSessionManagerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dropToConference(internalId: CallSessionInternalId, encryptedGroupKey: Data) {
|
||||||
|
if let context = self.contexts[internalId] {
|
||||||
|
var dropData: (CallSessionStableId, Int64)?
|
||||||
|
let isVideo = context.type == .video
|
||||||
|
switch context.state {
|
||||||
|
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _):
|
||||||
|
dropData = (id, accessHash)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (id, accessHash) = dropData {
|
||||||
|
self.contextIdByStableId.removeValue(forKey: id)
|
||||||
|
context.state = .dropping(reason: .ended(.hungUp), disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: .switchToConference(encryptedGroupKey: encryptedGroupKey))
|
||||||
|
|> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let context = strongSelf.contexts[internalId] {
|
||||||
|
context.state = .terminated(id: id, accessHash: accessHash, reason: .ended(.hungUp), reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
|
strongSelf.contextUpdated(internalId: internalId)
|
||||||
|
if context.isEmpty {
|
||||||
|
strongSelf.contexts.removeValue(forKey: internalId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
self.contextUpdated(internalId: internalId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.contextUpdated(internalId: internalId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func dropAll() {
|
func dropAll() {
|
||||||
let contexts = self.contexts
|
let contexts = self.contexts
|
||||||
for (internalId, _) in contexts {
|
for (internalId, _) in contexts {
|
||||||
@ -739,9 +783,9 @@ private final class CallSessionManagerContext {
|
|||||||
func accept(internalId: CallSessionInternalId) {
|
func accept(internalId: CallSessionInternalId) {
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case let .ringing(id, accessHash, gAHash, b, _):
|
case let .ringing(id, accessHash, gAHash, b, _, conferenceCall):
|
||||||
let acceptVersions = self.versions.map({ $0.version })
|
let acceptVersions = self.versions.map({ $0.version })
|
||||||
context.state = .accepting(id: id, accessHash: accessHash, gAHash: gAHash, b: b, disposable: (acceptCallSession(accountPeerId: self.accountPeerId, postbox: self.postbox, network: self.network, stableId: id, accessHash: accessHash, b: b, maxLayer: self.maxLayer, versions: acceptVersions) |> deliverOn(self.queue)).start(next: { [weak self] result in
|
context.state = .accepting(id: id, accessHash: accessHash, gAHash: gAHash, b: b, conferenceCall: conferenceCall, disposable: (acceptCallSession(accountPeerId: self.accountPeerId, postbox: self.postbox, network: self.network, stableId: id, accessHash: accessHash, b: b, maxLayer: self.maxLayer, versions: acceptVersions) |> deliverOn(self.queue)).start(next: { [weak self] result in
|
||||||
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
||||||
if case .accepting = context.state {
|
if case .accepting = context.state {
|
||||||
switch result {
|
switch result {
|
||||||
@ -835,7 +879,7 @@ private final class CallSessionManagerContext {
|
|||||||
switch call {
|
switch call {
|
||||||
case .phoneCallEmpty:
|
case .phoneCallEmpty:
|
||||||
break
|
break
|
||||||
case let .phoneCallAccepted(_, id, _, _, _, _, gB, remoteProtocol):
|
case let .phoneCallAccepted(_, id, _, _, _, _, gB, remoteProtocol, conferenceCall):
|
||||||
let remoteVersions: [String]
|
let remoteVersions: [String]
|
||||||
switch remoteProtocol {
|
switch remoteProtocol {
|
||||||
case let .phoneCallProtocol(_, _, _, versions):
|
case let .phoneCallProtocol(_, _, _, versions):
|
||||||
@ -849,7 +893,7 @@ private final class CallSessionManagerContext {
|
|||||||
|
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case let .requested(_, accessHash, a, gA, config, _):
|
case let .requested(_, accessHash, a, gA, config, _, _):
|
||||||
let p = config.p.makeData()
|
let p = config.p.makeData()
|
||||||
if !MTCheckIsSafeGAOrB(self.network.encryptionProvider, gA, p) {
|
if !MTCheckIsSafeGAOrB(self.network.encryptionProvider, gA, p) {
|
||||||
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
||||||
@ -874,10 +918,14 @@ private final class CallSessionManagerContext {
|
|||||||
|
|
||||||
let keyVisualHash = MTSha256(key + gA)
|
let keyVisualHash = MTSha256(key + gA)
|
||||||
|
|
||||||
context.state = .confirming(id: id, accessHash: accessHash, key: key, keyId: keyId, keyVisualHash: keyVisualHash, disposable: (confirmCallSession(network: self.network, stableId: id, accessHash: accessHash, gA: gA, keyFingerprint: keyId, maxLayer: self.maxLayer, versions: selectedVersions) |> deliverOnMainQueue).start(next: { [weak self] updatedCall in
|
context.state = .confirming(id: id, accessHash: accessHash, key: key, keyId: keyId, keyVisualHash: keyVisualHash, conferenceCall: conferenceCall.flatMap(GroupCallReference.init), disposable: (confirmCallSession(network: self.network, stableId: id, accessHash: accessHash, gA: gA, keyFingerprint: keyId, maxLayer: self.maxLayer, versions: selectedVersions) |> deliverOnMainQueue).start(next: { [weak self] updatedCall in
|
||||||
if let strongSelf = self, let context = strongSelf.contexts[internalId], case .confirming = context.state {
|
if let strongSelf = self, let context = strongSelf.contexts[internalId], case .confirming = context.state {
|
||||||
if let updatedCall = updatedCall {
|
if let updatedCall = updatedCall {
|
||||||
strongSelf.updateSession(updatedCall, completion: { _ in })
|
strongSelf.updateSession(updatedCall, completion: { _ in })
|
||||||
|
|
||||||
|
if let pendingConference = context.pendingConference {
|
||||||
|
strongSelf.dropToConference(internalId: internalId, encryptedGroupKey: pendingConference.encryptionKey)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
strongSelf.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
strongSelf.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
||||||
}
|
}
|
||||||
@ -891,7 +939,8 @@ private final class CallSessionManagerContext {
|
|||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .phoneCallDiscarded(flags, id, reason, _):
|
case let .phoneCallDiscarded(flags, id, reason, _, conferenceCall):
|
||||||
|
let _ = conferenceCall
|
||||||
let reportRating = (flags & (1 << 2)) != 0
|
let reportRating = (flags & (1 << 2)) != 0
|
||||||
let sendDebugLogs = (flags & (1 << 3)) != 0
|
let sendDebugLogs = (flags & (1 << 3)) != 0
|
||||||
if let internalId = self.contextIdByStableId[id] {
|
if let internalId = self.contextIdByStableId[id] {
|
||||||
@ -899,47 +948,53 @@ private final class CallSessionManagerContext {
|
|||||||
let parsedReason: CallSessionTerminationReason
|
let parsedReason: CallSessionTerminationReason
|
||||||
if let reason = reason {
|
if let reason = reason {
|
||||||
switch reason {
|
switch reason {
|
||||||
case .phoneCallDiscardReasonBusy:
|
case .phoneCallDiscardReasonBusy:
|
||||||
parsedReason = .ended(.busy)
|
parsedReason = .ended(.busy)
|
||||||
case .phoneCallDiscardReasonDisconnect:
|
case .phoneCallDiscardReasonDisconnect:
|
||||||
parsedReason = .error(.disconnected)
|
parsedReason = .error(.disconnected)
|
||||||
case .phoneCallDiscardReasonHangup:
|
case .phoneCallDiscardReasonHangup:
|
||||||
parsedReason = .ended(.hungUp)
|
parsedReason = .ended(.hungUp)
|
||||||
case .phoneCallDiscardReasonMissed:
|
case .phoneCallDiscardReasonMissed:
|
||||||
parsedReason = .ended(.missed)
|
parsedReason = .ended(.missed)
|
||||||
|
case .phoneCallDiscardReasonAllowGroupCall:
|
||||||
|
parsedReason = .ended(.hungUp)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parsedReason = .ended(.hungUp)
|
parsedReason = .ended(.hungUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case let .accepting(id, accessHash, _, _, disposable):
|
case let .accepting(id, accessHash, _, _, _, disposable):
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
|
self.contextUpdated(internalId: internalId)
|
||||||
|
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, conferenceCall):
|
||||||
|
if let conferenceCall, case let .phoneCallDiscardReasonAllowGroupCall(encryptedGroupKey) = reason {
|
||||||
|
context.state = .switchedToConference(key: encryptedGroupKey.makeData(), keyVisualHash: MTSha256(encryptedGroupKey.makeData()), conferenceCall: conferenceCall)
|
||||||
|
} else {
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
self.contextUpdated(internalId: internalId)
|
}
|
||||||
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _):
|
self.contextUpdated(internalId: internalId)
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
case let .awaitingConfirmation(id, accessHash, _, _, _):
|
||||||
self.contextUpdated(internalId: internalId)
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
case let .awaitingConfirmation(id, accessHash, _, _, _):
|
self.contextUpdated(internalId: internalId)
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
case let .requested(id, accessHash, _, _, _, _, _):
|
||||||
self.contextUpdated(internalId: internalId)
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
case let .requested(id, accessHash, _, _, _, _):
|
self.contextUpdated(internalId: internalId)
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
case let .confirming(id, accessHash, _, _, _, _, disposable):
|
||||||
self.contextUpdated(internalId: internalId)
|
disposable.dispose()
|
||||||
case let .confirming(id, accessHash, _, _, _, disposable):
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
disposable.dispose()
|
self.contextUpdated(internalId: internalId)
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
case let .requesting(_, _, disposable):
|
||||||
self.contextUpdated(internalId: internalId)
|
disposable.dispose()
|
||||||
case let .requesting(_, disposable):
|
context.state = .terminated(id: nil, accessHash: nil, reason: parsedReason, reportRating: false, sendDebugLogs: false)
|
||||||
disposable.dispose()
|
self.contextUpdated(internalId: internalId)
|
||||||
context.state = .terminated(id: nil, accessHash: nil, reason: parsedReason, reportRating: false, sendDebugLogs: false)
|
case let .ringing(id, accessHash, _, _, _, _):
|
||||||
self.contextUpdated(internalId: internalId)
|
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
||||||
case let .ringing(id, accessHash, _, _, _):
|
self.ringingStatesUpdated()
|
||||||
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
|
self.contextUpdated(internalId: internalId)
|
||||||
self.ringingStatesUpdated()
|
case .dropping, .terminated, .switchedToConference:
|
||||||
self.contextUpdated(internalId: internalId)
|
break
|
||||||
case .dropping, .terminated:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//assertionFailure()
|
//assertionFailure()
|
||||||
@ -950,7 +1005,7 @@ private final class CallSessionManagerContext {
|
|||||||
if let internalId = self.contextIdByStableId[id] {
|
if let internalId = self.contextIdByStableId[id] {
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested:
|
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested, .switchedToConference:
|
||||||
break
|
break
|
||||||
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
|
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
|
||||||
if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) {
|
if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) {
|
||||||
@ -981,7 +1036,7 @@ private final class CallSessionManagerContext {
|
|||||||
} else {
|
} else {
|
||||||
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
|
||||||
}
|
}
|
||||||
case let .confirming(id, accessHash, key, keyId, keyVisualHash, _):
|
case let .confirming(id, accessHash, key, keyId, keyVisualHash, _, _):
|
||||||
switch callProtocol {
|
switch callProtocol {
|
||||||
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
||||||
if !versions.isEmpty {
|
if !versions.isEmpty {
|
||||||
@ -1007,7 +1062,7 @@ private final class CallSessionManagerContext {
|
|||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .phoneCallRequested(flags, id, accessHash, date, adminId, _, gAHash, requestedProtocol):
|
case let .phoneCallRequested(flags, id, accessHash, date, adminId, _, gAHash, requestedProtocol, conferenceCall):
|
||||||
let isVideo = (flags & (1 << 6)) != 0
|
let isVideo = (flags & (1 << 6)) != 0
|
||||||
let versions: [String]
|
let versions: [String]
|
||||||
switch requestedProtocol {
|
switch requestedProtocol {
|
||||||
@ -1015,7 +1070,7 @@ private final class CallSessionManagerContext {
|
|||||||
versions = libraryVersions
|
versions = libraryVersions
|
||||||
}
|
}
|
||||||
if self.contextIdByStableId[id] == nil {
|
if self.contextIdByStableId[id] == nil {
|
||||||
let internalId = self.addIncoming(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), stableId: id, accessHash: accessHash, timestamp: date, gAHash: gAHash.makeData(), versions: versions, isVideo: isVideo)
|
let internalId = self.addIncoming(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), stableId: id, accessHash: accessHash, timestamp: date, gAHash: gAHash.makeData(), versions: versions, isVideo: isVideo, conferenceCall: conferenceCall.flatMap(GroupCallReference.init))
|
||||||
if let internalId = internalId {
|
if let internalId = internalId {
|
||||||
var resultRingingStateValue: CallSessionRingingState?
|
var resultRingingStateValue: CallSessionRingingState?
|
||||||
for ringingState in self.ringingStatesValue() {
|
for ringingState in self.ringingStatesValue() {
|
||||||
@ -1032,13 +1087,13 @@ private final class CallSessionManagerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .phoneCallWaiting(_, id, _, _, _, _, _, receiveDate):
|
case let .phoneCallWaiting(_, id, _, _, _, _, _, receiveDate, conferenceCall):
|
||||||
if let internalId = self.contextIdByStableId[id] {
|
if let internalId = self.contextIdByStableId[id] {
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
switch context.state {
|
switch context.state {
|
||||||
case let .requested(id, accessHash, a, gA, config, remoteConfirmationTimestamp):
|
case let .requested(id, accessHash, a, gA, config, remoteConfirmationTimestamp, _):
|
||||||
if let receiveDate = receiveDate, remoteConfirmationTimestamp == nil {
|
if let receiveDate = receiveDate, remoteConfirmationTimestamp == nil {
|
||||||
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: receiveDate)
|
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: receiveDate, conferenceCall: conferenceCall.flatMap(GroupCallReference.init))
|
||||||
self.contextUpdated(internalId: internalId)
|
self.contextUpdated(internalId: internalId)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1101,17 +1156,17 @@ private final class CallSessionManagerContext {
|
|||||||
return (key, keyId, keyVisualHash)
|
return (key, keyId, keyVisualHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func request(peerId: PeerId, internalId: CallSessionInternalId, isVideo: Bool, enableVideo: Bool) -> CallSessionInternalId? {
|
func request(peerId: PeerId, internalId: CallSessionInternalId, isVideo: Bool, enableVideo: Bool, conferenceCall: (conference: GroupCallReference, encryptionKey: Data)?) -> CallSessionInternalId? {
|
||||||
let aBytes = malloc(256)!
|
let aBytes = malloc(256)!
|
||||||
let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self))
|
let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self))
|
||||||
let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free)
|
let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free)
|
||||||
if randomStatus == 0 {
|
if randomStatus == 0 {
|
||||||
self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, type: isVideo ? .video : .audio, isVideoPossible: enableVideo || isVideo, state: .requesting(a: a, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.filteredVersions(enableVideo: true), isVideo: isVideo) |> deliverOn(queue)).start(next: { [weak self] result in
|
self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, type: isVideo ? .video : .audio, isVideoPossible: enableVideo || isVideo, pendingConference: conferenceCall, state: .requesting(a: a, conferenceCall: conferenceCall?.conference, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.filteredVersions(enableVideo: true), isVideo: isVideo, conferenceCall: conferenceCall?.conference) |> deliverOn(queue)).start(next: { [weak self] result in
|
||||||
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
||||||
if case .requesting = context.state {
|
if case .requesting = context.state {
|
||||||
switch result {
|
switch result {
|
||||||
case let .success(id, accessHash, config, gA, remoteConfirmationTimestamp):
|
case let .success(id, accessHash, config, gA, remoteConfirmationTimestamp):
|
||||||
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: remoteConfirmationTimestamp)
|
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: remoteConfirmationTimestamp, conferenceCall: conferenceCall?.conference)
|
||||||
strongSelf.contextIdByStableId[id] = internalId
|
strongSelf.contextIdByStableId[id] = internalId
|
||||||
strongSelf.contextUpdated(internalId: internalId)
|
strongSelf.contextUpdated(internalId: internalId)
|
||||||
strongSelf.deliverCallSignalingData(id: id)
|
strongSelf.deliverCallSignalingData(id: id)
|
||||||
@ -1206,12 +1261,12 @@ public final class CallSessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func request(peerId: PeerId, isVideo: Bool, enableVideo: Bool, internalId: CallSessionInternalId = CallSessionInternalId()) -> Signal<CallSessionInternalId, NoError> {
|
public func request(peerId: PeerId, isVideo: Bool, enableVideo: Bool, conferenceCall: (conference: GroupCallReference, encryptionKey: Data)?, internalId: CallSessionInternalId = CallSessionInternalId()) -> Signal<CallSessionInternalId, NoError> {
|
||||||
return Signal { [weak self] subscriber in
|
return Signal { [weak self] subscriber in
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
self?.withContext { context in
|
self?.withContext { context in
|
||||||
if let internalId = context.request(peerId: peerId, internalId: internalId, isVideo: isVideo, enableVideo: enableVideo) {
|
if let internalId = context.request(peerId: peerId, internalId: internalId, isVideo: isVideo, enableVideo: enableVideo, conferenceCall: conferenceCall) {
|
||||||
subscriber.putNext(internalId)
|
subscriber.putNext(internalId)
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
}
|
}
|
||||||
@ -1358,7 +1413,7 @@ private enum RequestCallSessionResult {
|
|||||||
case failed(CallSessionError)
|
case failed(CallSessionError)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestCallSession(postbox: Postbox, network: Network, peerId: PeerId, a: Data, maxLayer: Int32, versions: [String], isVideo: Bool) -> Signal<RequestCallSessionResult, NoError> {
|
private func requestCallSession(postbox: Postbox, network: Network, peerId: PeerId, a: Data, maxLayer: Int32, versions: [String], isVideo: Bool, conferenceCall: GroupCallReference?) -> Signal<RequestCallSessionResult, NoError> {
|
||||||
return validatedEncryptionConfig(postbox: postbox, network: network)
|
return validatedEncryptionConfig(postbox: postbox, network: network)
|
||||||
|> mapToSignal { config -> Signal<RequestCallSessionResult, NoError> in
|
|> mapToSignal { config -> Signal<RequestCallSessionResult, NoError> in
|
||||||
return postbox.transaction { transaction -> Signal<RequestCallSessionResult, NoError> in
|
return postbox.transaction { transaction -> Signal<RequestCallSessionResult, NoError> in
|
||||||
@ -1378,15 +1433,18 @@ private func requestCallSession(postbox: Postbox, network: Network, peerId: Peer
|
|||||||
if isVideo {
|
if isVideo {
|
||||||
callFlags |= 1 << 0
|
callFlags |= 1 << 0
|
||||||
}
|
}
|
||||||
|
if conferenceCall != nil {
|
||||||
|
callFlags |= 1 << 1
|
||||||
|
}
|
||||||
|
|
||||||
return network.request(Api.functions.phone.requestCall(flags: callFlags, userId: inputUser, randomId: Int32(bitPattern: arc4random()), gAHash: Buffer(data: gAHash), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: minLayer, maxLayer: maxLayer, libraryVersions: versions)))
|
return network.request(Api.functions.phone.requestCall(flags: callFlags, userId: inputUser, conferenceCall: conferenceCall.flatMap { Api.InputGroupCall.inputGroupCall(id: $0.id, accessHash: $0.accessHash) }, randomId: Int32(bitPattern: arc4random()), gAHash: Buffer(data: gAHash), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: minLayer, maxLayer: maxLayer, libraryVersions: versions)))
|
||||||
|> map { result -> RequestCallSessionResult in
|
|> map { result -> RequestCallSessionResult in
|
||||||
switch result {
|
switch result {
|
||||||
case let .phoneCall(phoneCall, _):
|
case let .phoneCall(phoneCall, _):
|
||||||
switch phoneCall {
|
switch phoneCall {
|
||||||
case let .phoneCallRequested(_, id, accessHash, _, _, _, _, _):
|
case let .phoneCallRequested(_, id, accessHash, _, _, _, _, _, _):
|
||||||
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: nil)
|
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: nil)
|
||||||
case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate):
|
case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate, _):
|
||||||
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: receiveDate)
|
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: receiveDate)
|
||||||
default:
|
default:
|
||||||
return .failed(.generic)
|
return .failed(.generic)
|
||||||
@ -1439,23 +1497,26 @@ private enum DropCallSessionReason {
|
|||||||
case busy
|
case busy
|
||||||
case disconnect
|
case disconnect
|
||||||
case missed
|
case missed
|
||||||
|
case switchToConference(encryptedGroupKey: Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dropCallSession(network: Network, addUpdates: @escaping (Api.Updates) -> Void, stableId: CallSessionStableId, accessHash: Int64, isVideo: Bool, reason: DropCallSessionReason) -> Signal<(Bool, Bool), NoError> {
|
private func dropCallSession(network: Network, addUpdates: @escaping (Api.Updates) -> Void, stableId: CallSessionStableId, accessHash: Int64, isVideo: Bool, reason: DropCallSessionReason) -> Signal<(Bool, Bool), NoError> {
|
||||||
var mappedReason: Api.PhoneCallDiscardReason
|
var mappedReason: Api.PhoneCallDiscardReason
|
||||||
var duration: Int32 = 0
|
var duration: Int32 = 0
|
||||||
switch reason {
|
switch reason {
|
||||||
case .abort:
|
case .abort:
|
||||||
mappedReason = .phoneCallDiscardReasonHangup
|
mappedReason = .phoneCallDiscardReasonHangup
|
||||||
case let .hangUp(value):
|
case let .hangUp(value):
|
||||||
duration = value
|
duration = value
|
||||||
mappedReason = .phoneCallDiscardReasonHangup
|
mappedReason = .phoneCallDiscardReasonHangup
|
||||||
case .busy:
|
case .busy:
|
||||||
mappedReason = .phoneCallDiscardReasonBusy
|
mappedReason = .phoneCallDiscardReasonBusy
|
||||||
case .disconnect:
|
case .disconnect:
|
||||||
mappedReason = .phoneCallDiscardReasonDisconnect
|
mappedReason = .phoneCallDiscardReasonDisconnect
|
||||||
case .missed:
|
case .missed:
|
||||||
mappedReason = .phoneCallDiscardReasonMissed
|
mappedReason = .phoneCallDiscardReasonMissed
|
||||||
|
case let .switchToConference(encryptedGroupKey):
|
||||||
|
mappedReason = .phoneCallDiscardReasonAllowGroupCall(encryptedKey: Buffer(data: encryptedGroupKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
var callFlags: Int32 = 0
|
var callFlags: Int32 = 0
|
||||||
@ -1478,7 +1539,7 @@ private func dropCallSession(network: Network, addUpdates: @escaping (Api.Update
|
|||||||
switch update {
|
switch update {
|
||||||
case .updatePhoneCall(let phoneCall):
|
case .updatePhoneCall(let phoneCall):
|
||||||
switch phoneCall {
|
switch phoneCall {
|
||||||
case let .phoneCallDiscarded(flags, _, _, _):
|
case let .phoneCallDiscarded(flags, _, _, _, _):
|
||||||
reportRating = (flags & (1 << 2)) != 0
|
reportRating = (flags & (1 << 2)) != 0
|
||||||
sendDebugLogs = (flags & (1 << 3)) != 0
|
sendDebugLogs = (flags & (1 << 3)) != 0
|
||||||
default:
|
default:
|
||||||
@ -1501,33 +1562,7 @@ private func dropCallSession(network: Network, addUpdates: @escaping (Api.Update
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func createConferenceCall(postbox: Postbox, network: Network, accountPeerId: PeerId, callId: CallId) -> Signal<GroupCallReference?, NoError> {
|
private func createConferenceCall(postbox: Postbox, network: Network, accountPeerId: PeerId, callId: CallId) -> Signal<GroupCallReference?, NoError> {
|
||||||
#if DEBUG && false
|
return network.request(Api.functions.phone.createConferenceCall(peer: .inputPhoneCall(id: callId.id, accessHash: callId.accessHash), keyFingerprint: 1))
|
||||||
if "".isEmpty {
|
|
||||||
return _internal_resolvePeerByName(postbox: postbox, network: network, accountPeerId: accountPeerId, name: "qwfqwfqwefqwef22", referrer: nil)
|
|
||||||
|> mapToSignal { result -> Signal<PeerId?, NoError> in
|
|
||||||
switch result {
|
|
||||||
case .progress:
|
|
||||||
return .never()
|
|
||||||
case let .result(peerId):
|
|
||||||
return .single(peerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|> mapToSignal { peerId -> Signal<GroupCallReference?, NoError> in
|
|
||||||
guard let peerId else {
|
|
||||||
return .single(nil)
|
|
||||||
}
|
|
||||||
return _internal_updatedCurrentPeerGroupCall(postbox: postbox, network: network, accountPeerId: accountPeerId, peerId: peerId)
|
|
||||||
|> map { result -> GroupCallReference? in
|
|
||||||
guard let result else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return GroupCallReference(id: result.id, accessHash: result.accessHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return network.request(Api.functions.phone.createConferenceCall(peer: .inputPhoneCall(id: callId.id, accessHash: callId.accessHash)))
|
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.phone.PhoneCall?, NoError> in
|
|> `catch` { _ -> Signal<Api.phone.PhoneCall?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
|
|||||||
@ -1745,7 +1745,7 @@ public final class PendingMessageManager {
|
|||||||
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
||||||
isScheduled = true
|
isScheduled = true
|
||||||
}
|
}
|
||||||
if case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage {
|
if case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage {
|
||||||
if (flags2 & (1 << 4)) != 0 {
|
if (flags2 & (1 << 4)) != 0 {
|
||||||
isScheduled = true
|
isScheduled = true
|
||||||
}
|
}
|
||||||
@ -1780,7 +1780,7 @@ public final class PendingMessageManager {
|
|||||||
namespace = Namespaces.Message.QuickReplyCloud
|
namespace = Namespaces.Message.QuickReplyCloud
|
||||||
} else if let apiMessage = result.messages.first, message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
} else if let apiMessage = result.messages.first, message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
||||||
namespace = Namespaces.Message.ScheduledCloud
|
namespace = Namespaces.Message.ScheduledCloud
|
||||||
} else if let apiMessage = result.messages.first, case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage, (flags2 & (1 << 4)) != 0 {
|
} else if let apiMessage = result.messages.first, case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage, (flags2 & (1 << 4)) != 0 {
|
||||||
namespace = Namespaces.Message.ScheduledCloud
|
namespace = Namespaces.Message.ScheduledCloud
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
|||||||
self.putNext(groups)
|
self.putNext(groups)
|
||||||
}
|
}
|
||||||
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
|
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
|
||||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil)
|
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil)
|
||||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||||
if groups.count != 0 {
|
if groups.count != 0 {
|
||||||
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
|||||||
|
|
||||||
let generatedPeerId = Api.Peer.peerUser(userId: userId)
|
let generatedPeerId = Api.Peer.peerUser(userId: userId)
|
||||||
|
|
||||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil)
|
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil, factcheck: nil, reportDeliveryUntilDate: nil)
|
||||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||||
if groups.count != 0 {
|
if groups.count != 0 {
|
||||||
|
|||||||
@ -104,7 +104,7 @@ extension Api.MessageMedia {
|
|||||||
extension Api.Message {
|
extension Api.Message {
|
||||||
var rawId: Int32 {
|
var rawId: Int32 {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return id
|
return id
|
||||||
case let .messageEmpty(_, id, _):
|
case let .messageEmpty(_, id, _):
|
||||||
return id
|
return id
|
||||||
@ -115,7 +115,7 @@ extension Api.Message {
|
|||||||
|
|
||||||
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
|
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, flags2, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, flags2, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
var namespace = namespace
|
var namespace = namespace
|
||||||
if (flags2 & (1 << 4)) != 0 {
|
if (flags2 & (1 << 4)) != 0 {
|
||||||
namespace = Namespaces.Message.ScheduledCloud
|
namespace = Namespaces.Message.ScheduledCloud
|
||||||
@ -136,7 +136,7 @@ extension Api.Message {
|
|||||||
|
|
||||||
var peerId: PeerId? {
|
var peerId: PeerId? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
let peerId: PeerId = messagePeerId.peerId
|
let peerId: PeerId = messagePeerId.peerId
|
||||||
return peerId
|
return peerId
|
||||||
case let .messageEmpty(_, _, peerId):
|
case let .messageEmpty(_, _, peerId):
|
||||||
@ -149,7 +149,7 @@ extension Api.Message {
|
|||||||
|
|
||||||
var timestamp: Int32? {
|
var timestamp: Int32? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return date
|
return date
|
||||||
case let .messageService(_, _, _, _, _, date, _, _, _):
|
case let .messageService(_, _, _, _, _, date, _, _, _):
|
||||||
return date
|
return date
|
||||||
@ -160,7 +160,7 @@ extension Api.Message {
|
|||||||
|
|
||||||
var preCachedResources: [(MediaResource, Data)]? {
|
var preCachedResources: [(MediaResource, Data)]? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return media?.preCachedResources
|
return media?.preCachedResources
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
@ -169,7 +169,7 @@ extension Api.Message {
|
|||||||
|
|
||||||
var preCachedStories: [StoryId: Api.StoryItem]? {
|
var preCachedStories: [StoryId: Api.StoryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||||
return media?.preCachedStories
|
return media?.preCachedStories
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -435,7 +435,7 @@ public struct JoinGroupCallResult {
|
|||||||
public var jsonParams: String
|
public var jsonParams: String
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil, keyFingerprint: Int64?) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
if let joinAs = joinAs {
|
if let joinAs = joinAs {
|
||||||
return transaction.getPeer(joinAs).flatMap(apiInputPeer)
|
return transaction.getPeer(joinAs).flatMap(apiInputPeer)
|
||||||
@ -457,8 +457,11 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||||||
if let _ = inviteHash {
|
if let _ = inviteHash {
|
||||||
flags |= (1 << 1)
|
flags |= (1 << 1)
|
||||||
}
|
}
|
||||||
|
if keyFingerprint != nil {
|
||||||
|
flags |= (1 << 3)
|
||||||
|
}
|
||||||
|
|
||||||
let joinRequest = account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), joinAs: inputJoinAs, inviteHash: inviteHash, params: .dataJSON(data: joinPayload)))
|
let joinRequest = account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), joinAs: inputJoinAs, inviteHash: inviteHash, keyFingerprint: keyFingerprint, params: .dataJSON(data: joinPayload)))
|
||||||
|> `catch` { error -> Signal<Api.Updates, JoinGroupCallError> in
|
|> `catch` { error -> Signal<Api.Updates, JoinGroupCallError> in
|
||||||
if error.errorDescription == "GROUPCALL_ANONYMOUS_FORBIDDEN" {
|
if error.errorDescription == "GROUPCALL_ANONYMOUS_FORBIDDEN" {
|
||||||
return .fail(.anonymousNotAllowed)
|
return .fail(.anonymousNotAllowed)
|
||||||
|
|||||||
@ -57,8 +57,8 @@ public extension TelegramEngine {
|
|||||||
return _internal_getGroupCallParticipants(account: self.account, callId: callId, accessHash: accessHash, offset: offset, ssrcs: ssrcs, limit: limit, sortAscending: sortAscending)
|
return _internal_getGroupCallParticipants(account: self.account, callId: callId, accessHash: accessHash, offset: offset, ssrcs: ssrcs, limit: limit, sortAscending: sortAscending)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func joinGroupCall(peerId: PeerId?, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
public func joinGroupCall(peerId: PeerId?, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil, keyFingerprint: Int64?) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
||||||
return _internal_joinGroupCall(account: self.account, peerId: peerId, joinAs: joinAs, callId: callId, accessHash: accessHash, preferMuted: preferMuted, joinPayload: joinPayload, peerAdminIds: peerAdminIds, inviteHash: inviteHash)
|
return _internal_joinGroupCall(account: self.account, peerId: peerId, joinAs: joinAs, callId: callId, accessHash: accessHash, preferMuted: preferMuted, joinPayload: joinPayload, peerAdminIds: peerAdminIds, inviteHash: inviteHash, keyFingerprint: keyFingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func joinGroupCallAsScreencast(callId: Int64, accessHash: Int64, joinPayload: String) -> Signal<JoinGroupCallAsScreencastResult, JoinGroupCallError> {
|
public func joinGroupCallAsScreencast(callId: Int64, accessHash: Int64, joinPayload: String) -> Signal<JoinGroupCallAsScreencastResult, JoinGroupCallError> {
|
||||||
|
|||||||
@ -226,6 +226,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
|
|||||||
public var backAction: (() -> Void)?
|
public var backAction: (() -> Void)?
|
||||||
public var closeAction: (() -> Void)?
|
public var closeAction: (() -> Void)?
|
||||||
public var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
|
public var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
|
||||||
|
public var conferenceAddParticipant: (() -> Void)?
|
||||||
|
|
||||||
private let pipView: PrivateCallPictureInPictureView
|
private let pipView: PrivateCallPictureInPictureView
|
||||||
private var pipContentSource: AnyObject?
|
private var pipContentSource: AnyObject?
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 965c46f32425cb270e88ab0aab7c3593b5be574e
|
Subproject commit ab50f4e095d5793c39dc54b740a982fc3ba27ea5
|
||||||
Loading…
x
Reference in New Issue
Block a user