[WIP] Conference calls

This commit is contained in:
Isaac 2024-12-18 23:35:27 +08:00
parent e18795980e
commit 2b9f5ed541
22 changed files with 619 additions and 407 deletions

View File

@ -283,6 +283,9 @@
"LOCAL_CHANNEL_MESSAGE_FWDS" = "%1$@ posted %2$d forwarded 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.OK" = "OK";
"Common.Cancel" = "Cancel";

View File

@ -535,7 +535,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
dict[1235637404] = { return Api.MediaArea.parse_mediaAreaWeather($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[-741178048] = { return Api.Message.parse_messageService($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[-1707742823] = { return Api.PeerStories.parse_peerStories($0) }
dict[1000707084] = { return Api.PhoneCall.parse_phoneCall($0) }
dict[912311057] = { return Api.PhoneCall.parse_phoneCallAccepted($0) }
dict[1355435489] = { return Api.PhoneCall.parse_phoneCallDiscarded($0) }
dict[587035009] = { return Api.PhoneCall.parse_phoneCallAccepted($0) }
dict[-103656189] = { return Api.PhoneCall.parse_phoneCallDiscarded($0) }
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
dict[347139340] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
dict[-987599081] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
dict[1161174115] = { return Api.PhoneCall.parse_phoneCallRequested($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[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) }
dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) }

View File

@ -60,15 +60,15 @@ public extension Api {
}
public extension Api {
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 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) {
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 {
buffer.appendInt32(-1808510398)
buffer.appendInt32(-1761756183)
}
serializeInt32(flags, 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(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 << 5) != 0 {serializeInt32(reportDeliveryUntilDate!, buffer: buffer, boxed: false)}
break
case .messageEmpty(let flags, let id, let peerId):
if boxed {
@ -134,8 +135,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
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):
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)])
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), ("reportDeliveryUntilDate", reportDeliveryUntilDate as Any)])
case .messageEmpty(let flags, let id, let peerId):
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):
@ -224,6 +225,8 @@ public extension Api {
if Int(_2!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -252,8 +255,9 @@ public extension Api {
let _c26 = (Int(_1!) & Int(1 << 30) == 0) || _26 != nil
let _c27 = (Int(_2!) & Int(1 << 2) == 0) || _27 != 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 {
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)
let _c29 = (Int(_2!) & Int(1 << 5) == 0) || _29 != 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 && _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 {
return nil

View File

@ -1011,11 +1011,11 @@ public extension Api {
public extension Api {
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 phoneCallAccepted(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gB: Buffer, protocol: Api.PhoneCallProtocol)
case phoneCallDiscarded(flags: Int32, id: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?)
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?, conferenceCall: Api.InputGroupCall?)
case phoneCallEmpty(id: Int64)
case phoneCallRequested(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAHash: Buffer, protocol: Api.PhoneCallProtocol)
case phoneCallWaiting(flags: Int32, id: Int64, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, protocol: Api.PhoneCallProtocol, receiveDate: Int32?)
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?, conferenceCall: Api.InputGroupCall?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
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 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
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 {
buffer.appendInt32(912311057)
buffer.appendInt32(587035009)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false)
@ -1053,15 +1053,17 @@ public extension Api {
serializeInt64(participantId, buffer: buffer, boxed: false)
serializeBytes(gB, buffer: buffer, boxed: false)
`protocol`.serialize(buffer, true)
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
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 {
buffer.appendInt32(1355435489)
buffer.appendInt32(-103656189)
}
serializeInt32(flags, 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 << 1) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
break
case .phoneCallEmpty(let id):
if boxed {
@ -1069,9 +1071,9 @@ public extension Api {
}
serializeInt64(id, buffer: buffer, boxed: false)
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 {
buffer.appendInt32(347139340)
buffer.appendInt32(1161174115)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false)
@ -1081,10 +1083,11 @@ public extension Api {
serializeInt64(participantId, buffer: buffer, boxed: false)
serializeBytes(gAHash, buffer: buffer, boxed: false)
`protocol`.serialize(buffer, true)
if Int(flags) & Int(1 << 8) != 0 {conferenceCall!.serialize(buffer, true)}
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 {
buffer.appendInt32(-987599081)
buffer.appendInt32(-288085928)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false)
@ -1094,6 +1097,7 @@ public extension Api {
serializeInt64(participantId, buffer: buffer, boxed: false)
`protocol`.serialize(buffer, true)
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
}
}
@ -1102,16 +1106,16 @@ public extension Api {
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):
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`):
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)])
case .phoneCallDiscarded(let flags, let id, let reason, let duration):
return ("phoneCallDiscarded", [("flags", flags as Any), ("id", id as Any), ("reason", reason as Any), ("duration", duration as Any)])
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), ("conferenceCall", conferenceCall as Any)])
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), ("conferenceCall", conferenceCall as Any)])
case .phoneCallEmpty(let id):
return ("phoneCallEmpty", [("id", id as Any)])
case .phoneCallRequested(let flags, let id, let accessHash, let date, let adminId, let participantId, let gAHash, let `protocol`):
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)])
case .phoneCallWaiting(let flags, let id, let accessHash, let date, let adminId, let participantId, let `protocol`, let receiveDate):
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)])
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), ("conferenceCall", conferenceCall as Any)])
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), ("conferenceCall", conferenceCall as Any)])
}
}
@ -1189,6 +1193,10 @@ public extension Api {
if let signature = reader.readInt32() {
_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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -1197,8 +1205,9 @@ public extension Api {
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.PhoneCall.phoneCallAccepted(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gB: _7!, protocol: _8!)
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
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 {
return nil
@ -1215,12 +1224,17 @@ public extension Api {
} }
var _4: Int32?
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 _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PhoneCall.phoneCallDiscarded(flags: _1!, id: _2!, reason: _3, duration: _4)
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.PhoneCall.phoneCallDiscarded(flags: _1!, id: _2!, reason: _3, duration: _4, conferenceCall: _5)
}
else {
return nil
@ -1256,6 +1270,10 @@ public extension Api {
if let signature = reader.readInt32() {
_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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -1264,8 +1282,9 @@ public extension Api {
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.PhoneCall.phoneCallRequested(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, gAHash: _7!, protocol: _8!)
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
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 {
return nil
@ -1290,6 +1309,10 @@ public extension Api {
}
var _8: Int32?
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 _c2 = _2 != nil
let _c3 = _3 != nil
@ -1298,8 +1321,9 @@ public extension Api {
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.PhoneCall.phoneCallWaiting(flags: _1!, id: _2!, accessHash: _3!, date: _4!, adminId: _5!, participantId: _6!, protocol: _7!, receiveDate: _8)
let _c9 = (Int(_1!) & Int(1 << 8) == 0) || _9 != nil
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 {
return nil
@ -1310,6 +1334,7 @@ public extension Api {
}
public extension Api {
enum PhoneCallDiscardReason: TypeConstructorDescription {
case phoneCallDiscardReasonAllowGroupCall(encryptedKey: Buffer)
case phoneCallDiscardReasonBusy
case phoneCallDiscardReasonDisconnect
case phoneCallDiscardReasonHangup
@ -1317,6 +1342,12 @@ public extension Api {
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .phoneCallDiscardReasonAllowGroupCall(let encryptedKey):
if boxed {
buffer.appendInt32(-1344096199)
}
serializeBytes(encryptedKey, buffer: buffer, boxed: false)
break
case .phoneCallDiscardReasonBusy:
if boxed {
buffer.appendInt32(-84416311)
@ -1346,6 +1377,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .phoneCallDiscardReasonAllowGroupCall(let encryptedKey):
return ("phoneCallDiscardReasonAllowGroupCall", [("encryptedKey", encryptedKey as Any)])
case .phoneCallDiscardReasonBusy:
return ("phoneCallDiscardReasonBusy", [])
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? {
return Api.PhoneCallDiscardReason.phoneCallDiscardReasonBusy
}

View File

@ -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 {
static func reportReaction(peer: Api.InputPeer, id: Int32, reactionPeer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -9587,11 +9608,12 @@ 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()
buffer.appendInt32(-1828162221)
buffer.appendInt32(-540472917)
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)
var result: Api.phone.PhoneCall?
if let signature = reader.readInt32() {
@ -9834,15 +9856,16 @@ 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()
buffer.appendInt32(-1322057861)
buffer.appendInt32(-702669325)
serializeInt32(flags, buffer: buffer, boxed: false)
call.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 << 3) != 0 {serializeInt64(keyFingerprint!, buffer: buffer, boxed: false)}
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)
var result: Api.Updates?
if let signature = reader.readInt32() {
@ -9915,15 +9938,16 @@ 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()
buffer.appendInt32(1124046573)
buffer.appendInt32(-1497079796)
serializeInt32(flags, buffer: buffer, boxed: false)
userId.serialize(buffer, true)
if Int(flags) & Int(1 << 1) != 0 {conferenceCall!.serialize(buffer, true)}
serializeInt32(randomId, buffer: buffer, boxed: false)
serializeBytes(gAHash, buffer: buffer, boxed: false)
`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)
var result: Api.phone.PhoneCall?
if let signature = reader.readInt32() {

View File

@ -522,6 +522,13 @@ public final class CallController: ViewController {
let _ = self?.dismiss()
}
displayNode.conferenceAddParticipant = { [weak self] in
guard let self else {
return
}
self.conferenceAddParticipant()
}
self.controllerNode.presentCallRating = { [weak self] callId, isVideo in
if let strongSelf = self, !strongSelf.presentedCallRating {
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() {
self.dismiss()
}

View File

@ -60,6 +60,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
var dismissedInteractively: (() -> Void)?
var dismissAllTooltips: (() -> Void)?
var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
var conferenceAddParticipant: (() -> Void)?
private var emojiKey: (data: Data, resolvedKey: [String])?
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat)?
@ -129,6 +130,14 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
guard let self else {
return
}
#if DEBUG
if self.sharedContext.immediateExperimentalUISettings.conferenceCalls {
self.conferenceAddParticipant?()
return
}
#endif
self.call.toggleIsMuted()
}
self.callScreen.endCallAction = { [weak self] in
@ -157,6 +166,12 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
}
self.restoreUIForPictureInPicture?(completion)
}
self.callScreen.conferenceAddParticipant = { [weak self] in
guard let self else {
return
}
self.conferenceAddParticipant?()
}
self.callScreenState = PrivateCallScreen.State(
strings: presentationData.strings,

View File

@ -550,9 +550,9 @@ public final class PresentationCallImpl: PresentationCall {
presentationState = PresentationCallState(state: .terminating(reason), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
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)
case let .requesting(ringing):
case let .requesting(ringing, _):
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
if let callContextState = callContextState {
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 {
case .requesting:
if let _ = audioSessionControl {
self.audioSessionShouldBeActive.set(true)
}
case let .active(id, key, keyVisualHash, 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)
}
})
})
}
case let .active(id, key, _, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
if conferenceCall == nil, self.isExpectedToBeConference {
self.createConferenceIfPossible()
}
self.audioSessionShouldBeActive.set(true)
if self.isExpectedToBeConference {
if self.isExpectedToBeConference || conferenceCallData != nil {
if sessionState.isOutgoing {
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):
self.audioSessionShouldBeActive.set(true)
if wasActive {
@ -1093,9 +1112,9 @@ public final class PresentationCallImpl: PresentationCall {
}
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)
}
}*/
}
private func updateIsAudioSessionActive(_ value: Bool) {
@ -1272,6 +1291,32 @@ public final class PresentationCallImpl: PresentationCall {
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) {
guard self.currentAudioOutputValue != output else {
return

View File

@ -536,7 +536,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|> mapToSignal { areVideoCallsAvailable -> Signal<CallSessionInternalId, NoError> in
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

View File

@ -865,7 +865,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
private var screencastStateDisposable: Disposable?
public let isStream: Bool
private let encryptionKey: Data?
private let encryptionKey: (key: Data, fingerprint: Int64)?
private let sharedAudioDevice: OngoingCallContext.AudioDevice?
private let conferenceFromCallId: CallId?
@ -885,7 +885,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
invite: String?,
joinAsPeerId: EnginePeer.Id?,
isStream: Bool,
encryptionKey: Data?,
encryptionKey: (key: Data, fingerprint: Int64)?,
conferenceFromCallId: CallId?,
isConference: Bool,
sharedAudioDevice: OngoingCallContext.AudioDevice?
@ -1711,16 +1711,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
}
var encryptionKey: Data?
encryptionKey = self.encryptionKey
#if DEBUG
if encryptionKey == nil {
encryptionKey = Data(count: 256)
}
encryptionKey = self.encryptionKey?.key
if "".isEmpty {
encryptionKey = nil
}
#endif
genericCallContext = .call(OngoingGroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in
let disposable = MetaDisposable()
@ -1860,7 +1854,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
preferMuted: true,
joinPayload: joinPayload,
peerAdminIds: peerAdminIds,
inviteHash: strongSelf.invite
inviteHash: strongSelf.invite,
keyFingerprint: strongSelf.encryptionKey?.fingerprint
)
|> deliverOnMainQueue).start(next: { joinCallResult in
guard let strongSelf = self else {

View File

@ -126,7 +126,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
switch messsage {
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
let chatPeerId = messagePeerId
return chatPeerId.peerId
case let .messageEmpty(_, _, peerId):
@ -142,7 +142,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
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
var result = [peerId]
@ -270,7 +270,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? {
switch message {
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
if let replyTo = replyTo {
let peerId: PeerId = chatPeerId.peerId
@ -654,7 +654,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage {
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
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] = []
if (flags2 & (1 << 4)) != 0 {

View File

@ -200,6 +200,8 @@ extension PhoneCallDiscardReason {
self = .hangup
case .phoneCallDiscardReasonMissed:
self = .missed
case .phoneCallDiscardReasonAllowGroupCall:
self = .hangup
}
}
}

View File

@ -134,19 +134,22 @@ public final class AccountStateManager {
public let timestamp: Int32
public let peer: EnginePeer
public let isVideo: Bool
public let isConference: Bool
init(
callId: Int64,
callAccessHash: Int64,
timestamp: Int32,
peer: EnginePeer,
isVideo: Bool
isVideo: Bool,
isConference: Bool
) {
self.callId = callId
self.callAccessHash = callAccessHash
self.timestamp = timestamp
self.peer = peer
self.isVideo = isVideo
self.isConference = isConference
}
}
@ -2160,7 +2163,7 @@ public final class AccountStateManager {
switch update {
case let .updatePhoneCall(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 {
return nil
}
@ -2169,7 +2172,8 @@ public final class AccountStateManager {
callAccessHash: accessHash,
timestamp: date,
peer: EnginePeer(peer),
isVideo: (flags & (1 << 6)) != 0
isVideo: (flags & (1 << 6)) != 0,
isConference: conferenceCall != nil
)
default:
break

View File

@ -104,7 +104,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
var updatedTimestamp: Int32?
if let apiMessage = apiMessage {
switch apiMessage {
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
updatedTimestamp = date
case .messageEmpty:
break
@ -400,7 +400,7 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
} else if let message = messages.first, let apiMessage = result.messages.first {
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
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
}
}

View File

@ -73,32 +73,35 @@ extension GroupCallReference {
}
enum CallSessionInternalState {
case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data, versions: [String])
case accepting(id: Int64, accessHash: Int64, gAHash: Data, b: Data, disposable: Disposable)
case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data, versions: [String], conferenceCall: GroupCallReference?)
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 requesting(a: Data, disposable: Disposable)
case requested(id: Int64, accessHash: Int64, a: Data, gA: Data, config: SecretChatEncryptionConfig, remoteConfirmationTimestamp: Int32?)
case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: 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?, conferenceCall: GroupCallReference?)
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 switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
case dropping(reason: CallSessionTerminationReason, disposable: Disposable)
case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool)
var stableId: Int64? {
switch self {
case let .ringing(id, _, _, _, _):
case let .ringing(id, _, _, _, _, _):
return id
case let .accepting(id, _, _, _, _):
case let .accepting(id, _, _, _, _, _):
return id
case let .awaitingConfirmation(id, _, _, _, _):
return id
case .requesting:
return nil
case let .requested(id, _, _, _, _, _):
case let .requested(id, _, _, _, _, _, _):
return id
case let .confirming(id, _, _, _, _, _):
case let .confirming(id, _, _, _, _, _, _):
return id
case let .active(id, _, _, _, _, _, _, _, _, _, _, _):
return id
case .switchedToConference:
return nil
case .dropping:
return nil
case let .terminated(id, _, _, _, _):
@ -161,8 +164,9 @@ public struct CallTerminationOptions: OptionSet {
public enum CallSessionState {
case ringing
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 switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
case dropping(reason: CallSessionTerminationReason)
case terminated(id: CallId?, reason: CallSessionTerminationReason, options: CallTerminationOptions)
@ -172,12 +176,12 @@ public enum CallSessionState {
self = .ringing
case .accepting, .awaitingConfirmation:
self = .accepting
case .requesting:
self = .requesting(ringing: false)
case .confirming:
self = .requesting(ringing: true)
case let .requested(_, _, _, _, _, remoteConfirmationTimestamp):
self = .requesting(ringing: remoteConfirmationTimestamp != nil)
case let .requesting(_, conferenceCall, _):
self = .requesting(ringing: false, conferenceCall: conferenceCall)
case let .confirming(_, _, _, _, _, conferenceCall, _):
self = .requesting(ringing: true, conferenceCall: conferenceCall)
case let .requested(_, _, _, _, _, remoteConfirmationTimestamp, conferenceCall):
self = .requesting(ringing: remoteConfirmationTimestamp != nil, conferenceCall: 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)
case let .dropping(reason, _):
@ -197,6 +201,8 @@ public enum CallSessionState {
callId = nil
}
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
var type: CallSession.CallType
var isVideoPossible: Bool
let pendingConference: (conference: GroupCallReference, encryptionKey: Data)?
var state: CallSessionInternalState
let subscribers = Bag<(CallSession) -> 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.isOutgoing = isOutgoing
self.type = type
self.isVideoPossible = isVideoPossible
self.pendingConference = pendingConference
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 {
return nil
}
@ -582,7 +590,7 @@ private final class CallSessionManagerContext {
//#endif
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
let queue = self.queue
@ -619,7 +627,7 @@ private final class CallSessionManagerContext {
var wasRinging = false
let isVideo = context.type == .video
switch context.state {
case let .ringing(id, accessHash, _, _, _):
case let .ringing(id, accessHash, _, _, _, _):
wasRinging = true
let internalReason: DropCallSessionReason
switch reason {
@ -633,7 +641,7 @@ private final class CallSessionManagerContext {
internalReason = .missed
}
dropData = (id, accessHash, internalReason)
case let .accepting(id, accessHash, _, _, disposable):
case let .accepting(id, accessHash, _, _, _, disposable):
dropData = (id, accessHash, .abort)
disposable.dispose()
case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _, _, _, _):
@ -648,14 +656,16 @@ private final class CallSessionManagerContext {
internalReason = .missed
}
dropData = (id, accessHash, internalReason)
case .switchedToConference:
break
case .dropping, .terminated:
break
case let .awaitingConfirmation(id, accessHash, _, _, _):
dropData = (id, accessHash, .abort)
case let .confirming(id, accessHash, _, _, _, disposable):
case let .confirming(id, accessHash, _, _, _, _, disposable):
disposable.dispose()
dropData = (id, accessHash, .abort)
case let .requested(id, accessHash, _, _, _, _):
case let .requested(id, accessHash, _, _, _, _, _):
let internalReason: DropCallSessionReason
switch reason {
case .busy, .hangUp:
@ -666,7 +676,7 @@ private final class CallSessionManagerContext {
internalReason = .missed
}
dropData = (id, accessHash, internalReason)
case let .requesting(_, disposable):
case let .requesting(_, _, disposable):
disposable.dispose()
context.state = .terminated(id: nil, accessHash: nil, reason: .ended(.hungUp), reportRating: false, sendDebugLogs: false)
self.contextUpdated(internalId: internalId)
@ -689,6 +699,8 @@ private final class CallSessionManagerContext {
mappedReason = .ended(.hungUp)
case .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)
|> 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() {
let contexts = self.contexts
for (internalId, _) in contexts {
@ -739,9 +783,9 @@ private final class CallSessionManagerContext {
func accept(internalId: CallSessionInternalId) {
if let context = self.contexts[internalId] {
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 })
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 case .accepting = context.state {
switch result {
@ -835,7 +879,7 @@ private final class CallSessionManagerContext {
switch call {
case .phoneCallEmpty:
break
case let .phoneCallAccepted(_, id, _, _, _, _, gB, remoteProtocol):
case let .phoneCallAccepted(_, id, _, _, _, _, gB, remoteProtocol, conferenceCall):
let remoteVersions: [String]
switch remoteProtocol {
case let .phoneCallProtocol(_, _, _, versions):
@ -849,7 +893,7 @@ private final class CallSessionManagerContext {
if let context = self.contexts[internalId] {
switch context.state {
case let .requested(_, accessHash, a, gA, config, _):
case let .requested(_, accessHash, a, gA, config, _, _):
let p = config.p.makeData()
if !MTCheckIsSafeGAOrB(self.network.encryptionProvider, gA, p) {
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
@ -874,10 +918,14 @@ private final class CallSessionManagerContext {
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 updatedCall = updatedCall {
strongSelf.updateSession(updatedCall, completion: { _ in })
if let pendingConference = context.pendingConference {
strongSelf.dropToConference(internalId: internalId, encryptedGroupKey: pendingConference.encryptionKey)
}
} else {
strongSelf.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
}
@ -891,7 +939,8 @@ private final class CallSessionManagerContext {
assertionFailure()
}
}
case let .phoneCallDiscarded(flags, id, reason, _):
case let .phoneCallDiscarded(flags, id, reason, _, conferenceCall):
let _ = conferenceCall
let reportRating = (flags & (1 << 2)) != 0
let sendDebugLogs = (flags & (1 << 3)) != 0
if let internalId = self.contextIdByStableId[id] {
@ -899,47 +948,53 @@ private final class CallSessionManagerContext {
let parsedReason: CallSessionTerminationReason
if let reason = reason {
switch reason {
case .phoneCallDiscardReasonBusy:
parsedReason = .ended(.busy)
case .phoneCallDiscardReasonDisconnect:
parsedReason = .error(.disconnected)
case .phoneCallDiscardReasonHangup:
parsedReason = .ended(.hungUp)
case .phoneCallDiscardReasonMissed:
parsedReason = .ended(.missed)
case .phoneCallDiscardReasonBusy:
parsedReason = .ended(.busy)
case .phoneCallDiscardReasonDisconnect:
parsedReason = .error(.disconnected)
case .phoneCallDiscardReasonHangup:
parsedReason = .ended(.hungUp)
case .phoneCallDiscardReasonMissed:
parsedReason = .ended(.missed)
case .phoneCallDiscardReasonAllowGroupCall:
parsedReason = .ended(.hungUp)
}
} else {
parsedReason = .ended(.hungUp)
}
switch context.state {
case let .accepting(id, accessHash, _, _, disposable):
disposable.dispose()
case let .accepting(id, accessHash, _, _, _, disposable):
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)
self.contextUpdated(internalId: internalId)
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .awaitingConfirmation(id, accessHash, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .requested(id, accessHash, _, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .confirming(id, accessHash, _, _, _, disposable):
disposable.dispose()
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .requesting(_, disposable):
disposable.dispose()
context.state = .terminated(id: nil, accessHash: nil, reason: parsedReason, reportRating: false, sendDebugLogs: false)
self.contextUpdated(internalId: internalId)
case let .ringing(id, accessHash, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.ringingStatesUpdated()
self.contextUpdated(internalId: internalId)
case .dropping, .terminated:
break
}
self.contextUpdated(internalId: internalId)
case let .awaitingConfirmation(id, accessHash, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .requested(id, accessHash, _, _, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .confirming(id, accessHash, _, _, _, _, disposable):
disposable.dispose()
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .requesting(_, _, disposable):
disposable.dispose()
context.state = .terminated(id: nil, accessHash: nil, reason: parsedReason, reportRating: false, sendDebugLogs: false)
self.contextUpdated(internalId: internalId)
case let .ringing(id, accessHash, _, _, _, _):
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.ringingStatesUpdated()
self.contextUpdated(internalId: internalId)
case .dropping, .terminated, .switchedToConference:
break
}
} else {
//assertionFailure()
@ -950,7 +1005,7 @@ private final class CallSessionManagerContext {
if let internalId = self.contextIdByStableId[id] {
if let context = self.contexts[internalId] {
switch context.state {
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested:
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested, .switchedToConference:
break
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
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 {
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 {
case let .phoneCallProtocol(_, _, maxLayer, versions):
if !versions.isEmpty {
@ -1007,7 +1062,7 @@ private final class CallSessionManagerContext {
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 versions: [String]
switch requestedProtocol {
@ -1015,7 +1070,7 @@ private final class CallSessionManagerContext {
versions = libraryVersions
}
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 {
var resultRingingStateValue: CallSessionRingingState?
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 context = self.contexts[internalId] {
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 {
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)
}
default:
@ -1101,17 +1156,17 @@ private final class CallSessionManagerContext {
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 randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self))
let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free)
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 case .requesting = context.state {
switch result {
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.contextUpdated(internalId: internalId)
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
let disposable = MetaDisposable()
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.putCompletion()
}
@ -1358,7 +1413,7 @@ private enum RequestCallSessionResult {
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)
|> mapToSignal { config -> 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 {
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
switch result {
case let .phoneCall(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)
case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate):
case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate, _):
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: receiveDate)
default:
return .failed(.generic)
@ -1439,23 +1497,26 @@ private enum DropCallSessionReason {
case busy
case disconnect
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> {
var mappedReason: Api.PhoneCallDiscardReason
var duration: Int32 = 0
switch reason {
case .abort:
mappedReason = .phoneCallDiscardReasonHangup
case let .hangUp(value):
duration = value
mappedReason = .phoneCallDiscardReasonHangup
case .busy:
mappedReason = .phoneCallDiscardReasonBusy
case .disconnect:
mappedReason = .phoneCallDiscardReasonDisconnect
case .missed:
mappedReason = .phoneCallDiscardReasonMissed
case .abort:
mappedReason = .phoneCallDiscardReasonHangup
case let .hangUp(value):
duration = value
mappedReason = .phoneCallDiscardReasonHangup
case .busy:
mappedReason = .phoneCallDiscardReasonBusy
case .disconnect:
mappedReason = .phoneCallDiscardReasonDisconnect
case .missed:
mappedReason = .phoneCallDiscardReasonMissed
case let .switchToConference(encryptedGroupKey):
mappedReason = .phoneCallDiscardReasonAllowGroupCall(encryptedKey: Buffer(data: encryptedGroupKey))
}
var callFlags: Int32 = 0
@ -1478,7 +1539,7 @@ private func dropCallSession(network: Network, addUpdates: @escaping (Api.Update
switch update {
case .updatePhoneCall(let phoneCall):
switch phoneCall {
case let .phoneCallDiscarded(flags, _, _, _):
case let .phoneCallDiscarded(flags, _, _, _, _):
reportRating = (flags & (1 << 2)) != 0
sendDebugLogs = (flags & (1 << 3)) != 0
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> {
#if DEBUG && false
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)))
return network.request(Api.functions.phone.createConferenceCall(peer: .inputPhoneCall(id: callId.id, accessHash: callId.accessHash), keyFingerprint: 1))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.phone.PhoneCall?, NoError> in
return .single(nil)

View File

@ -1745,7 +1745,7 @@ public final class PendingMessageManager {
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
isScheduled = true
}
if case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage {
if case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage {
if (flags2 & (1 << 4)) != 0 {
isScheduled = true
}
@ -1780,7 +1780,7 @@ public final class PendingMessageManager {
namespace = Namespaces.Message.QuickReplyCloud
} else if let apiMessage = result.messages.first, message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
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
}
}

View File

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups)
}
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 groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
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 groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {

View File

@ -104,7 +104,7 @@ extension Api.MessageMedia {
extension Api.Message {
var rawId: Int32 {
switch self {
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return id
case let .messageEmpty(_, id, _):
return id
@ -115,7 +115,7 @@ extension Api.Message {
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
switch self {
case let .message(_, flags2, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, flags2, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
var namespace = namespace
if (flags2 & (1 << 4)) != 0 {
namespace = Namespaces.Message.ScheduledCloud
@ -136,7 +136,7 @@ extension Api.Message {
var peerId: PeerId? {
switch self {
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
let peerId: PeerId = messagePeerId.peerId
return peerId
case let .messageEmpty(_, _, peerId):
@ -149,7 +149,7 @@ extension Api.Message {
var timestamp: Int32? {
switch self {
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return date
case let .messageService(_, _, _, _, _, date, _, _, _):
return date
@ -160,7 +160,7 @@ extension Api.Message {
var preCachedResources: [(MediaResource, Data)]? {
switch self {
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return media?.preCachedResources
default:
return nil
@ -169,7 +169,7 @@ extension Api.Message {
var preCachedStories: [StoryId: Api.StoryItem]? {
switch self {
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
return media?.preCachedStories
default:
return nil

View File

@ -435,7 +435,7 @@ public struct JoinGroupCallResult {
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
if let joinAs = joinAs {
return transaction.getPeer(joinAs).flatMap(apiInputPeer)
@ -457,8 +457,11 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
if let _ = inviteHash {
flags |= (1 << 1)
}
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)))
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, keyFingerprint: keyFingerprint, params: .dataJSON(data: joinPayload)))
|> `catch` { error -> Signal<Api.Updates, JoinGroupCallError> in
if error.errorDescription == "GROUPCALL_ANONYMOUS_FORBIDDEN" {
return .fail(.anonymousNotAllowed)

View File

@ -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)
}
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> {
return _internal_joinGroupCall(account: self.account, peerId: peerId, joinAs: joinAs, callId: callId, accessHash: accessHash, preferMuted: preferMuted, joinPayload: joinPayload, peerAdminIds: peerAdminIds, inviteHash: inviteHash)
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, keyFingerprint: keyFingerprint)
}
public func joinGroupCallAsScreencast(callId: Int64, accessHash: Int64, joinPayload: String) -> Signal<JoinGroupCallAsScreencastResult, JoinGroupCallError> {

View File

@ -226,6 +226,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
public var backAction: (() -> Void)?
public var closeAction: (() -> Void)?
public var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
public var conferenceAddParticipant: (() -> Void)?
private let pipView: PrivateCallPictureInPictureView
private var pipContentSource: AnyObject?

@ -1 +1 @@
Subproject commit 965c46f32425cb270e88ab0aab7c3593b5be574e
Subproject commit ab50f4e095d5793c39dc54b740a982fc3ba27ea5