mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
WIP
This commit is contained in:
parent
edbbc48340
commit
0e3445983c
@ -3,7 +3,7 @@
|
||||
@implementation Serialization
|
||||
|
||||
- (NSUInteger)currentLayer {
|
||||
return 120;
|
||||
return 122;
|
||||
}
|
||||
|
||||
- (id _Nullable)parseMessage:(NSData * _Nullable)data {
|
||||
|
@ -151,8 +151,13 @@ public protocol PresentationCall: class {
|
||||
func makeOutgoingVideoView(completion: @escaping (PresentationCallVideoView?) -> Void)
|
||||
}
|
||||
|
||||
public protocol PresentationGroupCall: class {
|
||||
|
||||
}
|
||||
|
||||
public protocol PresentationCallManager: class {
|
||||
var currentCallSignal: Signal<PresentationCall?, NoError> { get }
|
||||
|
||||
func requestCall(context: AccountContext, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
|
||||
func requestOrJoinGroupCall(context: AccountContext, peerId: PeerId)
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T], isLess
|
||||
for item in rightList {
|
||||
rightStableIds.append(getId(item))
|
||||
}
|
||||
if Set(leftStableIds) == Set(rightStableIds) && leftStableIds != rightStableIds && !allUpdated {
|
||||
if false && Set(leftStableIds) == Set(rightStableIds) && leftStableIds != rightStableIds && !allUpdated {
|
||||
var updatedItems: [(T, AnyHashable)] = []
|
||||
for i in 0 ..< leftList.count {
|
||||
if getId(leftList[i]) != getId(rightList[i]) {
|
||||
|
@ -46,6 +46,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case peerJoined
|
||||
case phoneNumberRequest
|
||||
case geoProximityReached(from: PeerId, to: PeerId, distance: Int32)
|
||||
case groupPhoneCall(callId: Int64, accessHash: Int64, duration: Int32?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||
@ -98,6 +99,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
self = .phoneNumberRequest
|
||||
case 21:
|
||||
self = .geoProximityReached(from: PeerId(decoder.decodeInt64ForKey("fromId", orElse: 0)), to: PeerId(decoder.decodeInt64ForKey("toId", orElse: 0)), distance: (decoder.decodeInt32ForKey("dst", orElse: 0)))
|
||||
case 22:
|
||||
self = .groupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), duration: decoder.decodeOptionalInt32ForKey("duration"))
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
@ -188,6 +191,15 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
encoder.encodeInt64(from.toInt64(), forKey: "fromId")
|
||||
encoder.encodeInt64(to.toInt64(), forKey: "toId")
|
||||
encoder.encodeInt32(distance, forKey: "dst")
|
||||
case let .groupPhoneCall(callId, accessHash, duration):
|
||||
encoder.encodeInt32(22, forKey: "_rawValue")
|
||||
encoder.encodeInt64(callId, forKey: "callId")
|
||||
encoder.encodeInt64(accessHash, forKey: "accessHash")
|
||||
if let duration = duration {
|
||||
encoder.encodeInt32(duration, forKey: "duration")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "duration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,14 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[571523412] = { return $0.readDouble() }
|
||||
dict[-1255641564] = { return parseString($0) }
|
||||
dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) }
|
||||
dict[1829443076] = { return Api.GroupCall.parse_groupCallPrivate($0) }
|
||||
dict[-857633264] = { return Api.GroupCall.parse_groupCall($0) }
|
||||
dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) }
|
||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||
dict[461151667] = { return Api.ChatFull.parse_chatFull($0) }
|
||||
dict[-253335766] = { return Api.ChatFull.parse_channelFull($0) }
|
||||
dict[-428758403] = { return Api.ChatFull.parse_channelFull($0) }
|
||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
||||
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
||||
@ -132,6 +135,11 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1511503333] = { return Api.InputEncryptedFile.parse_inputEncryptedFile($0) }
|
||||
dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) }
|
||||
dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) }
|
||||
dict[-1513019911] = { return Api.GroupCallParticipant.parse_groupCallParticipantAdmin($0) }
|
||||
dict[-1985949076] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||
dict[1100680690] = { return Api.GroupCallParticipant.parse_groupCallParticipantLeft($0) }
|
||||
dict[-1648085351] = { return Api.GroupCallParticipant.parse_groupCallParticipantKicked($0) }
|
||||
dict[-874654354] = { return Api.GroupCallParticipant.parse_groupCallParticipantInvited($0) }
|
||||
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
|
||||
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
|
||||
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
||||
@ -258,6 +266,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-13975905] = { return Api.Update.parse_updateChannelUserTyping($0) }
|
||||
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
|
||||
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
|
||||
dict[92188360] = { return Api.Update.parse_updateGroupCallParticipant($0) }
|
||||
dict[-2046916883] = { return Api.Update.parse_updateGroupCall($0) }
|
||||
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||
@ -329,11 +339,11 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-392411726] = { return Api.WebPage.parse_webPage($0) }
|
||||
dict[1930545681] = { return Api.WebPage.parse_webPageNotModified($0) }
|
||||
dict[1036876423] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageText($0) }
|
||||
dict[-190472735] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
||||
dict[864077702] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaAuto($0) }
|
||||
dict[1098628881] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaVenue($0) }
|
||||
dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) }
|
||||
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
|
||||
dict[-290164953] = { return Api.StickerSet.parse_stickerSet($0) }
|
||||
dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) }
|
||||
@ -392,6 +402,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
|
||||
dict[1694474197] = { return Api.messages.Chats.parse_chats($0) }
|
||||
dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) }
|
||||
dict[-659913713] = { return Api.InputGroupCall.parse_inputGroupCall($0) }
|
||||
dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) }
|
||||
dict[1163625789] = { return Api.MessageViews.parse_messageViews($0) }
|
||||
dict[218751099] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowContacts($0) }
|
||||
@ -496,6 +507,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1495959709] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
|
||||
dict[411017418] = { return Api.SecureValue.parse_secureValue($0) }
|
||||
dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) }
|
||||
dict[1731723191] = { return Api.phone.GroupCall.parse_groupCall($0) }
|
||||
dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) }
|
||||
dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) }
|
||||
dict[-1188055347] = { return Api.PageListItem.parse_pageListItemText($0) }
|
||||
@ -777,6 +789,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) }
|
||||
dict[-202219658] = { return Api.MessageAction.parse_messageActionContactSignUp($0) }
|
||||
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
|
||||
dict[2047704898] = { return Api.MessageAction.parse_messageActionGroupCall($0) }
|
||||
dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) }
|
||||
dict[462375633] = { return Api.PhoneCall.parse_phoneCallWaiting($0) }
|
||||
dict[-2014659757] = { return Api.PhoneCall.parse_phoneCallRequested($0) }
|
||||
@ -914,6 +927,8 @@ public struct Api {
|
||||
switch object {
|
||||
case let _1 as Api.messages.StickerSet:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.GroupCall:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputGeoPoint:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.payments.ValidatedRequestedInfo:
|
||||
@ -994,6 +1009,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.InactiveChats:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.GroupCallParticipant:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.SentEncryptedMessage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ExportedMessageLink:
|
||||
@ -1122,6 +1139,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.Chats:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputGroupCall:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputSingleMedia:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessageViews:
|
||||
@ -1206,6 +1225,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.SecureValueHash:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.phone.GroupCall:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.SearchCounter:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.auth.CheckedPhone:
|
||||
|
@ -1909,6 +1909,134 @@ public struct messages {
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
public enum GroupCall: TypeConstructorDescription {
|
||||
case groupCallPrivate(flags: Int32, id: Int64, accessHash: Int64, channelId: Int32?, participantsCount: Int32, adminId: Int32)
|
||||
case groupCall(flags: Int32, id: Int64, accessHash: Int64, channelId: Int32?, adminId: Int32, reflectorId: Int64, params: Api.DataJSON?)
|
||||
case groupCallDiscarded(id: Int64, accessHash: Int64, duration: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .groupCallPrivate(let flags, let id, let accessHash, let channelId, let participantsCount, let adminId):
|
||||
if boxed {
|
||||
buffer.appendInt32(1829443076)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(channelId!, buffer: buffer, boxed: false)}
|
||||
serializeInt32(participantsCount, buffer: buffer, boxed: false)
|
||||
serializeInt32(adminId, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .groupCall(let flags, let id, let accessHash, let channelId, let adminId, let reflectorId, let params):
|
||||
if boxed {
|
||||
buffer.appendInt32(-857633264)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(channelId!, buffer: buffer, boxed: false)}
|
||||
serializeInt32(adminId, buffer: buffer, boxed: false)
|
||||
serializeInt64(reflectorId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {params!.serialize(buffer, true)}
|
||||
break
|
||||
case .groupCallDiscarded(let id, let accessHash, let duration):
|
||||
if boxed {
|
||||
buffer.appendInt32(2004925620)
|
||||
}
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||
serializeInt32(duration, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .groupCallPrivate(let flags, let id, let accessHash, let channelId, let participantsCount, let adminId):
|
||||
return ("groupCallPrivate", [("flags", flags), ("id", id), ("accessHash", accessHash), ("channelId", channelId), ("participantsCount", participantsCount), ("adminId", adminId)])
|
||||
case .groupCall(let flags, let id, let accessHash, let channelId, let adminId, let reflectorId, let params):
|
||||
return ("groupCall", [("flags", flags), ("id", id), ("accessHash", accessHash), ("channelId", channelId), ("adminId", adminId), ("reflectorId", reflectorId), ("params", params)])
|
||||
case .groupCallDiscarded(let id, let accessHash, let duration):
|
||||
return ("groupCallDiscarded", [("id", id), ("accessHash", accessHash), ("duration", duration)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_groupCallPrivate(_ reader: BufferReader) -> GroupCall? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int64?
|
||||
_3 = reader.readInt64()
|
||||
var _4: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: Int32?
|
||||
_6 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.GroupCall.groupCallPrivate(flags: _1!, id: _2!, accessHash: _3!, channelId: _4, participantsCount: _5!, adminId: _6!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCall(_ reader: BufferReader) -> GroupCall? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int64?
|
||||
_3 = reader.readInt64()
|
||||
var _4: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: Int64?
|
||||
_6 = reader.readInt64()
|
||||
var _7: Api.DataJSON?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, channelId: _4, adminId: _5!, reflectorId: _6!, params: _7)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCallDiscarded(_ reader: BufferReader) -> GroupCall? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.GroupCall.groupCallDiscarded(id: _1!, accessHash: _2!, duration: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum InputGeoPoint: TypeConstructorDescription {
|
||||
case inputGeoPointEmpty
|
||||
case inputGeoPoint(flags: Int32, lat: Double, long: Double, accuracyRadius: Int32?)
|
||||
@ -1969,7 +2097,7 @@ public extension Api {
|
||||
}
|
||||
public enum ChatFull: TypeConstructorDescription {
|
||||
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?)
|
||||
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32)
|
||||
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, callMsgId: Int32?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -1992,9 +2120,9 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts):
|
||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let callMsgId):
|
||||
if boxed {
|
||||
buffer.appendInt32(-253335766)
|
||||
buffer.appendInt32(-428758403)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
@ -2027,6 +2155,7 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 18) != 0 {serializeInt32(slowmodeNextSendDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 12) != 0 {serializeInt32(statsDc!, buffer: buffer, boxed: false)}
|
||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 21) != 0 {serializeInt32(callMsgId!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -2035,8 +2164,8 @@ public extension Api {
|
||||
switch self {
|
||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId):
|
||||
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId)])
|
||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts):
|
||||
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts)])
|
||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let callMsgId):
|
||||
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("callMsgId", callMsgId)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -2155,6 +2284,8 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 12) != 0 {_26 = reader.readInt32() }
|
||||
var _27: Int32?
|
||||
_27 = reader.readInt32()
|
||||
var _28: Int32?
|
||||
if Int(_1!) & Int(1 << 21) != 0 {_28 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -2182,8 +2313,9 @@ public extension Api {
|
||||
let _c25 = (Int(_1!) & Int(1 << 18) == 0) || _25 != nil
|
||||
let _c26 = (Int(_1!) & Int(1 << 12) == 0) || _26 != nil
|
||||
let _c27 = _27 != 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 {
|
||||
return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, statsDc: _26, pts: _27!)
|
||||
let _c28 = (Int(_1!) & Int(1 << 21) == 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.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, statsDc: _26, pts: _27!, callMsgId: _28)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
@ -5266,6 +5398,148 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum GroupCallParticipant: TypeConstructorDescription {
|
||||
case groupCallParticipantAdmin(userId: Int32, source: Int32)
|
||||
case groupCallParticipant(flags: Int32, userId: Int32, date: Int32, source: Int32)
|
||||
case groupCallParticipantLeft(userId: Int32)
|
||||
case groupCallParticipantKicked(userId: Int32)
|
||||
case groupCallParticipantInvited(flags: Int32, userId: Int32, inviterId: Int32, date: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .groupCallParticipantAdmin(let userId, let source):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1513019911)
|
||||
}
|
||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||
serializeInt32(source, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .groupCallParticipant(let flags, let userId, let date, let source):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1985949076)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
serializeInt32(source, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .groupCallParticipantLeft(let userId):
|
||||
if boxed {
|
||||
buffer.appendInt32(1100680690)
|
||||
}
|
||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .groupCallParticipantKicked(let userId):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1648085351)
|
||||
}
|
||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .groupCallParticipantInvited(let flags, let userId, let inviterId, let date):
|
||||
if boxed {
|
||||
buffer.appendInt32(-874654354)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||
serializeInt32(inviterId, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .groupCallParticipantAdmin(let userId, let source):
|
||||
return ("groupCallParticipantAdmin", [("userId", userId), ("source", source)])
|
||||
case .groupCallParticipant(let flags, let userId, let date, let source):
|
||||
return ("groupCallParticipant", [("flags", flags), ("userId", userId), ("date", date), ("source", source)])
|
||||
case .groupCallParticipantLeft(let userId):
|
||||
return ("groupCallParticipantLeft", [("userId", userId)])
|
||||
case .groupCallParticipantKicked(let userId):
|
||||
return ("groupCallParticipantKicked", [("userId", userId)])
|
||||
case .groupCallParticipantInvited(let flags, let userId, let inviterId, let date):
|
||||
return ("groupCallParticipantInvited", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("date", date)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_groupCallParticipantAdmin(_ reader: BufferReader) -> GroupCallParticipant? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.GroupCallParticipant.groupCallParticipantAdmin(userId: _1!, source: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCallParticipant(_ reader: BufferReader) -> GroupCallParticipant? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, userId: _2!, date: _3!, source: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCallParticipantLeft(_ reader: BufferReader) -> GroupCallParticipant? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.GroupCallParticipant.groupCallParticipantLeft(userId: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCallParticipantKicked(_ reader: BufferReader) -> GroupCallParticipant? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.GroupCallParticipant.groupCallParticipantKicked(userId: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_groupCallParticipantInvited(_ reader: BufferReader) -> GroupCallParticipant? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.GroupCallParticipant.groupCallParticipantInvited(flags: _1!, userId: _2!, inviterId: _3!, date: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum ExportedMessageLink: TypeConstructorDescription {
|
||||
case exportedMessageLink(link: String, html: String)
|
||||
@ -6193,6 +6467,8 @@ public extension Api {
|
||||
case updateChannelUserTyping(flags: Int32, channelId: Int32, topMsgId: Int32?, userId: Int32, action: Api.SendMessageAction)
|
||||
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||
case updatePinnedChannelMessages(flags: Int32, channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||
case updateGroupCallParticipant(call: Api.InputGroupCall, participant: Api.GroupCallParticipant)
|
||||
case updateGroupCall(call: Api.GroupCall)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -6928,6 +7204,19 @@ public extension Api {
|
||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .updateGroupCallParticipant(let call, let participant):
|
||||
if boxed {
|
||||
buffer.appendInt32(92188360)
|
||||
}
|
||||
call.serialize(buffer, true)
|
||||
participant.serialize(buffer, true)
|
||||
break
|
||||
case .updateGroupCall(let call):
|
||||
if boxed {
|
||||
buffer.appendInt32(-2046916883)
|
||||
}
|
||||
call.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -7103,6 +7392,10 @@ public extension Api {
|
||||
return ("updatePinnedMessages", [("flags", flags), ("peer", peer), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
||||
case .updatePinnedChannelMessages(let flags, let channelId, let messages, let pts, let ptsCount):
|
||||
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
||||
case .updateGroupCallParticipant(let call, let participant):
|
||||
return ("updateGroupCallParticipant", [("call", call), ("participant", participant)])
|
||||
case .updateGroupCall(let call):
|
||||
return ("updateGroupCall", [("call", call)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -8575,6 +8868,37 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateGroupCallParticipant(_ reader: BufferReader) -> Update? {
|
||||
var _1: Api.InputGroupCall?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||
}
|
||||
var _2: Api.GroupCallParticipant?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.GroupCallParticipant
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.Update.updateGroupCallParticipant(call: _1!, participant: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateGroupCall(_ reader: BufferReader) -> Update? {
|
||||
var _1: Api.GroupCall?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.GroupCall
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.Update.updateGroupCall(call: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum PopularContact: TypeConstructorDescription {
|
||||
@ -10399,11 +10723,11 @@ public extension Api {
|
||||
}
|
||||
public enum InputBotInlineMessage: TypeConstructorDescription {
|
||||
case inputBotInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaGeo(flags: Int32, geoPoint: Api.InputGeoPoint, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageGame(flags: Int32, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaAuto(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaVenue(flags: Int32, geoPoint: Api.InputGeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaGeo(flags: Int32, geoPoint: Api.InputGeoPoint, heading: Int32?, period: Int32?, proximityNotificationRadius: Int32?, replyMarkup: Api.ReplyMarkup?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -10420,14 +10744,6 @@ public extension Api {
|
||||
}}
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let replyMarkup):
|
||||
if boxed {
|
||||
buffer.appendInt32(-190472735)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
geoPoint.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
case .inputBotInlineMessageGame(let flags, let replyMarkup):
|
||||
if boxed {
|
||||
buffer.appendInt32(1262639204)
|
||||
@ -10472,6 +10788,17 @@ public extension Api {
|
||||
serializeString(vcard, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let heading, let period, let proximityNotificationRadius, let replyMarkup):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1768777083)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
geoPoint.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(heading!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(proximityNotificationRadius!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -10479,8 +10806,6 @@ public extension Api {
|
||||
switch self {
|
||||
case .inputBotInlineMessageText(let flags, let message, let entities, let replyMarkup):
|
||||
return ("inputBotInlineMessageText", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let replyMarkup):
|
||||
return ("inputBotInlineMessageMediaGeo", [("flags", flags), ("geoPoint", geoPoint), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageGame(let flags, let replyMarkup):
|
||||
return ("inputBotInlineMessageGame", [("flags", flags), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup):
|
||||
@ -10489,6 +10814,8 @@ public extension Api {
|
||||
return ("inputBotInlineMessageMediaVenue", [("flags", flags), ("geoPoint", geoPoint), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup):
|
||||
return ("inputBotInlineMessageMediaContact", [("flags", flags), ("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageMediaGeo(let flags, let geoPoint, let heading, let period, let proximityNotificationRadius, let replyMarkup):
|
||||
return ("inputBotInlineMessageMediaGeo", [("flags", flags), ("geoPoint", geoPoint), ("heading", heading), ("period", period), ("proximityNotificationRadius", proximityNotificationRadius), ("replyMarkup", replyMarkup)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -10516,27 +10843,6 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputBotInlineMessageMediaGeo(_ reader: BufferReader) -> InputBotInlineMessage? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.InputGeoPoint?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint
|
||||
}
|
||||
var _3: Api.ReplyMarkup?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.InputBotInlineMessage.inputBotInlineMessageMediaGeo(flags: _1!, geoPoint: _2!, replyMarkup: _3)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputBotInlineMessageGame(_ reader: BufferReader) -> InputBotInlineMessage? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
@ -10641,6 +10947,36 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputBotInlineMessageMediaGeo(_ reader: BufferReader) -> InputBotInlineMessage? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.InputGeoPoint?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.InputGeoPoint
|
||||
}
|
||||
var _3: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
|
||||
var _4: Int32?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_4 = reader.readInt32() }
|
||||
var _5: Int32?
|
||||
if Int(_1!) & Int(1 << 3) != 0 {_5 = reader.readInt32() }
|
||||
var _6: Api.ReplyMarkup?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
|
||||
} }
|
||||
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
|
||||
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.InputBotInlineMessage.inputBotInlineMessageMediaGeo(flags: _1!, geoPoint: _2!, heading: _3, period: _4, proximityNotificationRadius: _5, replyMarkup: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum KeyboardButtonRow: TypeConstructorDescription {
|
||||
@ -12048,6 +12384,44 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum InputGroupCall: TypeConstructorDescription {
|
||||
case inputGroupCall(id: Int64, accessHash: Int64)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .inputGroupCall(let id, let accessHash):
|
||||
if boxed {
|
||||
buffer.appendInt32(-659913713)
|
||||
}
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .inputGroupCall(let id, let accessHash):
|
||||
return ("inputGroupCall", [("id", id), ("accessHash", accessHash)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_inputGroupCall(_ reader: BufferReader) -> InputGroupCall? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.InputGroupCall.inputGroupCall(id: _1!, accessHash: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum InputSingleMedia: TypeConstructorDescription {
|
||||
case inputSingleMedia(flags: Int32, media: Api.InputMedia, randomId: Int64, message: String, entities: [Api.MessageEntity]?)
|
||||
@ -21186,6 +21560,7 @@ public extension Api {
|
||||
case messageActionSecureValuesSent(types: [Api.SecureValueType])
|
||||
case messageActionContactSignUp
|
||||
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
|
||||
case messageActionGroupCall(flags: Int32, call: Api.InputGroupCall, duration: Int32?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -21365,6 +21740,14 @@ public extension Api {
|
||||
toId.serialize(buffer, true)
|
||||
serializeInt32(distance, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .messageActionGroupCall(let flags, let call, let duration):
|
||||
if boxed {
|
||||
buffer.appendInt32(2047704898)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
call.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -21418,6 +21801,8 @@ public extension Api {
|
||||
return ("messageActionContactSignUp", [])
|
||||
case .messageActionGeoProximityReached(let fromId, let toId, let distance):
|
||||
return ("messageActionGeoProximityReached", [("fromId", fromId), ("toId", toId), ("distance", distance)])
|
||||
case .messageActionGroupCall(let flags, let call, let duration):
|
||||
return ("messageActionGroupCall", [("flags", flags), ("call", call), ("duration", duration)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -21707,6 +22092,25 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageActionGroupCall(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.InputGroupCall?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||
}
|
||||
var _3: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.MessageAction.messageActionGroupCall(flags: _1!, call: _2!, duration: _3)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum PhoneCall: TypeConstructorDescription {
|
||||
|
@ -1648,6 +1648,72 @@ public struct photos {
|
||||
}
|
||||
public extension Api {
|
||||
public struct phone {
|
||||
public enum GroupCall: TypeConstructorDescription {
|
||||
case groupCall(call: Api.GroupCall, participants: [Api.GroupCallParticipant], chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .groupCall(let call, let participants, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(1731723191)
|
||||
}
|
||||
call.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(participants.count))
|
||||
for item in participants {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(chats.count))
|
||||
for item in chats {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .groupCall(let call, let participants, let chats, let users):
|
||||
return ("groupCall", [("call", call), ("participants", participants), ("chats", chats), ("users", users)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_groupCall(_ reader: BufferReader) -> GroupCall? {
|
||||
var _1: Api.GroupCall?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.GroupCall
|
||||
}
|
||||
var _2: [Api.GroupCallParticipant]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipant.self)
|
||||
}
|
||||
var _3: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _4: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.phone.GroupCall.groupCall(call: _1!, participants: _2!, chats: _3!, users: _4!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum PhoneCall: TypeConstructorDescription {
|
||||
case phoneCall(phoneCall: Api.PhoneCall, users: [Api.User])
|
||||
|
||||
@ -7118,6 +7184,111 @@ public extension Api {
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func createGroupCall(flags: Int32, channel: Api.InputChannel, randomId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1542553507)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
channel.serialize(buffer, true)
|
||||
serializeInt32(randomId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "phone.createGroupCall", parameters: [("flags", flags), ("channel", channel), ("randomId", randomId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func joinGroupCall(call: Api.InputGroupCall, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(893342305)
|
||||
call.serialize(buffer, true)
|
||||
params.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.joinGroupCall", parameters: [("call", call), ("params", params)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func leaveGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1625919071)
|
||||
call.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.leaveGroupCall", parameters: [("call", call)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func editGroupCallMember(flags: Int32, call: Api.InputGroupCall, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1662282468)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
call.serialize(buffer, true)
|
||||
userId.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.editGroupCallMember", parameters: [("flags", flags), ("call", call), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func kickGroupCallMember(flags: Int32, call: Api.InputGroupCall, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1731080446)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
call.serialize(buffer, true)
|
||||
userId.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.kickGroupCallMember", parameters: [("flags", flags), ("call", call), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func discardGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(2054648117)
|
||||
call.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.discardGroupCall", parameters: [("call", call)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
public static func getGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.GroupCall>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(209498135)
|
||||
call.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.getGroupCall", parameters: [("call", call)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.GroupCall? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.phone.GroupCall?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.phone.GroupCall
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,11 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
private var currentCallDisposable = MetaDisposable()
|
||||
private let removeCurrentCallDisposable = MetaDisposable()
|
||||
|
||||
private var currentGroupCallValue: PresentationGroupCallImpl?
|
||||
private var currentGroupCall: PresentationGroupCallImpl? {
|
||||
return self.currentGroupCallValue
|
||||
}
|
||||
|
||||
private var ringingStatesDisposable: Disposable?
|
||||
|
||||
private let hasActiveCallsPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
@ -72,6 +77,11 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
return self.currentCallPromise.get()
|
||||
}
|
||||
|
||||
private let currentGroupCallPromise = Promise<PresentationGroupCall?>(nil)
|
||||
public var currentGroupCallSignal: Signal<PresentationGroupCall?, NoError> {
|
||||
return self.currentGroupCallPromise.get()
|
||||
}
|
||||
|
||||
private let startCallDisposable = MetaDisposable()
|
||||
|
||||
private var proxyServer: ProxyServerSettings?
|
||||
@ -566,4 +576,100 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
self.resumeMediaPlayback()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateCurrentGroupCall(_ value: PresentationGroupCallImpl?) {
|
||||
let wasEmpty = self.currentGroupCallValue == nil
|
||||
let isEmpty = value == nil
|
||||
if wasEmpty && !isEmpty {
|
||||
self.resumeMedia = self.isMediaPlaying()
|
||||
}
|
||||
|
||||
self.currentGroupCallValue = value
|
||||
|
||||
if !wasEmpty && isEmpty && self.resumeMedia {
|
||||
self.resumeMedia = false
|
||||
self.resumeMediaPlayback()
|
||||
}
|
||||
}
|
||||
|
||||
public func requestOrJoinGroupCall(context: AccountContext, peerId: PeerId) {
|
||||
let begin: () -> Void = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.startGroupCall(account: context.account, peerId: peerId).start()
|
||||
}
|
||||
begin()
|
||||
}
|
||||
|
||||
private func startGroupCall(
|
||||
account: Account,
|
||||
peerId: PeerId,
|
||||
internalId: CallSessionInternalId = CallSessionInternalId()
|
||||
) -> Signal<Bool, NoError> {
|
||||
let (presentationData, present, openSettings) = self.getDeviceAccessData()
|
||||
|
||||
let isVideo = false
|
||||
|
||||
let accessEnabledSignal: Signal<Bool, NoError> = Signal { subscriber in
|
||||
DeviceAccess.authorizeAccess(to: .microphone(.voiceCall), presentationData: presentationData, present: { c, a in
|
||||
present(c, a)
|
||||
}, openSettings: {
|
||||
openSettings()
|
||||
}, { value in
|
||||
if isVideo && value {
|
||||
DeviceAccess.authorizeAccess(to: .camera(.videoCall), presentationData: presentationData, present: { c, a in
|
||||
present(c, a)
|
||||
}, openSettings: {
|
||||
openSettings()
|
||||
}, { value in
|
||||
subscriber.putNext(value)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
} else {
|
||||
subscriber.putNext(value)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return EmptyDisposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|
||||
return accessEnabledSignal
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { [weak self] accessEnabled -> Signal<Bool, NoError> in
|
||||
guard let strongSelf = self else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
if !accessEnabled {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
let call = PresentationGroupCallImpl(
|
||||
account: account,
|
||||
audioSession: strongSelf.audioSession,
|
||||
callKitIntegration: nil,
|
||||
getDeviceAccessData: strongSelf.getDeviceAccessData,
|
||||
internalId: internalId,
|
||||
peerId: peerId,
|
||||
peer: nil
|
||||
)
|
||||
strongSelf.updateCurrentGroupCall(call)
|
||||
strongSelf.currentGroupCallPromise.set(.single(call))
|
||||
strongSelf.hasActiveCallsPromise.set(true)
|
||||
strongSelf.removeCurrentCallDisposable.set((call.canBeRemoved.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak call] value in
|
||||
if value, let strongSelf = self, let call = call {
|
||||
if strongSelf.currentGroupCall === call {
|
||||
strongSelf.updateCurrentGroupCall(nil)
|
||||
strongSelf.currentGroupCallPromise.set(.single(nil))
|
||||
strongSelf.hasActiveCallsPromise.set(false)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
return .single(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
346
submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift
Normal file
346
submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift
Normal file
@ -0,0 +1,346 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import AVFoundation
|
||||
import TelegramVoip
|
||||
import TelegramAudio
|
||||
import TelegramUIPreferences
|
||||
import TelegramPresentationData
|
||||
import DeviceAccess
|
||||
import UniversalMediaPlayer
|
||||
import AccountContext
|
||||
|
||||
public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
private enum InternalState {
|
||||
case requesting
|
||||
case active(GroupCallInfo)
|
||||
case estabilished(GroupCallInfo, String, [Int32])
|
||||
|
||||
var callInfo: GroupCallInfo? {
|
||||
switch self {
|
||||
case .requesting:
|
||||
return nil
|
||||
case let .active(info):
|
||||
return info
|
||||
case let .estabilished(info, _, _):
|
||||
return info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public let account: Account
|
||||
private let audioSession: ManagedAudioSession
|
||||
private let callKitIntegration: CallKitIntegration?
|
||||
public var isIntegratedWithCallKit: Bool {
|
||||
return self.callKitIntegration != nil
|
||||
}
|
||||
|
||||
private let getDeviceAccessData: () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void)
|
||||
|
||||
public let internalId: CallSessionInternalId
|
||||
public let peerId: PeerId
|
||||
public let peer: Peer?
|
||||
|
||||
private var internalState: InternalState = .requesting
|
||||
|
||||
private var callContext: OngoingGroupCallContext?
|
||||
|
||||
private var sessionStateDisposable: Disposable?
|
||||
|
||||
private let isMutedPromise = ValuePromise<Bool>(false)
|
||||
private var isMutedValue = false
|
||||
public var isMuted: Signal<Bool, NoError> {
|
||||
return self.isMutedPromise.get()
|
||||
}
|
||||
|
||||
private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil))
|
||||
private var audioOutputStateValue: ([AudioSessionOutput], AudioSessionOutput?) = ([], nil)
|
||||
private var currentAudioOutputValue: AudioSessionOutput = .builtin
|
||||
public var audioOutputState: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> {
|
||||
return self.audioOutputStatePromise.get()
|
||||
}
|
||||
|
||||
private var audioSessionControl: ManagedAudioSessionControl?
|
||||
private var audioSessionDisposable: Disposable?
|
||||
private let audioSessionShouldBeActive = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
private var audioSessionShouldBeActiveDisposable: Disposable?
|
||||
private let audioSessionActive = Promise<Bool>(false)
|
||||
private var audioSessionActiveDisposable: Disposable?
|
||||
private var isAudioSessionActive = false
|
||||
|
||||
let canBeRemoved = Promise<Bool>(false)
|
||||
|
||||
private let requestDisposable = MetaDisposable()
|
||||
private var groupCallParticipantUpdatesDisposable: Disposable?
|
||||
|
||||
init(
|
||||
account: Account,
|
||||
audioSession: ManagedAudioSession,
|
||||
callKitIntegration: CallKitIntegration?,
|
||||
getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void),
|
||||
internalId: CallSessionInternalId,
|
||||
peerId: PeerId,
|
||||
peer: Peer?
|
||||
) {
|
||||
self.account = account
|
||||
self.audioSession = audioSession
|
||||
self.callKitIntegration = callKitIntegration
|
||||
self.getDeviceAccessData = getDeviceAccessData
|
||||
|
||||
self.internalId = internalId
|
||||
self.peerId = peerId
|
||||
self.peer = peer
|
||||
|
||||
var didReceiveAudioOutputs = false
|
||||
|
||||
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSessionState(internalState: strongSelf.internalState, audioSessionControl: control)
|
||||
}
|
||||
}
|
||||
}, deactivate: { [weak self] in
|
||||
return Signal { subscriber in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateIsAudioSessionActive(false)
|
||||
strongSelf.updateSessionState(internalState: strongSelf.internalState, audioSessionControl: nil)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}, availableOutputsChanged: { [weak self] availableOutputs, currentOutput in
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.audioOutputStateValue = (availableOutputs, currentOutput)
|
||||
|
||||
var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput))
|
||||
if !didReceiveAudioOutputs {
|
||||
didReceiveAudioOutputs = true
|
||||
if currentOutput == .speaker {
|
||||
signal = .single((availableOutputs, .builtin))
|
||||
|> then(
|
||||
signal
|
||||
|> delay(1.0, queue: Queue.mainQueue())
|
||||
)
|
||||
}
|
||||
}
|
||||
strongSelf.audioOutputStatePromise.set(signal)
|
||||
}
|
||||
})
|
||||
|
||||
self.audioSessionShouldBeActiveDisposable = (self.audioSessionShouldBeActive.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
if value {
|
||||
if let audioSessionControl = strongSelf.audioSessionControl {
|
||||
let audioSessionActive: Signal<Bool, NoError>
|
||||
if let callKitIntegration = strongSelf.callKitIntegration {
|
||||
audioSessionActive = callKitIntegration.audioSessionActive
|
||||
|> filter { $0 }
|
||||
|> timeout(2.0, queue: Queue.mainQueue(), alternate: Signal { subscriber in
|
||||
if let strongSelf = self, let _ = strongSelf.audioSessionControl {
|
||||
}
|
||||
subscriber.putNext(true)
|
||||
subscriber.putCompletion()
|
||||
return EmptyDisposable
|
||||
})
|
||||
} else {
|
||||
audioSessionControl.activate({ _ in })
|
||||
audioSessionActive = .single(true)
|
||||
}
|
||||
strongSelf.audioSessionActive.set(audioSessionActive)
|
||||
} else {
|
||||
strongSelf.audioSessionActive.set(.single(false))
|
||||
}
|
||||
} else {
|
||||
strongSelf.audioSessionActive.set(.single(false))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.audioSessionActiveDisposable = (self.audioSessionActive.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateIsAudioSessionActive(value)
|
||||
}
|
||||
})
|
||||
|
||||
self.requestCall()
|
||||
|
||||
self.groupCallParticipantUpdatesDisposable = (self.account.stateManager.groupCallParticipantUpdates
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updates in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if case let .estabilished(callInfo, _, _) = strongSelf.internalState {
|
||||
var addedSsrc: [Int32] = []
|
||||
for (callId, ssrc) in updates {
|
||||
if callId == callInfo.id {
|
||||
addedSsrc.append(ssrc)
|
||||
}
|
||||
}
|
||||
if !addedSsrc.isEmpty {
|
||||
strongSelf.callContext?.addSsrcs(ssrcs: addedSsrc)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.audioSessionShouldBeActiveDisposable?.dispose()
|
||||
self.audioSessionActiveDisposable?.dispose()
|
||||
self.sessionStateDisposable?.dispose()
|
||||
self.audioSessionDisposable?.dispose()
|
||||
self.requestDisposable.dispose()
|
||||
self.groupCallParticipantUpdatesDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func updateSessionState(internalState: InternalState, audioSessionControl: ManagedAudioSessionControl?) {
|
||||
let previousControl = self.audioSessionControl
|
||||
self.audioSessionControl = audioSessionControl
|
||||
|
||||
let previousInternalState = self.internalState
|
||||
self.internalState = internalState
|
||||
|
||||
if let audioSessionControl = audioSessionControl, previousControl == nil {
|
||||
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
|
||||
audioSessionControl.setup(synchronous: true)
|
||||
}
|
||||
|
||||
self.audioSessionShouldBeActive.set(true)
|
||||
|
||||
switch previousInternalState {
|
||||
case .active:
|
||||
break
|
||||
default:
|
||||
if case let .active(callInfo) = internalState {
|
||||
let callContext = OngoingGroupCallContext()
|
||||
self.callContext = callContext
|
||||
self.requestDisposable.set((callContext.joinPayload
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] joinPayload in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.requestDisposable.set((joinGroupCall(
|
||||
account: strongSelf.account,
|
||||
callId: callInfo.id,
|
||||
accessHash: callInfo.accessHash,
|
||||
joinPayload: joinPayload
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { joinCallResult in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let clientParams = joinCallResult.callInfo.clientParams {
|
||||
strongSelf.updateSessionState(internalState: .estabilished(joinCallResult.callInfo, clientParams, joinCallResult.ssrcs), audioSessionControl: strongSelf.audioSessionControl)
|
||||
}
|
||||
}))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
switch previousInternalState {
|
||||
case .estabilished:
|
||||
break
|
||||
default:
|
||||
if case let .estabilished(_, clientParams, ssrcs) = internalState {
|
||||
self.callContext?.setJoinResponse(payload: clientParams, ssrcs: ssrcs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateIsAudioSessionActive(_ value: Bool) {
|
||||
if self.isAudioSessionActive != value {
|
||||
self.isAudioSessionActive = value
|
||||
}
|
||||
}
|
||||
|
||||
public func hangUp() -> Signal<Bool, NoError> {
|
||||
return .single(true)
|
||||
}
|
||||
|
||||
public func toggleIsMuted() {
|
||||
self.setIsMuted(!self.isMutedValue)
|
||||
}
|
||||
|
||||
public func setIsMuted(_ value: Bool) {
|
||||
self.isMutedValue = value
|
||||
self.isMutedPromise.set(self.isMutedValue)
|
||||
self.callContext?.setIsMuted(self.isMutedValue)
|
||||
}
|
||||
|
||||
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
||||
guard self.currentAudioOutputValue != output else {
|
||||
return
|
||||
}
|
||||
self.currentAudioOutputValue = output
|
||||
|
||||
self.audioOutputStatePromise.set(.single((self.audioOutputStateValue.0, output))
|
||||
|> then(
|
||||
.single(self.audioOutputStateValue)
|
||||
|> delay(1.0, queue: Queue.mainQueue())
|
||||
))
|
||||
|
||||
if let audioSessionControl = self.audioSessionControl {
|
||||
audioSessionControl.setOutputMode(.custom(output))
|
||||
}
|
||||
}
|
||||
|
||||
private func requestCall() {
|
||||
self.internalState = .requesting
|
||||
|
||||
enum CallError {
|
||||
case generic
|
||||
}
|
||||
|
||||
let account = self.account
|
||||
let peerId = self.peerId
|
||||
|
||||
let currentCall = getCurrentGroupCall(account: account, peerId: peerId)
|
||||
|> mapError { _ -> CallError in
|
||||
return .generic
|
||||
}
|
||||
|
||||
let currentOrRequestedCall = currentCall
|
||||
|> mapToSignal { callInfo -> Signal<GroupCallInfo, CallError> in
|
||||
if let callInfo = callInfo {
|
||||
return .single(callInfo)
|
||||
} else {
|
||||
return createGroupCall(account: account, peerId: peerId)
|
||||
|> mapError { _ -> CallError in
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let restartedCall = currentOrRequestedCall
|
||||
|> mapToSignal { value -> Signal<GroupCallInfo, CallError> in
|
||||
let stopped: Signal<GroupCallInfo, CallError> = stopGroupCall(account: account, callId: value.id, accessHash: value.accessHash)
|
||||
|> mapError { _ -> CallError in
|
||||
return .generic
|
||||
}
|
||||
|> map { _ -> GroupCallInfo in
|
||||
}
|
||||
|
||||
return stopped
|
||||
|> then(currentOrRequestedCall)
|
||||
}
|
||||
|
||||
self.requestDisposable.set((currentOrRequestedCall
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl)
|
||||
}))
|
||||
}
|
||||
}
|
@ -110,6 +110,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateChatListFilterOrder(order: [Int32])
|
||||
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
|
||||
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
|
||||
case UpdateGroupCallParticipant(id: Int64, accessHash: Int64, participant: Api.GroupCallParticipant)
|
||||
}
|
||||
|
||||
struct HoleFromPreviousState {
|
||||
@ -276,6 +277,10 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateReadThread(threadMessageId: threadMessageId, readMaxId: readMaxId, isIncoming: isIncoming, mainChannelMessage: mainChannelMessage))
|
||||
}
|
||||
|
||||
mutating func updateGroupCallParticipant(id: Int64, accessHash: Int64, participant: Api.GroupCallParticipant) {
|
||||
self.addOperation(.UpdateGroupCallParticipant(id: id, accessHash: accessHash, participant: participant))
|
||||
}
|
||||
|
||||
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {
|
||||
self.addOperation(.ReadGroupFeedInbox(groupId, index))
|
||||
}
|
||||
@ -484,7 +489,7 @@ struct AccountMutableState {
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateMessagesPinned:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipant, .UpdateMessagesPinned:
|
||||
break
|
||||
case let .AddMessages(messages, location):
|
||||
for message in messages {
|
||||
@ -602,6 +607,7 @@ struct AccountReplayedFinalState {
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let addedCallSignalingData: [(Int64, Data)]
|
||||
let updatedGroupCallParticipants: [(Int64, Int32)]
|
||||
let updatedPeersNearby: [PeerNearby]?
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let delayNotificatonsUntil: Int32?
|
||||
@ -617,6 +623,7 @@ struct AccountFinalStateEvents {
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let addedCallSignalingData: [(Int64, Data)]
|
||||
let updatedGroupCallParticipants: [(Int64, Int32)]
|
||||
let updatedPeersNearby: [PeerNearby]?
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let displayAlerts: [(text: String, isDropAuth: Bool)]
|
||||
@ -629,10 +636,10 @@ struct AccountFinalStateEvents {
|
||||
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, Int32)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||
self.deletedMessageIds = deletedMessageIds
|
||||
@ -640,6 +647,7 @@ struct AccountFinalStateEvents {
|
||||
self.updatedWebpages = updatedWebpages
|
||||
self.updatedCalls = updatedCalls
|
||||
self.addedCallSignalingData = addedCallSignalingData
|
||||
self.updatedGroupCallParticipants = updatedGroupCallParticipants
|
||||
self.updatedPeersNearby = updatedPeersNearby
|
||||
self.isContactUpdates = isContactUpdates
|
||||
self.displayAlerts = displayAlerts
|
||||
@ -660,6 +668,7 @@ struct AccountFinalStateEvents {
|
||||
self.updatedWebpages = state.updatedWebpages
|
||||
self.updatedCalls = state.updatedCalls
|
||||
self.addedCallSignalingData = state.addedCallSignalingData
|
||||
self.updatedGroupCallParticipants = state.updatedGroupCallParticipants
|
||||
self.updatedPeersNearby = state.updatedPeersNearby
|
||||
self.isContactUpdates = state.isContactUpdates
|
||||
self.displayAlerts = state.state.state.displayAlerts
|
||||
@ -695,6 +704,6 @@ struct AccountFinalStateEvents {
|
||||
let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId)
|
||||
let authorizationListUpdated = self.authorizationListUpdated || other.authorizationListUpdated
|
||||
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }))
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }))
|
||||
}
|
||||
}
|
||||
|
@ -1306,6 +1306,11 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
updatedState.addUpdateCall(phoneCall)
|
||||
case let .updatePhoneCallSignalingData(phoneCallId, data):
|
||||
updatedState.addCallSignalingData(callId: phoneCallId, data: data.makeData())
|
||||
case let .updateGroupCallParticipant(call, participant):
|
||||
switch call {
|
||||
case let .inputGroupCall(id, accessHash):
|
||||
updatedState.updateGroupCallParticipant(id: id, accessHash: accessHash, participant: participant)
|
||||
}
|
||||
case let .updateLangPackTooLong(langCode):
|
||||
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
||||
case let .updateLangPack(difference):
|
||||
@ -2109,7 +2114,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddScheduledMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipant:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -2196,6 +2201,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
var updatedWebpages: [MediaId: TelegramMediaWebpage] = [:]
|
||||
var updatedCalls: [Api.PhoneCall] = []
|
||||
var addedCallSignalingData: [(Int64, Data)] = []
|
||||
var updatedGroupCallParticipants: [(Int64, Int32)] = []
|
||||
var updatedPeersNearby: [PeerNearby]?
|
||||
var isContactUpdates: [(PeerId, Bool)] = []
|
||||
var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = []
|
||||
@ -2925,6 +2931,23 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
updatedCalls.append(call)
|
||||
case let .AddCallSignalingData(callId, data):
|
||||
addedCallSignalingData.append((callId, data))
|
||||
case let .UpdateGroupCallParticipant(callId, _, participant):
|
||||
var ssrc: Int32?
|
||||
switch participant {
|
||||
case let .groupCallParticipantAdmin(_, source):
|
||||
ssrc = source
|
||||
case let .groupCallParticipant(_, _, _, source):
|
||||
ssrc = source
|
||||
case .groupCallParticipantLeft:
|
||||
break
|
||||
case .groupCallParticipantKicked:
|
||||
break
|
||||
case .groupCallParticipantInvited:
|
||||
break
|
||||
}
|
||||
if let ssrc = ssrc {
|
||||
updatedGroupCallParticipants.append((callId, ssrc))
|
||||
}
|
||||
case let .UpdateLangPack(langCode, difference):
|
||||
if let difference = difference {
|
||||
if langPackDifferences[langCode] == nil {
|
||||
@ -3347,5 +3370,5 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
requestChatListFiltersSync(transaction: transaction)
|
||||
}
|
||||
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates)
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates)
|
||||
}
|
||||
|
@ -148,6 +148,11 @@ public final class AccountStateManager {
|
||||
return self.threadReadStateUpdatesPipe.signal()
|
||||
}
|
||||
|
||||
private let groupCallParticipantUpdatesPipe = ValuePipe<[(Int64, Int32)]>()
|
||||
public var groupCallParticipantUpdates: Signal<[(Int64, Int32)], NoError> {
|
||||
return self.groupCallParticipantUpdatesPipe.signal()
|
||||
}
|
||||
|
||||
private let deletedMessagesPipe = ValuePipe<[DeletedMessageId]>()
|
||||
public var deletedMessages: Signal<[DeletedMessageId], NoError> {
|
||||
return self.deletedMessagesPipe.signal()
|
||||
@ -673,6 +678,9 @@ public final class AccountStateManager {
|
||||
strongSelf.callSessionManager.addCallSignalingData(id: id, data: data)
|
||||
}
|
||||
}
|
||||
if !events.updatedGroupCallParticipants.isEmpty {
|
||||
strongSelf.groupCallParticipantUpdatesPipe.putNext(events.updatedGroupCallParticipants)
|
||||
}
|
||||
if !events.updatedIncomingThreadReadStates.isEmpty || !events.updatedOutgoingThreadReadStates.isEmpty {
|
||||
strongSelf.threadReadStateUpdatesPipe.putNext((events.updatedIncomingThreadReadStates, events.updatedOutgoingThreadReadStates))
|
||||
}
|
||||
|
287
submodules/TelegramCore/Sources/GroupCalls.swift
Normal file
287
submodules/TelegramCore/Sources/GroupCalls.swift
Normal file
@ -0,0 +1,287 @@
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
import SyncCore
|
||||
|
||||
public struct GroupCallInfo: Equatable {
|
||||
public var id: Int64
|
||||
public var accessHash: Int64
|
||||
public var peerId: PeerId?
|
||||
public var clientParams: String?
|
||||
}
|
||||
|
||||
private extension GroupCallInfo {
|
||||
init?(_ call: Api.GroupCall) {
|
||||
switch call {
|
||||
case let .groupCallPrivate(_, id, accessHash, channelId, _, _):
|
||||
self.init(
|
||||
id: id,
|
||||
accessHash: accessHash,
|
||||
peerId: channelId.flatMap { PeerId(namespace: Namespaces.Peer.CloudChannel, id: $0) },
|
||||
clientParams: nil
|
||||
)
|
||||
case let .groupCall(_, id, accessHash, channelId, _, _, params):
|
||||
var clientParams: String?
|
||||
if let params = params {
|
||||
switch params {
|
||||
case let .dataJSON(data):
|
||||
clientParams = data
|
||||
}
|
||||
}
|
||||
self.init(
|
||||
id: id,
|
||||
accessHash: accessHash,
|
||||
peerId: channelId.flatMap { PeerId(namespace: Namespaces.Peer.CloudChannel, id: $0) },
|
||||
clientParams: clientParams
|
||||
)
|
||||
case .groupCallDiscarded:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum GetCurrentGroupCallError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func getCurrentGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCallInfo?, GetCurrentGroupCallError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> castError(GetCurrentGroupCallError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<MessageId?, GetCurrentGroupCallError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return account.network.request(Api.functions.channels.getFullChannel(channel: inputPeer))
|
||||
|> mapError { _ -> GetCurrentGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<MessageId?, GetCurrentGroupCallError> in
|
||||
switch result {
|
||||
case let .chatFull(fullChat, _, _):
|
||||
switch fullChat {
|
||||
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, callMsgId):
|
||||
return .single(callMsgId.flatMap { callMsgId in
|
||||
MessageId(peerId: peerId, namespace: Namespaces.Peer.CloudChannel, id: callMsgId)
|
||||
})
|
||||
default:
|
||||
return .single(nil)
|
||||
}
|
||||
default:
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> mapToSignal { messageId -> Signal<GroupCallInfo?, GetCurrentGroupCallError> in
|
||||
guard let messageId = messageId else {
|
||||
return .single(nil)
|
||||
}
|
||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> castError(GetCurrentGroupCallError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<GroupCallInfo?, GetCurrentGroupCallError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return account.network.request(Api.functions.channels.getMessages(channel: inputPeer, id: [.inputMessageID(id: messageId.id)]))
|
||||
|> mapError { _ -> GetCurrentGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<GroupCallInfo?, GetCurrentGroupCallError> in
|
||||
let messages: [Api.Message]
|
||||
let chats: [Api.Chat]
|
||||
let users: [Api.User]
|
||||
|
||||
switch result {
|
||||
case let .messages(apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .messagesSlice(_, _, _, _, messages: apiMessages, chats: apiChats, users: apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
|
||||
messages = apiMessages
|
||||
chats = apiChats
|
||||
users = apiUsers
|
||||
case .messagesNotModified:
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
guard let apiMessage = messages.first else {
|
||||
return .single(nil)
|
||||
}
|
||||
guard let message = StoreMessage(apiMessage: apiMessage) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
var maybeInputCall: Api.InputGroupCall?
|
||||
loop: for media in message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
case let .groupPhoneCall(callId, accessHash, _):
|
||||
maybeInputCall = .inputGroupCall(id: callId, accessHash: accessHash)
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let inputCall = maybeInputCall else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.phone.getGroupCall(call: inputCall))
|
||||
|> mapError { _ -> GetCurrentGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<GroupCallInfo?, GetCurrentGroupCallError> in
|
||||
switch result {
|
||||
case let .groupCall(call, participants, chats, users):
|
||||
return account.postbox.transaction { transaction -> GroupCallInfo? in
|
||||
return GroupCallInfo(call)
|
||||
}
|
||||
|> mapError { _ -> GetCurrentGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CreateGroupCallError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCallInfo, CreateGroupCallError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> castError(CreateGroupCallError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<GroupCallInfo, CreateGroupCallError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.phone.createGroupCall(flags: 0, channel: inputPeer, randomId: Int32.random(in: Int32.min ... Int32.max)))
|
||||
|> mapError { _ -> CreateGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<GroupCallInfo, CreateGroupCallError> in
|
||||
account.stateManager.addUpdates(result)
|
||||
|
||||
var parsedCall: GroupCallInfo?
|
||||
loop: for update in result.allUpdates {
|
||||
switch update {
|
||||
case let .updateGroupCall(call):
|
||||
parsedCall = GroupCallInfo(call)
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let parsedCall = parsedCall {
|
||||
return .single(parsedCall)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum JoinGroupCallError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public struct JoinGroupCallResult {
|
||||
public var callInfo: GroupCallInfo
|
||||
public var ssrcs: [Int32]
|
||||
}
|
||||
|
||||
public func joinGroupCall(account: Account, callId: Int64, accessHash: Int64, joinPayload: String) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
||||
return account.network.request(Api.functions.phone.joinGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash), params: .dataJSON(data: joinPayload)))
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||
return account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||
account.stateManager.addUpdates(updates)
|
||||
|
||||
var maybeParsedCall: GroupCallInfo?
|
||||
loop: for update in updates.allUpdates {
|
||||
switch update {
|
||||
case let .updateGroupCall(call):
|
||||
maybeParsedCall = GroupCallInfo(call)
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
guard let parsedCall = maybeParsedCall else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
switch result {
|
||||
case let .groupCall(call, participants, chats, users):
|
||||
guard let _ = GroupCallInfo(call) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
var ssrcs: [Int32] = []
|
||||
for participant in participants {
|
||||
var ssrc: Int32?
|
||||
switch participant {
|
||||
case let .groupCallParticipantAdmin(_, source):
|
||||
ssrc = source
|
||||
case let .groupCallParticipant(_, _, _, source):
|
||||
ssrc = source
|
||||
case .groupCallParticipantLeft:
|
||||
break
|
||||
case .groupCallParticipantKicked:
|
||||
break
|
||||
case .groupCallParticipantInvited:
|
||||
break
|
||||
}
|
||||
if let ssrc = ssrc {
|
||||
ssrcs.append(ssrc)
|
||||
}
|
||||
}
|
||||
return account.postbox.transaction { transaction -> JoinGroupCallResult in
|
||||
return JoinGroupCallResult(
|
||||
callInfo: parsedCall,
|
||||
ssrcs: ssrcs
|
||||
)
|
||||
}
|
||||
|> castError(JoinGroupCallError.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum StopGroupCallError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func stopGroupCall(account: Account, callId: Int64, accessHash: Int64) -> Signal<Never, StopGroupCallError> {
|
||||
return account.network.request(Api.functions.phone.discardGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
||||
|> mapError { _ -> StopGroupCallError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, StopGroupCallError> in
|
||||
account.stateManager.addUpdates(result)
|
||||
|
||||
return .complete()
|
||||
}
|
||||
}
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 121
|
||||
return 122
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -188,7 +188,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp:
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall:
|
||||
break
|
||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))
|
||||
|
@ -59,6 +59,11 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return TelegramMediaAction(action: .peerJoined)
|
||||
case let .messageActionGeoProximityReached(fromId, toId, distance):
|
||||
return TelegramMediaAction(action: .geoProximityReached(from: fromId.peerId, to: toId.peerId, distance: distance))
|
||||
case let .messageActionGroupCall(_, call, duration):
|
||||
switch call {
|
||||
case let .inputGroupCall(id, accessHash):
|
||||
return TelegramMediaAction(action: .groupPhoneCall(callId: id, accessHash: accessHash, duration: duration))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
||||
}
|
||||
|
||||
switch fullChat {
|
||||
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts):
|
||||
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts, callMsgId):
|
||||
var channelFlags = CachedChannelFlags()
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
channelFlags.insert(.canDisplayParticipants)
|
||||
|
@ -338,6 +338,21 @@ extension Api.Update {
|
||||
}
|
||||
}
|
||||
|
||||
extension Api.Updates {
|
||||
var allUpdates: [Api.Update] {
|
||||
switch self {
|
||||
case let .updates(updates, _, _, _, _):
|
||||
return updates
|
||||
case let .updatesCombined(updates, _, _, _, _, _):
|
||||
return updates
|
||||
case let .updateShort(update, _):
|
||||
return [update]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Api.Updates {
|
||||
var rawMessageIds: [Int32] {
|
||||
switch self {
|
||||
|
@ -404,6 +404,15 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
case let .groupPhoneCall(_, _, duration):
|
||||
//TODO:localize
|
||||
let titleString: String
|
||||
if let duration = duration {
|
||||
titleString = "Group Call \(duration)s"
|
||||
} else {
|
||||
titleString = "Group Call"
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
case let .customText(text, entities):
|
||||
attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false)
|
||||
case let .botDomainAccessGranted(domain):
|
||||
|
@ -949,6 +949,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
||||
displayLeave = false
|
||||
if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
|
||||
result.append(.addMember)
|
||||
result.append(.call)
|
||||
}
|
||||
}
|
||||
switch channel.participationStatus {
|
||||
|
@ -3163,6 +3163,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
|
||||
private func requestCall(isVideo: Bool) {
|
||||
if let peer = self.data?.peer as? TelegramChannel {
|
||||
self.context.sharedContext.callManager?.requestOrJoinGroupCall(context: self.context, peerId: peer.id)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard let peer = self.data?.peer as? TelegramUser, let cachedUserData = self.data?.cachedData as? CachedUserData else {
|
||||
return
|
||||
}
|
||||
|
@ -732,7 +732,7 @@ private extension ConferenceDescription {
|
||||
let videoMid: String?
|
||||
if stream.isMain {
|
||||
audioMid = "0"
|
||||
if let videoSsrc = stream.videoSsrc {
|
||||
if let _ = stream.videoSsrc {
|
||||
videoMid = "1"
|
||||
} else {
|
||||
videoMid = nil
|
||||
@ -740,7 +740,7 @@ private extension ConferenceDescription {
|
||||
} else {
|
||||
audioMid = "audio\(stream.audioSsrc)"
|
||||
if let videoSsrc = stream.videoSsrc {
|
||||
videoMid = "video\(stream.videoSsrc)"
|
||||
videoMid = "video\(videoSsrc)"
|
||||
} else {
|
||||
videoMid = nil
|
||||
}
|
||||
@ -1590,17 +1590,6 @@ public final class GroupCallContext {
|
||||
strongSelf.relaySdpAnswer(sdpAnswer: offerSdp)
|
||||
}
|
||||
})
|
||||
|
||||
/*guard let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: bundleId, bridgeHost: strongSelf.colibriHost, transport: transport, currentState: strongSelf.currentOfferState) else {
|
||||
return
|
||||
}
|
||||
strongSelf.currentOfferState = offer.state
|
||||
|
||||
strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count)
|
||||
|
||||
for sdp in offer.sdpList {
|
||||
strongSelf.context.setOfferSdp(sdp, isPartial: false)
|
||||
}*/
|
||||
}))
|
||||
}
|
||||
|
||||
@ -1698,8 +1687,6 @@ public final class GroupCallContext {
|
||||
|
||||
if let offer = conference.offerSdp(sessionId: strongSelf.sessionId, bundleId: localBundleId, bridgeHost: strongSelf.colibriHost, transport: localTransport, currentState: strongSelf.currentOfferState, isAnswer: false) {
|
||||
strongSelf.currentOfferState = offer.state
|
||||
let queue = strongSelf.queue
|
||||
|
||||
strongSelf.memberCount.set(offer.state.items.filter({ !$0.isRemoved }).count)
|
||||
|
||||
for sdp in offer.sdpList {
|
||||
@ -1837,6 +1824,14 @@ public final class GroupCallContext {
|
||||
self.context.setIsMuted(self.isMutedValue)
|
||||
}
|
||||
|
||||
func setIsMuted(_ isMuted: Bool) {
|
||||
if self.isMutedValue != isMuted {
|
||||
self.isMutedValue = isMuted
|
||||
self.isMuted.set(self.isMutedValue)
|
||||
self.context.setIsMuted(self.isMutedValue)
|
||||
}
|
||||
}
|
||||
|
||||
func makeIncomingVideoView(id: String, completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
|
||||
self.context.makeIncomingVideoView(withStreamId: id, completion: { view in
|
||||
if let view = view {
|
||||
@ -1929,6 +1924,12 @@ public final class GroupCallContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func setIsMuted(_ isMuted: Bool) {
|
||||
self.impl.with { impl in
|
||||
impl.setIsMuted(isMuted)
|
||||
}
|
||||
}
|
||||
|
||||
public func makeIncomingVideoView(id: String, completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
|
||||
self.impl.with { impl in
|
||||
impl.makeIncomingVideoView(id: id, completion: completion)
|
||||
@ -1936,3 +1937,527 @@ public final class GroupCallContext {
|
||||
}
|
||||
}
|
||||
|
||||
private struct ParsedJoinPayload {
|
||||
var payload: String
|
||||
var audioSsrc: UInt32
|
||||
}
|
||||
|
||||
private func parseSdpIntoJoinPayload(sdp: String) -> ParsedJoinPayload? {
|
||||
let lines = sdp.components(separatedBy: "\n")
|
||||
|
||||
var videoLines: [String] = []
|
||||
var audioLines: [String] = []
|
||||
var isAudioLine = false
|
||||
var isVideoLine = false
|
||||
for line in lines {
|
||||
if line.hasPrefix("m=audio") {
|
||||
isAudioLine = true
|
||||
isVideoLine = false
|
||||
} else if line.hasPrefix("m=video") {
|
||||
isVideoLine = true
|
||||
isAudioLine = false
|
||||
}
|
||||
|
||||
if isAudioLine {
|
||||
audioLines.append(line)
|
||||
} else if isVideoLine {
|
||||
videoLines.append(line)
|
||||
}
|
||||
}
|
||||
|
||||
func getLines(prefix: String) -> [String] {
|
||||
var result: [String] = []
|
||||
for line in lines {
|
||||
if line.hasPrefix(prefix) {
|
||||
var cleanLine = String(line[line.index(line.startIndex, offsetBy: prefix.count)...])
|
||||
if cleanLine.hasSuffix("\r") {
|
||||
cleanLine.removeLast()
|
||||
}
|
||||
result.append(cleanLine)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getLines(prefix: String, isAudio: Bool) -> [String] {
|
||||
var result: [String] = []
|
||||
for line in (isAudio ? audioLines : videoLines) {
|
||||
if line.hasPrefix(prefix) {
|
||||
var cleanLine = String(line[line.index(line.startIndex, offsetBy: prefix.count)...])
|
||||
if cleanLine.hasSuffix("\r") {
|
||||
cleanLine.removeLast()
|
||||
}
|
||||
result.append(cleanLine)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var audioSources: [Int] = []
|
||||
for line in getLines(prefix: "a=ssrc:", isAudio: true) {
|
||||
let scanner = Scanner(string: line)
|
||||
if #available(iOS 13.0, *) {
|
||||
if let ssrc = scanner.scanInt() {
|
||||
if !audioSources.contains(ssrc) {
|
||||
audioSources.append(ssrc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let ssrc = audioSources.first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let ufrag = getLines(prefix: "a=ice-ufrag:").first else {
|
||||
return nil
|
||||
}
|
||||
guard let pwd = getLines(prefix: "a=ice-pwd:").first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var resultPayload: [String: Any] = [:]
|
||||
|
||||
var fingerprints: [[String: Any]] = []
|
||||
for line in getLines(prefix: "a=fingerprint:") {
|
||||
let components = line.components(separatedBy: " ")
|
||||
if components.count != 2 {
|
||||
continue
|
||||
}
|
||||
fingerprints.append([
|
||||
"hash": components[0],
|
||||
"fingerprint": components[1],
|
||||
"setup": "active"
|
||||
])
|
||||
}
|
||||
|
||||
resultPayload["fingerprints"] = fingerprints
|
||||
|
||||
resultPayload["ufrag"] = ufrag
|
||||
resultPayload["pwd"] = pwd
|
||||
|
||||
resultPayload["ssrc"] = ssrc
|
||||
|
||||
guard let payloadData = try? JSONSerialization.data(withJSONObject: resultPayload, options: []) else {
|
||||
return nil
|
||||
}
|
||||
guard let payloadString = String(data: payloadData, encoding: .utf8) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ParsedJoinPayload(
|
||||
payload: payloadString,
|
||||
audioSsrc: UInt32(ssrc)
|
||||
)
|
||||
}
|
||||
|
||||
private func parseJoinResponseIntoSdp(sessionId: UInt32, mainStreamAudioSsrc: UInt32, payload: String, isAnswer: Bool, otherSsrcs: [UInt32]) -> String? {
|
||||
guard let payloadData = payload.data(using: .utf8) else {
|
||||
return nil
|
||||
}
|
||||
guard let jsonPayload = try? JSONSerialization.jsonObject(with: payloadData, options: []) as? [String: Any] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let transport = jsonPayload["transport"] as? [String: Any] else {
|
||||
return nil
|
||||
}
|
||||
guard let pwd = transport["pwd"] as? String else {
|
||||
return nil
|
||||
}
|
||||
guard let ufrag = transport["ufrag"] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
struct ParsedFingerprint {
|
||||
var hashValue: String
|
||||
var fingerprint: String
|
||||
var setup: String
|
||||
}
|
||||
|
||||
var fingerprints: [ParsedFingerprint] = []
|
||||
guard let fingerprintsValue = transport["fingerprints"] as? [[String: Any]] else {
|
||||
return nil
|
||||
}
|
||||
for fingerprintValue in fingerprintsValue {
|
||||
guard let hashValue = fingerprintValue["hash"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let fingerprint = fingerprintValue["fingerprint"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let setup = fingerprintValue["setup"] as? String else {
|
||||
continue
|
||||
}
|
||||
fingerprints.append(ParsedFingerprint(
|
||||
hashValue: hashValue,
|
||||
fingerprint: fingerprint,
|
||||
setup: setup
|
||||
))
|
||||
}
|
||||
|
||||
struct ParsedCandidate {
|
||||
var port: String
|
||||
var `protocol`: String
|
||||
var network: String
|
||||
var generation: String
|
||||
var id: String
|
||||
var component: String
|
||||
var foundation: String
|
||||
var priority: String
|
||||
var ip: String
|
||||
var type: String
|
||||
var tcpType: String?
|
||||
var relAddr: String?
|
||||
var relPort: String?
|
||||
}
|
||||
|
||||
var candidates: [ParsedCandidate] = []
|
||||
guard let candidatesValue = transport["candidates"] as? [[String: Any]] else {
|
||||
return nil
|
||||
}
|
||||
for candidateValue in candidatesValue {
|
||||
guard let port = candidateValue["port"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let `protocol` = candidateValue["protocol"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let network = candidateValue["network"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let generation = candidateValue["generation"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let id = candidateValue["id"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let component = candidateValue["component"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let foundation = candidateValue["foundation"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let priority = candidateValue["priority"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let ip = candidateValue["ip"] as? String else {
|
||||
continue
|
||||
}
|
||||
guard let type = candidateValue["type"] as? String else {
|
||||
continue
|
||||
}
|
||||
|
||||
let tcpType = candidateValue["tcptype"] as? String
|
||||
|
||||
let relAddr = candidateValue["rel-addr"] as? String
|
||||
let relPort = candidateValue["rel-port"] as? String
|
||||
|
||||
candidates.append(ParsedCandidate(
|
||||
port: port,
|
||||
protocol: `protocol`,
|
||||
network: network,
|
||||
generation: generation,
|
||||
id: id,
|
||||
component: component,
|
||||
foundation: foundation,
|
||||
priority: priority,
|
||||
ip: ip,
|
||||
type: type,
|
||||
tcpType: tcpType,
|
||||
relAddr: relAddr,
|
||||
relPort: relPort
|
||||
))
|
||||
}
|
||||
|
||||
struct StreamSpec {
|
||||
var isMain: Bool
|
||||
var audioSsrc: Int
|
||||
var isRemoved: Bool
|
||||
}
|
||||
|
||||
func createSdp(sessionId: UInt32, bundleStreams: [StreamSpec]) -> String {
|
||||
var sdp = ""
|
||||
func appendSdp(_ string: String) {
|
||||
if !sdp.isEmpty {
|
||||
sdp.append("\n")
|
||||
}
|
||||
sdp.append(string)
|
||||
}
|
||||
|
||||
appendSdp("v=0")
|
||||
appendSdp("o=- \(sessionId) 2 IN IP4 0.0.0.0")
|
||||
appendSdp("s=-")
|
||||
appendSdp("t=0 0")
|
||||
|
||||
var bundleString = "a=group:BUNDLE"
|
||||
for stream in bundleStreams {
|
||||
bundleString.append(" ")
|
||||
let audioMid: String
|
||||
if stream.isMain {
|
||||
audioMid = "0"
|
||||
} else {
|
||||
audioMid = "audio\(stream.audioSsrc)"
|
||||
}
|
||||
bundleString.append("\(audioMid)")
|
||||
}
|
||||
appendSdp(bundleString)
|
||||
|
||||
appendSdp("a=ice-lite")
|
||||
|
||||
for stream in bundleStreams {
|
||||
let audioMid: String
|
||||
if stream.isMain {
|
||||
audioMid = "0"
|
||||
} else {
|
||||
audioMid = "audio\(stream.audioSsrc)"
|
||||
}
|
||||
|
||||
appendSdp("m=audio \(stream.isMain ? "1" : "0") RTP/SAVPF 111 126")
|
||||
if stream.isMain {
|
||||
appendSdp("c=IN IP4 0.0.0.0")
|
||||
}
|
||||
appendSdp("a=mid:\(audioMid)")
|
||||
if stream.isRemoved {
|
||||
appendSdp("a=inactive")
|
||||
} else {
|
||||
if stream.isMain {
|
||||
appendSdp("a=ice-ufrag:\(ufrag)")
|
||||
appendSdp("a=ice-pwd:\(pwd)")
|
||||
|
||||
for fingerprint in fingerprints {
|
||||
appendSdp("a=fingerprint:\(fingerprint.hashValue) \(fingerprint.fingerprint)")
|
||||
appendSdp("a=setup:passive")
|
||||
}
|
||||
|
||||
for candidate in candidates {
|
||||
var candidateString = "a=candidate:"
|
||||
candidateString.append("\(candidate.foundation) ")
|
||||
candidateString.append("\(candidate.component) ")
|
||||
var protocolValue = candidate.protocol
|
||||
if protocolValue == "ssltcp" {
|
||||
protocolValue = "tcp"
|
||||
}
|
||||
candidateString.append("\(protocolValue) ")
|
||||
candidateString.append("\(candidate.priority) ")
|
||||
|
||||
let ip = candidate.ip
|
||||
candidateString.append("\(ip) ")
|
||||
candidateString.append("\(candidate.port) ")
|
||||
|
||||
candidateString.append("typ \(candidate.type) ")
|
||||
|
||||
switch candidate.type {
|
||||
case "srflx", "prflx", "relay":
|
||||
if let relAddr = candidate.relAddr, let relPort = candidate.relPort {
|
||||
candidateString.append("raddr \(relAddr) rport \(relPort) ")
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if protocolValue == "tcp" {
|
||||
guard let tcpType = candidate.tcpType else {
|
||||
continue
|
||||
}
|
||||
candidateString.append("tcptype \(tcpType) ")
|
||||
}
|
||||
|
||||
candidateString.append("generation \(candidate.generation)")
|
||||
|
||||
appendSdp(candidateString)
|
||||
}
|
||||
}
|
||||
|
||||
appendSdp("a=rtpmap:111 opus/48000/2")
|
||||
appendSdp("a=rtpmap:126 telephone-event/8000")
|
||||
appendSdp("a=fmtp:111 minptime=10; useinbandfec=1; usedtx=1")
|
||||
appendSdp("a=rtcp:1 IN IP4 0.0.0.0")
|
||||
appendSdp("a=rtcp-mux")
|
||||
appendSdp("a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level")
|
||||
appendSdp("a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time")
|
||||
appendSdp("a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")
|
||||
appendSdp("a=rtcp-fb:111 transport-cc")
|
||||
|
||||
if isAnswer {
|
||||
appendSdp("a=recvonly")
|
||||
} else {
|
||||
if stream.isMain {
|
||||
appendSdp("a=sendrecv")
|
||||
} else {
|
||||
appendSdp("a=sendonly")
|
||||
appendSdp("a=bundle-only")
|
||||
}
|
||||
|
||||
appendSdp("a=ssrc-group:FID \(stream.audioSsrc)")
|
||||
appendSdp("a=ssrc:\(stream.audioSsrc) cname:stream\(stream.audioSsrc)")
|
||||
appendSdp("a=ssrc:\(stream.audioSsrc) msid:stream\(stream.audioSsrc) audio\(stream.audioSsrc)")
|
||||
appendSdp("a=ssrc:\(stream.audioSsrc) mslabel:audio\(stream.audioSsrc)")
|
||||
appendSdp("a=ssrc:\(stream.audioSsrc) label:audio\(stream.audioSsrc)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appendSdp("")
|
||||
|
||||
return sdp
|
||||
}
|
||||
|
||||
var bundleStreams: [StreamSpec] = []
|
||||
bundleStreams.append(StreamSpec(
|
||||
isMain: true,
|
||||
audioSsrc: Int(mainStreamAudioSsrc),
|
||||
isRemoved: false
|
||||
))
|
||||
|
||||
for ssrc in otherSsrcs {
|
||||
bundleStreams.append(StreamSpec(
|
||||
isMain: false,
|
||||
audioSsrc: Int(ssrc),
|
||||
isRemoved: false
|
||||
))
|
||||
}
|
||||
|
||||
/*var bundleStreams: [StreamSpec] = []
|
||||
if let currentState = currentState {
|
||||
for item in currentState.items {
|
||||
let isRemoved = !streams.contains(where: { $0.audioSsrc == item.audioSsrc })
|
||||
bundleStreams.append(StreamSpec(
|
||||
isMain: item.audioSsrc == mainStreamAudioSsrc,
|
||||
audioSsrc: item.audioSsrc,
|
||||
videoSsrc: item.videoSsrc,
|
||||
isRemoved: isRemoved
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
for stream in streams {
|
||||
if bundleStreams.contains(where: { $0.audioSsrc == stream.audioSsrc }) {
|
||||
continue
|
||||
}
|
||||
bundleStreams.append(stream)
|
||||
}*/
|
||||
|
||||
return createSdp(sessionId: sessionId, bundleStreams: bundleStreams)
|
||||
}
|
||||
|
||||
public final class OngoingGroupCallContext {
|
||||
private final class Impl {
|
||||
let queue: Queue
|
||||
let context: GroupCallThreadLocalContext
|
||||
|
||||
let sessionId = UInt32.random(in: 0 ..< UInt32(Int32.max))
|
||||
var mainStreamAudioSsrc: UInt32?
|
||||
var initialAnswerPayload: String?
|
||||
var otherSsrcs: [UInt32] = []
|
||||
|
||||
let joinPayload = Promise<String>()
|
||||
|
||||
init(queue: Queue) {
|
||||
self.queue = queue
|
||||
|
||||
self.context = GroupCallThreadLocalContext(queue: ContextQueueImpl(queue: queue), relaySdpAnswer: { _ in
|
||||
}, incomingVideoStreamListUpdated: { _ in
|
||||
}, videoCapturer: nil)
|
||||
|
||||
let queue = self.queue
|
||||
self.context.emitOffer(adjustSdp: { sdp in
|
||||
return sdp
|
||||
}, completion: { [weak self] offerSdp in
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let payload = parseSdpIntoJoinPayload(sdp: offerSdp) {
|
||||
strongSelf.mainStreamAudioSsrc = payload.audioSsrc
|
||||
strongSelf.joinPayload.set(.single(payload.payload))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func setJoinResponse(payload: String, ssrcs: [Int32]) {
|
||||
guard let mainStreamAudioSsrc = self.mainStreamAudioSsrc else {
|
||||
return
|
||||
}
|
||||
if let sdp = parseJoinResponseIntoSdp(sessionId: self.sessionId, mainStreamAudioSsrc: mainStreamAudioSsrc, payload: payload, isAnswer: true, otherSsrcs: []) {
|
||||
self.initialAnswerPayload = payload
|
||||
self.context.setOfferSdp(sdp, isPartial: true)
|
||||
self.addSsrcs(ssrcs: ssrcs)
|
||||
}
|
||||
}
|
||||
|
||||
func addSsrcs(ssrcs: [Int32]) {
|
||||
if ssrcs.isEmpty {
|
||||
return
|
||||
}
|
||||
guard let mainStreamAudioSsrc = self.mainStreamAudioSsrc else {
|
||||
return
|
||||
}
|
||||
guard let initialAnswerPayload = self.initialAnswerPayload else {
|
||||
return
|
||||
}
|
||||
let mappedSsrcs = ssrcs.map(UInt32.init(bitPattern:))
|
||||
var otherSsrcs = self.otherSsrcs
|
||||
for ssrc in mappedSsrcs {
|
||||
if ssrc == mainStreamAudioSsrc {
|
||||
continue
|
||||
}
|
||||
if !otherSsrcs.contains(ssrc) {
|
||||
otherSsrcs.append(ssrc)
|
||||
}
|
||||
}
|
||||
if self.otherSsrcs != otherSsrcs {
|
||||
self.otherSsrcs = otherSsrcs
|
||||
|
||||
if let sdp = parseJoinResponseIntoSdp(sessionId: self.sessionId, mainStreamAudioSsrc: mainStreamAudioSsrc, payload: initialAnswerPayload, isAnswer: false, otherSsrcs: self.otherSsrcs) {
|
||||
self.context.setOfferSdp(sdp, isPartial: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setIsMuted(_ isMuted: Bool) {
|
||||
}
|
||||
}
|
||||
|
||||
private let queue = Queue()
|
||||
private let impl: QueueLocalObject<Impl>
|
||||
|
||||
public var joinPayload: Signal<String, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.joinPayload.get().start(next: { value in
|
||||
subscriber.putNext(value)
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
public init() {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return Impl(queue: queue)
|
||||
})
|
||||
}
|
||||
|
||||
public func setIsMuted(_ isMuted: Bool) {
|
||||
self.impl.with { impl in
|
||||
impl.setIsMuted(isMuted)
|
||||
}
|
||||
}
|
||||
|
||||
public func setJoinResponse(payload: String, ssrcs: [Int32]) {
|
||||
self.impl.with { impl in
|
||||
impl.setJoinResponse(payload: payload, ssrcs: ssrcs)
|
||||
}
|
||||
}
|
||||
|
||||
public func addSsrcs(ssrcs: [Int32]) {
|
||||
self.impl.with { impl in
|
||||
impl.addSsrcs(ssrcs: ssrcs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user