diff --git a/Telegram/NotificationService/NotificationServiceObjC/Sources/Serialization.m b/Telegram/NotificationService/NotificationServiceObjC/Sources/Serialization.m index f749c99957..882de632f3 100644 --- a/Telegram/NotificationService/NotificationServiceObjC/Sources/Serialization.m +++ b/Telegram/NotificationService/NotificationServiceObjC/Sources/Serialization.m @@ -3,7 +3,7 @@ @implementation Serialization - (NSUInteger)currentLayer { - return 128; + return 129; } - (id _Nullable)parseMessage:(NSData * _Nullable)data { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 4aa4ae1827..7b747827f1 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -7,7 +7,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1255641564] = { return parseString($0) } dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) } dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) } - dict[-916691372] = { return Api.GroupCall.parse_groupCall($0) } + dict[1698544301] = { return Api.GroupCall.parse_groupCall($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) } @@ -142,7 +142,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) } dict[1304052993] = { return Api.account.Takeout.parse_takeout($0) } dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) } - dict[-1184160274] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) } + dict[-1464184409] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) } dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) } dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) } dict[289586518] = { return Api.SavedContact.parse_savedPhoneContact($0) } @@ -280,6 +280,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-206342113] = { return Api.Update.parse_updateChatParticipant($0) } dict[2146218476] = { return Api.Update.parse_updateChannelParticipant($0) } dict[133777546] = { return Api.Update.parse_updateBotStopped($0) } + dict[192428418] = { return Api.Update.parse_updateGroupCallConnection($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) } diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 01f64f5520..dd8176ad24 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -1,7 +1,7 @@ public extension Api { public enum GroupCall: TypeConstructorDescription { case groupCallDiscarded(id: Int64, accessHash: Int64, duration: Int32) - case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, params: Api.DataJSON?, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, version: Int32) + case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, version: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -13,15 +13,14 @@ public extension Api { serializeInt64(accessHash, buffer: buffer, boxed: false) serializeInt32(duration, buffer: buffer, boxed: false) break - case .groupCall(let flags, let id, let accessHash, let participantsCount, let params, let title, let streamDcId, let recordStartDate, let scheduleDate, let version): + case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let version): if boxed { - buffer.appendInt32(-916691372) + buffer.appendInt32(1698544301) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt64(id, buffer: buffer, boxed: false) serializeInt64(accessHash, buffer: buffer, boxed: false) serializeInt32(participantsCount, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {params!.serialize(buffer, true)} if Int(flags) & Int(1 << 3) != 0 {serializeString(title!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {serializeInt32(streamDcId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 5) != 0 {serializeInt32(recordStartDate!, buffer: buffer, boxed: false)} @@ -35,8 +34,8 @@ public extension Api { switch self { case .groupCallDiscarded(let id, let accessHash, let duration): return ("groupCallDiscarded", [("id", id), ("accessHash", accessHash), ("duration", duration)]) - case .groupCall(let flags, let id, let accessHash, let participantsCount, let params, let title, let streamDcId, let recordStartDate, let scheduleDate, let version): - return ("groupCall", [("flags", flags), ("id", id), ("accessHash", accessHash), ("participantsCount", participantsCount), ("params", params), ("title", title), ("streamDcId", streamDcId), ("recordStartDate", recordStartDate), ("scheduleDate", scheduleDate), ("version", version)]) + case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let version): + return ("groupCall", [("flags", flags), ("id", id), ("accessHash", accessHash), ("participantsCount", participantsCount), ("title", title), ("streamDcId", streamDcId), ("recordStartDate", recordStartDate), ("scheduleDate", scheduleDate), ("version", version)]) } } @@ -66,32 +65,27 @@ public extension Api { _3 = reader.readInt64() var _4: Int32? _4 = reader.readInt32() - var _5: Api.DataJSON? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.DataJSON - } } - var _6: String? - if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _6: Int32? + if Int(_1!) & Int(1 << 4) != 0 {_6 = reader.readInt32() } var _7: Int32? - if Int(_1!) & Int(1 << 4) != 0 {_7 = reader.readInt32() } + if Int(_1!) & Int(1 << 5) != 0 {_7 = reader.readInt32() } var _8: Int32? - if Int(_1!) & Int(1 << 5) != 0 {_8 = reader.readInt32() } + if Int(_1!) & Int(1 << 7) != 0 {_8 = reader.readInt32() } var _9: Int32? - if Int(_1!) & Int(1 << 7) != 0 {_9 = reader.readInt32() } - var _10: Int32? - _10 = reader.readInt32() + _9 = reader.readInt32() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil - let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil - let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil - let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil - let _c10 = _10 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { - return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, params: _5, title: _6, streamDcId: _7, recordStartDate: _8, scheduleDate: _9, version: _10!) + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 5) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 7) == 0) || _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, title: _5, streamDcId: _6, recordStartDate: _7, scheduleDate: _8, version: _9!) } else { return nil @@ -3602,13 +3596,13 @@ public extension Api { } public enum GroupCallParticipant: TypeConstructorDescription { - case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?, params: Api.DataJSON?) + case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?, video: Api.DataJSON?, presentation: Api.DataJSON?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params): + case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let video, let presentation): if boxed { - buffer.appendInt32(-1184160274) + buffer.appendInt32(-1464184409) } serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) @@ -3618,15 +3612,16 @@ public extension Api { if Int(flags) & Int(1 << 7) != 0 {serializeInt32(volume!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeString(about!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 13) != 0 {serializeInt64(raiseHandRating!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 6) != 0 {params!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {video!.serialize(buffer, true)} + if Int(flags) & Int(1 << 14) != 0 {presentation!.serialize(buffer, true)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params): - return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating), ("params", params)]) + case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let video, let presentation): + return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating), ("video", video), ("presentation", presentation)]) } } @@ -3653,6 +3648,10 @@ public extension Api { if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() { _9 = Api.parse(reader, signature: signature) as? Api.DataJSON } } + var _10: Api.DataJSON? + if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.DataJSON + } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -3662,8 +3661,9 @@ public extension Api { let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil let _c8 = (Int(_1!) & Int(1 << 13) == 0) || _8 != nil let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8, params: _9) + let _c10 = (Int(_1!) & Int(1 << 14) == 0) || _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8, video: _9, presentation: _10) } else { return nil @@ -4681,6 +4681,7 @@ public extension Api { case updateChatParticipant(flags: Int32, chatId: Int32, date: Int32, actorId: Int32, userId: Int32, prevParticipant: Api.ChatParticipant?, newParticipant: Api.ChatParticipant?, invite: Api.ExportedChatInvite?, qts: Int32) case updateChannelParticipant(flags: Int32, channelId: Int32, date: Int32, actorId: Int32, userId: Int32, prevParticipant: Api.ChannelParticipant?, newParticipant: Api.ChannelParticipant?, invite: Api.ExportedChatInvite?, qts: Int32) case updateBotStopped(userId: Int32, date: Int32, stopped: Api.Bool, qts: Int32) + case updateGroupCallConnection(flags: Int32, params: Api.DataJSON) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -5475,6 +5476,13 @@ public extension Api { stopped.serialize(buffer, true) serializeInt32(qts, buffer: buffer, boxed: false) break + case .updateGroupCallConnection(let flags, let params): + if boxed { + buffer.appendInt32(192428418) + } + serializeInt32(flags, buffer: buffer, boxed: false) + params.serialize(buffer, true) + break } } @@ -5662,6 +5670,8 @@ public extension Api { return ("updateChannelParticipant", [("flags", flags), ("channelId", channelId), ("date", date), ("actorId", actorId), ("userId", userId), ("prevParticipant", prevParticipant), ("newParticipant", newParticipant), ("invite", invite), ("qts", qts)]) case .updateBotStopped(let userId, let date, let stopped, let qts): return ("updateBotStopped", [("userId", userId), ("date", date), ("stopped", stopped), ("qts", qts)]) + case .updateGroupCallConnection(let flags, let params): + return ("updateGroupCallConnection", [("flags", flags), ("params", params)]) } } @@ -7281,6 +7291,22 @@ public extension Api { return nil } } + public static func parse_updateGroupCallConnection(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.DataJSON? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.Update.updateGroupCallConnection(flags: _1!, params: _2!) + } + else { + return nil + } + } } public enum PopularContact: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api4.swift b/submodules/TelegramApi/Sources/Api4.swift index e8f1337a11..933026c529 100644 --- a/submodules/TelegramApi/Sources/Api4.swift +++ b/submodules/TelegramApi/Sources/Api4.swift @@ -7837,16 +7837,20 @@ public extension Api { }) } - public static func checkGroupCall(call: Api.InputGroupCall, source: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + public static func checkGroupCall(call: Api.InputGroupCall, sources: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { let buffer = Buffer() - buffer.appendInt32(-1219855382) + buffer.appendInt32(-1248003721) call.serialize(buffer, true) - serializeInt32(source, buffer: buffer, boxed: false) - return (FunctionDescription(name: "phone.checkGroupCall", parameters: [("call", call), ("source", source)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sources.count)) + for item in sources { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "phone.checkGroupCall", parameters: [("call", call), ("sources", sources)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in let reader = BufferReader(buffer) - var result: Api.Bool? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Bool + var result: [Int32]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) } return result }) @@ -7975,6 +7979,35 @@ public extension Api { return result }) } + + public static func joinGroupCallPresentation(call: Api.InputGroupCall, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-873829436) + call.serialize(buffer, true) + params.serialize(buffer, true) + return (FunctionDescription(name: "phone.joinGroupCallPresentation", 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 leaveGroupCallPresentation(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(475058500) + call.serialize(buffer, true) + return (FunctionDescription(name: "phone.leaveGroupCallPresentation", 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 + }) + } } } } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 0b08446fb0..0a3297a21f 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -24,7 +24,20 @@ private extension GroupCallParticipantsContext.Participant { if let ssrc = self.ssrc { participantSsrcs.insert(ssrc) } - if let jsonParams = self.jsonParams, let jsonData = jsonParams.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { + if let jsonParams = self.videoJsonDescription, let jsonData = jsonParams.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { + if let groups = json["ssrc-groups"] as? [Any] { + for group in groups { + if let group = group as? [String: Any] { + if let groupSources = group["sources"] as? [UInt32] { + for source in groupSources { + participantSsrcs.insert(source) + } + } + } + } + } + } + if let jsonParams = self.presentationJsonDescription, let jsonData = jsonParams.data(using: .utf8), let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] { if let groups = json["ssrc-groups"] as? [Any] { for group in groups { if let group = group as? [String: Any] { @@ -74,14 +87,14 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext { id: call.id, accessHash: call.accessHash, participantCount: 0, - clientParams: nil, streamDcId: nil, title: call.title, scheduleTimestamp: call.scheduleTimestamp, subscribedToScheduled: call.subscribedToScheduled, recordingStartTimestamp: nil, sortAscending: true, - defaultParticipantsAreMuted: nil + defaultParticipantsAreMuted: nil, + isVideoEnabled: false ), topParticipants: [], participantCount: 0, @@ -123,7 +136,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext { } return GroupCallPanelData( peerId: peerId, - info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, clientParams: nil, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: state.subscribedToScheduled, recordingStartTimestamp: nil, sortAscending: state.sortAscending, defaultParticipantsAreMuted: state.defaultParticipantsAreMuted), + info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: state.subscribedToScheduled, recordingStartTimestamp: nil, sortAscending: state.sortAscending, defaultParticipantsAreMuted: state.defaultParticipantsAreMuted, isVideoEnabled: state.isVideoEnabled), topParticipants: topParticipants, participantCount: state.totalCount, activeSpeakers: activeSpeakers, @@ -698,7 +711,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { return } if case let .established(callInfo, _, _, _, _) = strongSelf.internalState { - var addedParticipants: [(UInt32, String?)] = [] + var addedParticipants: [(UInt32, String?, String?)] = [] var removedSsrc: [UInt32] = [] for (callId, update) in updates { if callId == callInfo.id { @@ -734,13 +747,13 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } else if case .joined = participantUpdate.participationStatusChange { if let ssrc = participantUpdate.ssrc { - addedParticipants.append((ssrc, participantUpdate.jsonParams)) + addedParticipants.append((ssrc, participantUpdate.videoJsonDescription, participantUpdate.presentationJsonDescription)) } } else if let ssrc = participantUpdate.ssrc, strongSelf.ssrcMapping[ssrc] == nil { - addedParticipants.append((ssrc, participantUpdate.jsonParams)) + addedParticipants.append((ssrc, participantUpdate.videoJsonDescription, participantUpdate.presentationJsonDescription)) } } - case let .call(isTerminated, _, _, _, _): + case let .call(isTerminated, _, _, _, _, _): if isTerminated { strongSelf.markAsCanBeRemoved() } @@ -750,7 +763,6 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { if !removedSsrc.isEmpty { strongSelf.callContext?.removeSsrcs(ssrcs: removedSsrc) } - //strongSelf.callContext?.addParticipants(participants: addedParticipants) } }) @@ -924,14 +936,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { participants.append(GroupCallParticipantsContext.Participant( peer: myPeer, ssrc: nil, - jsonParams: nil, + videoJsonDescription: nil, + presentationJsonDescription: nil, joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: strongSelf.temporaryRaiseHandRating, hasRaiseHand: strongSelf.temporaryHasRaiseHand, activityTimestamp: strongSelf.temporaryActivityTimestamp, activityRank: strongSelf.temporaryActivityRank, muteState: strongSelf.temporaryMuteState ?? GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false), - isVideoMuted: true, volume: nil, about: about )) @@ -1005,14 +1017,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { participants.append(GroupCallParticipantsContext.Participant( peer: myPeer, ssrc: nil, - jsonParams: nil, + videoJsonDescription: nil, + presentationJsonDescription: nil, joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: strongSelf.temporaryRaiseHandRating, hasRaiseHand: strongSelf.temporaryHasRaiseHand, activityTimestamp: strongSelf.temporaryActivityTimestamp, activityRank: strongSelf.temporaryActivityRank, muteState: strongSelf.temporaryMuteState ?? GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false), - isVideoMuted: true, volume: nil, about: about )) @@ -1114,6 +1126,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { scheduleTimestamp: self.stateValue.scheduleTimestamp, subscribedToScheduled: self.stateValue.subscribedToScheduled, totalCount: 0, + isVideoEnabled: false, version: 0 ), previousServiceState: nil @@ -1168,14 +1181,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { participants.append(GroupCallParticipantsContext.Participant( peer: myPeer, ssrc: nil, - jsonParams: nil, + videoJsonDescription: nil, + presentationJsonDescription: nil, joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: strongSelf.temporaryRaiseHandRating, hasRaiseHand: strongSelf.temporaryHasRaiseHand, activityTimestamp: strongSelf.temporaryActivityTimestamp, activityRank: strongSelf.temporaryActivityRank, muteState: strongSelf.temporaryMuteState ?? GroupCallParticipantsContext.Participant.MuteState(canUnmute: canManageCall || !state.defaultParticipantsAreMuted.isMuted, mutedByYou: false), - isVideoMuted: true, volume: nil, about: about )) @@ -1200,20 +1213,20 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { strongSelf.stateValue.scheduleTimestamp = strongSelf.isScheduledStarted ? nil : state.scheduleTimestamp if state.scheduleTimestamp == nil && !strongSelf.isScheduledStarted { - strongSelf.updateSessionState(internalState: .active(GroupCallInfo(id: callInfo.id, accessHash: callInfo.accessHash, participantCount: state.totalCount, clientParams: callInfo.clientParams, streamDcId: callInfo.streamDcId, title: state.title, scheduleTimestamp: nil, subscribedToScheduled: false, recordingStartTimestamp: nil, sortAscending: true, defaultParticipantsAreMuted: callInfo.defaultParticipantsAreMuted ?? state.defaultParticipantsAreMuted)), audioSessionControl: strongSelf.audioSessionControl) + strongSelf.updateSessionState(internalState: .active(GroupCallInfo(id: callInfo.id, accessHash: callInfo.accessHash, participantCount: state.totalCount, streamDcId: callInfo.streamDcId, title: state.title, scheduleTimestamp: nil, subscribedToScheduled: false, recordingStartTimestamp: nil, sortAscending: true, defaultParticipantsAreMuted: callInfo.defaultParticipantsAreMuted ?? state.defaultParticipantsAreMuted, isVideoEnabled: callInfo.isVideoEnabled)), audioSessionControl: strongSelf.audioSessionControl) } else { strongSelf.summaryInfoState.set(.single(SummaryInfoState(info: GroupCallInfo( id: callInfo.id, accessHash: callInfo.accessHash, participantCount: state.totalCount, - clientParams: nil, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: false, recordingStartTimestamp: state.recordingStartTimestamp, sortAscending: state.sortAscending, - defaultParticipantsAreMuted: state.defaultParticipantsAreMuted + defaultParticipantsAreMuted: state.defaultParticipantsAreMuted, + isVideoEnabled: state.isVideoEnabled )))) strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState( @@ -1389,28 +1402,26 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { guard let strongSelf = self else { return } - if let clientParams = joinCallResult.callInfo.clientParams { - strongSelf.ssrcMapping.removeAll() - let addedParticipants: [(UInt32, String?)] = [] - for participant in joinCallResult.state.participants { - if let ssrc = participant.ssrc { - strongSelf.ssrcMapping[ssrc] = participant.peer.id - //addedParticipants.append((participant.ssrc, participant.jsonParams)) - } + let clientParams = joinCallResult.jsonParams + + strongSelf.ssrcMapping.removeAll() + for participant in joinCallResult.state.participants { + if let ssrc = participant.ssrc { + strongSelf.ssrcMapping[ssrc] = participant.peer.id } - - switch joinCallResult.connectionMode { - case .rtc: - strongSelf.currentConnectionMode = .rtc - strongSelf.callContext?.setConnectionMode(.rtc, keepBroadcastConnectedIfWasEnabled: false) - strongSelf.callContext?.setJoinResponse(payload: clientParams, participants: addedParticipants) - case .broadcast: - strongSelf.currentConnectionMode = .broadcast - strongSelf.callContext?.setConnectionMode(.broadcast, keepBroadcastConnectedIfWasEnabled: false) - } - - strongSelf.updateSessionState(internalState: .established(info: joinCallResult.callInfo, connectionMode: joinCallResult.connectionMode, clientParams: clientParams, localSsrc: ssrc, initialState: joinCallResult.state), audioSessionControl: strongSelf.audioSessionControl) } + + switch joinCallResult.connectionMode { + case .rtc: + strongSelf.currentConnectionMode = .rtc + strongSelf.callContext?.setConnectionMode(.rtc, keepBroadcastConnectedIfWasEnabled: false) + strongSelf.callContext?.setJoinResponse(payload: clientParams) + case .broadcast: + strongSelf.currentConnectionMode = .broadcast + strongSelf.callContext?.setConnectionMode(.broadcast, keepBroadcastConnectedIfWasEnabled: false) + } + + strongSelf.updateSessionState(internalState: .established(info: joinCallResult.callInfo, connectionMode: joinCallResult.connectionMode, clientParams: clientParams, localSsrc: ssrc, initialState: joinCallResult.state), audioSessionControl: strongSelf.audioSessionControl) }, error: { error in guard let strongSelf = self else { return @@ -1743,14 +1754,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { participants.append(GroupCallParticipantsContext.Participant( peer: myPeer, ssrc: nil, - jsonParams: nil, + videoJsonDescription: nil, + presentationJsonDescription: nil, joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: strongSelf.temporaryRaiseHandRating, hasRaiseHand: strongSelf.temporaryHasRaiseHand, activityTimestamp: strongSelf.temporaryActivityTimestamp, activityRank: strongSelf.temporaryActivityRank, muteState: strongSelf.temporaryMuteState ?? GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false), - isVideoMuted: true, volume: nil, about: about )) @@ -1852,7 +1863,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } else if participant.muteState?.mutedByYou == true { strongSelf.callContext?.setVolume(ssrc: ssrc, volume: 0.0) } - if participant.isVideoMuted { + if participant.videoJsonDescription == nil { strongSelf.callContext?.removeIncomingVideoSource(ssrc) } } @@ -1885,14 +1896,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { id: callInfo.id, accessHash: callInfo.accessHash, participantCount: state.totalCount, - clientParams: nil, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: false, recordingStartTimestamp: state.recordingStartTimestamp, sortAscending: state.sortAscending, - defaultParticipantsAreMuted: state.defaultParticipantsAreMuted + defaultParticipantsAreMuted: state.defaultParticipantsAreMuted, + isVideoEnabled: state.isVideoEnabled )))) strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState( @@ -1949,7 +1960,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { private func maybeRequestParticipants(ssrcs: Set) { var addedMissingSsrcs = ssrcs - var addedParticipants: [(UInt32, String?)] = [] + var addedParticipants: [(UInt32, String?, String?)] = [] if let membersValue = self.membersValue { for participant in membersValue.participants { @@ -1959,7 +1970,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { addedMissingSsrcs.subtract(participantSsrcs) if let ssrc = participant.ssrc { - addedParticipants.append((ssrc, participant.jsonParams)) + addedParticipants.append((ssrc, participant.videoJsonDescription, participant.presentationJsonDescription)) } } } @@ -1994,22 +2005,22 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { strongSelf.isRequestingMissingSsrcs = false strongSelf.missingSsrcs.subtract(requestedSsrcs) - var addedParticipants: [(UInt32, Int32?, String?)] = [] + var addedParticipants: [(UInt32, Int32?, String?, String?)] = [] for participant in state.participants { if let ssrc = participant.ssrc { - addedParticipants.append((ssrc, participant.volume, participant.jsonParams)) + addedParticipants.append((ssrc, participant.volume, participant.videoJsonDescription, participant.presentationJsonDescription)) } } if !addedParticipants.isEmpty { - for (ssrc, volume, _) in addedParticipants { + for (ssrc, volume, _, _) in addedParticipants { if let volume = volume { strongSelf.callContext?.setVolume(ssrc: ssrc, volume: Double(volume) / 10000.0) } } - strongSelf.callContext?.addParticipants(participants: addedParticipants.map { ssrc, _, params in - return (ssrc, params) + strongSelf.callContext?.addParticipants(participants: addedParticipants.map { ssrc, _, videoParams, presentationParams in + return (ssrc, videoParams, presentationParams) }) } @@ -2023,14 +2034,21 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { return } if case let .established(callInfo, connectionMode, _, ssrc, _) = self.internalState, case .rtc = connectionMode { - let checkSignal = checkGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, ssrc: Int32(bitPattern: ssrc)) + let checkSignal = checkGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, ssrcs: [ssrc]) self.checkCallDisposable = (( checkSignal |> castError(Bool.self) |> delay(4.0, queue: .mainQueue()) |> mapToSignal { result -> Signal in - if case .success = result { + var foundAll = true + for value in [ssrc] { + if !result.contains(value) { + foundAll = false + break + } + } + if foundAll { return .fail(true) } else { return .single(true) @@ -2354,7 +2372,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { if id == peerId { self.callContext?.setVolume(ssrc: ssrc, volume: Double(volume) / 10000.0) if sync { - self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, isVideoMuted: nil, volume: volume, raiseHand: nil) + self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: volume, raiseHand: nil) } break } @@ -2462,19 +2480,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { canThenUnmute = true } let muteState = isMuted ? GroupCallParticipantsContext.Participant.MuteState(canUnmute: canThenUnmute, mutedByYou: mutedByYou) : nil - self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, isVideoMuted: nil, volume: nil, raiseHand: nil) + self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil, raiseHand: nil) return muteState } else { if peerId == self.joinAsPeerId { - self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, isVideoMuted: nil, volume: nil, raiseHand: nil) + self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil, raiseHand: nil) return nil } else if self.stateValue.canManageCall || self.stateValue.adminIds.contains(self.accountContext.account.peerId) { let muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false) - self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, isVideoMuted: nil, volume: nil, raiseHand: nil) + self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil, raiseHand: nil) return muteState } else { self.setVolume(peerId: peerId, volume: 10000, sync: true) - self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, isVideoMuted: nil, volume: nil, raiseHand: nil) + self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil, raiseHand: nil) return nil } } diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index b87be97a10..1d704defe4 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -8,7 +8,6 @@ public struct GroupCallInfo: Equatable { public var id: Int64 public var accessHash: Int64 public var participantCount: Int - public var clientParams: String? public var streamDcId: Int32? public var title: String? public var scheduleTimestamp: Int32? @@ -16,24 +15,24 @@ public struct GroupCallInfo: Equatable { public var recordingStartTimestamp: Int32? public var sortAscending: Bool public var defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted? + public var isVideoEnabled: Bool public init( id: Int64, accessHash: Int64, participantCount: Int, - clientParams: String?, streamDcId: Int32?, title: String?, scheduleTimestamp: Int32?, subscribedToScheduled: Bool, recordingStartTimestamp: Int32?, sortAscending: Bool, - defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted? + defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted?, + isVideoEnabled: Bool ) { self.id = id self.accessHash = accessHash self.participantCount = participantCount - self.clientParams = clientParams self.streamDcId = streamDcId self.title = title self.scheduleTimestamp = scheduleTimestamp @@ -41,6 +40,7 @@ public struct GroupCallInfo: Equatable { self.recordingStartTimestamp = recordingStartTimestamp self.sortAscending = sortAscending self.defaultParticipantsAreMuted = defaultParticipantsAreMuted + self.isVideoEnabled = isVideoEnabled } } @@ -52,26 +52,19 @@ public struct GroupCallSummary: Equatable { extension GroupCallInfo { init?(_ call: Api.GroupCall) { switch call { - case let .groupCall(flags, id, accessHash, participantCount, params, title, streamDcId, recordStartDate, scheduleDate, _): - var clientParams: String? - if let params = params { - switch params { - case let .dataJSON(data): - clientParams = data - } - } + case let .groupCall(flags, id, accessHash, participantsCount, title, streamDcId, recordStartDate, scheduleDate, _): self.init( id: id, accessHash: accessHash, - participantCount: Int(participantCount), - clientParams: clientParams, + participantCount: Int(participantsCount), streamDcId: streamDcId, title: title, scheduleTimestamp: scheduleDate, subscribedToScheduled: (flags & (1 << 8)) != 0, recordingStartTimestamp: recordStartDate, sortAscending: (flags & (1 << 6)) != 0, - defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: (flags & (1 << 1)) != 0, canChange: (flags & (1 << 2)) != 0) + defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: (flags & (1 << 1)) != 0, canChange: (flags & (1 << 2)) != 0), + isVideoEnabled: (flags & (1 << 9)) != 0 ) case .groupCallDiscarded: return nil @@ -133,8 +126,7 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): - //let params: Api.DataJSON? = nil + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, video, presentation): let peerId: PeerId = apiPeerId.peerId let ssrc = UInt32(bitPattern: source) @@ -150,25 +142,31 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int } else if mutedByYou { muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: false, mutedByYou: mutedByYou) } - var jsonParams: String? = nil - if let params = params { - switch params { + var videoJsonDescription: String? = nil + var presentationJsonDescription: String? = nil + if let video = video { + switch video { case let .dataJSON(data): - jsonParams = data + videoJsonDescription = data + } + } + if let presentation = presentation { + switch presentation { + case let .dataJSON(data): + presentationJsonDescription = data } } - let isVideoMuted = (flags & (1 << 14)) != 0 parsedParticipants.append(GroupCallParticipantsContext.Participant( peer: peer, ssrc: ssrc, - jsonParams: jsonParams, + videoJsonDescription: videoJsonDescription, + presentationJsonDescription: presentationJsonDescription, joinTimestamp: date, raiseHandRating: raiseHandRating, hasRaiseHand: raiseHandRating != nil, activityTimestamp: activeDate.flatMap(Double.init), activityRank: nil, muteState: muteState, - isVideoMuted: isVideoMuted, volume: volume, about: about )) @@ -451,8 +449,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): - //let params: Api.DataJSON? = nil + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, video, presentation): let peerId: PeerId = apiPeerId.peerId let ssrc = UInt32(bitPattern: source) guard let peer = transaction.getPeer(peerId) else { @@ -467,25 +464,31 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash } else if mutedByYou { muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: false, mutedByYou: mutedByYou) } - var jsonParams: String? = nil - if let params = params { - switch params { + var videoJsonDescription: String? = nil + var presentationJsonDescription: String? = nil + if let video = video { + switch video { case let .dataJSON(data): - jsonParams = data + videoJsonDescription = data + } + } + if let presentation = presentation { + switch presentation { + case let .dataJSON(data): + presentationJsonDescription = data } } - let isVideoMuted = (flags & (1 << 14)) != 0 parsedParticipants.append(GroupCallParticipantsContext.Participant( peer: peer, ssrc: ssrc, - jsonParams: jsonParams, + videoJsonDescription: videoJsonDescription, + presentationJsonDescription: presentationJsonDescription, joinTimestamp: date, raiseHandRating: raiseHandRating, hasRaiseHand: raiseHandRating != nil, activityTimestamp: activeDate.flatMap(Double.init), activityRank: nil, muteState: muteState, - isVideoMuted: isVideoMuted, volume: volume, about: about )) @@ -507,6 +510,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash scheduleTimestamp: scheduleTimestamp, subscribedToScheduled: subscribedToScheduled, totalCount: totalCount, + isVideoEnabled: false, version: version ) } @@ -530,6 +534,7 @@ public struct JoinGroupCallResult { public var callInfo: GroupCallInfo public var state: GroupCallParticipantsContext.State public var connectionMode: ConnectionMode + public var jsonParams: String } public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil) -> Signal { @@ -624,30 +629,36 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal account.stateManager.addUpdates(updates) var maybeParsedCall: GroupCallInfo? + var maybeParsedClientParams: String? loop: for update in updates.allUpdates { switch update { case let .updateGroupCall(_, call): maybeParsedCall = GroupCallInfo(call) switch call { - case let .groupCall(flags, _, _, _, _, title, _, recordStartDate, scheduleDate, _): + case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _): let isMuted = (flags & (1 << 1)) != 0 let canChange = (flags & (1 << 2)) != 0 + let isVideoEnabled = (flags & (1 << 9)) != 0 state.defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange) state.title = title state.recordingStartTimestamp = recordStartDate state.scheduleTimestamp = scheduleDate + state.isVideoEnabled = isVideoEnabled default: break } - - break loop + case let .updateGroupCallConnection(_, params): + switch params { + case let .dataJSON(data): + maybeParsedClientParams = data + } default: break } } - guard let parsedCall = maybeParsedCall else { + guard let parsedCall = maybeParsedCall, let parsedClientParams = maybeParsedClientParams else { return .fail(.generic) } @@ -669,7 +680,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal } let connectionMode: JoinGroupCallResult.ConnectionMode - if let clientParams = parsedCall.clientParams, let clientParamsData = clientParams.data(using: .utf8), let dict = (try? JSONSerialization.jsonObject(with: clientParamsData, options: [])) as? [String: Any] { + if let clientParamsData = parsedClientParams.data(using: .utf8), let dict = (try? JSONSerialization.jsonObject(with: clientParamsData, options: [])) as? [String: Any] { if let stream = dict["stream"] as? Bool, stream { connectionMode = .broadcast } else { @@ -697,8 +708,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal case let .updateGroupCallParticipants(_, participants, _): loop: for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): - //let params: Api.DataJSON? = nil + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, video, presentation): let peerId: PeerId = apiPeerId.peerId let ssrc = UInt32(bitPattern: source) guard let peer = transaction.getPeer(peerId) else { @@ -713,26 +723,32 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal } else if mutedByYou { muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: false, mutedByYou: mutedByYou) } - var jsonParams: String? = nil - if let params = params { - switch params { + var videoJsonDescription: String? = nil + var presentationJsonDescription: String? = nil + if let video = video { + switch video { case let .dataJSON(data): - jsonParams = data + videoJsonDescription = data + } + } + if let presentation = presentation { + switch presentation { + case let .dataJSON(data): + presentationJsonDescription = data } } - let isVideoMuted = (flags & (1 << 14)) != 0 if !state.participants.contains(where: { $0.peer.id == peer.id }) { state.participants.append(GroupCallParticipantsContext.Participant( peer: peer, ssrc: ssrc, - jsonParams: jsonParams, + videoJsonDescription: videoJsonDescription, + presentationJsonDescription: presentationJsonDescription, joinTimestamp: date, raiseHandRating: raiseHandRating, hasRaiseHand: raiseHandRating != nil, activityTimestamp: activeDate.flatMap(Double.init), activityRank: nil, muteState: muteState, - isVideoMuted: isVideoMuted, volume: volume, about: about )) @@ -754,7 +770,8 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal return JoinGroupCallResult( callInfo: parsedCall, state: state, - connectionMode: connectionMode + connectionMode: connectionMode, + jsonParams: parsedClientParams ) } |> castError(JoinGroupCallError.self) @@ -826,26 +843,13 @@ public func stopGroupCall(account: Account, peerId: PeerId, callId: Int64, acces } } -public enum CheckGroupCallResult { - case success - case restart -} - -public func checkGroupCall(account: Account, callId: Int64, accessHash: Int64, ssrc: Int32) -> Signal { - return account.network.request(Api.functions.phone.checkGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash), source: ssrc)) - |> `catch` { _ -> Signal in - return .single(.boolFalse) +public func checkGroupCall(account: Account, callId: Int64, accessHash: Int64, ssrcs: [UInt32]) -> Signal<[UInt32], NoError> { + return account.network.request(Api.functions.phone.checkGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash), sources: ssrcs.map(Int32.init(bitPattern:)))) + |> `catch` { _ -> Signal<[Int32], NoError> in + return .single([]) } - |> map { result -> CheckGroupCallResult in - #if DEBUG - //return .restart - #endif - switch result { - case .boolTrue: - return .success - case .boolFalse: - return .restart - } + |> map { result -> [UInt32] in + return result.map(UInt32.init(bitPattern:)) } } @@ -879,41 +883,41 @@ public final class GroupCallParticipantsContext { public var peer: Peer public var ssrc: UInt32? - public var jsonParams: String? + public var videoJsonDescription: String? + public var presentationJsonDescription: String? public var joinTimestamp: Int32 public var raiseHandRating: Int64? public var hasRaiseHand: Bool public var activityTimestamp: Double? public var activityRank: Int? public var muteState: MuteState? - public var isVideoMuted: Bool public var volume: Int32? public var about: String? public init( peer: Peer, ssrc: UInt32?, - jsonParams: String?, + videoJsonDescription: String?, + presentationJsonDescription: String?, joinTimestamp: Int32, raiseHandRating: Int64?, hasRaiseHand: Bool, activityTimestamp: Double?, activityRank: Int?, muteState: MuteState?, - isVideoMuted: Bool, volume: Int32?, about: String? ) { self.peer = peer self.ssrc = ssrc - self.jsonParams = jsonParams + self.videoJsonDescription = videoJsonDescription + self.presentationJsonDescription = presentationJsonDescription self.joinTimestamp = joinTimestamp self.raiseHandRating = raiseHandRating self.hasRaiseHand = hasRaiseHand self.activityTimestamp = activityTimestamp self.activityRank = activityRank self.muteState = muteState - self.isVideoMuted = isVideoMuted self.volume = volume self.about = about } @@ -936,6 +940,12 @@ public final class GroupCallParticipantsContext { if lhs.ssrc != rhs.ssrc { return false } + if lhs.videoJsonDescription != rhs.videoJsonDescription { + return false + } + if lhs.presentationJsonDescription != rhs.presentationJsonDescription { + return false + } if lhs.joinTimestamp != rhs.joinTimestamp { return false } @@ -954,9 +964,6 @@ public final class GroupCallParticipantsContext { if lhs.muteState != rhs.muteState { return false } - if lhs.isVideoMuted != rhs.isVideoMuted { - return false - } if lhs.volume != rhs.volume { return false } @@ -1040,6 +1047,7 @@ public final class GroupCallParticipantsContext { public var scheduleTimestamp: Int32? public var subscribedToScheduled: Bool public var totalCount: Int + public var isVideoEnabled: Bool public var version: Int32 public mutating func mergeActivity(from other: State, myPeerId: PeerId?, previousMyPeerId: PeerId?, mergeActivityTimestamps: Bool) { @@ -1072,6 +1080,7 @@ public final class GroupCallParticipantsContext { scheduleTimestamp: Int32?, subscribedToScheduled: Bool, totalCount: Int, + isVideoEnabled: Bool, version: Int32 ) { self.participants = participants @@ -1085,6 +1094,7 @@ public final class GroupCallParticipantsContext { self.scheduleTimestamp = scheduleTimestamp self.subscribedToScheduled = subscribedToScheduled self.totalCount = totalCount + self.isVideoEnabled = isVideoEnabled self.version = version } } @@ -1135,12 +1145,12 @@ public final class GroupCallParticipantsContext { public var peerId: PeerId public var ssrc: UInt32? - public var jsonParams: String? + public var videoJsonDescription: String? + public var presentationJsonDescription: String? public var joinTimestamp: Int32 public var activityTimestamp: Double? public var raiseHandRating: Int64? public var muteState: Participant.MuteState? - public var isVideoMuted: Bool public var participationStatusChange: ParticipationStatusChange public var volume: Int32? public var about: String? @@ -1149,12 +1159,12 @@ public final class GroupCallParticipantsContext { init( peerId: PeerId, ssrc: UInt32?, - jsonParams: String?, + videoJsonDescription: String?, + presentationJsonDescription: String?, joinTimestamp: Int32, activityTimestamp: Double?, raiseHandRating: Int64?, muteState: Participant.MuteState?, - isVideoMuted: Bool, participationStatusChange: ParticipationStatusChange, volume: Int32?, about: String?, @@ -1162,12 +1172,12 @@ public final class GroupCallParticipantsContext { ) { self.peerId = peerId self.ssrc = ssrc - self.jsonParams = jsonParams + self.videoJsonDescription = videoJsonDescription + self.presentationJsonDescription = presentationJsonDescription self.joinTimestamp = joinTimestamp self.activityTimestamp = activityTimestamp self.raiseHandRating = raiseHandRating self.muteState = muteState - self.isVideoMuted = isVideoMuted self.participationStatusChange = participationStatusChange self.volume = volume self.about = about @@ -1182,7 +1192,7 @@ public final class GroupCallParticipantsContext { } case state(update: StateUpdate) - case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, title: String?, recordingStartTimestamp: Int32?, scheduleTimestamp: Int32?) + case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, title: String?, recordingStartTimestamp: Int32?, scheduleTimestamp: Int32?, isVideoEnabled: Bool) } public final class MemberEvent { @@ -1376,6 +1386,7 @@ public final class GroupCallParticipantsContext { scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp, subscribedToScheduled: strongSelf.stateValue.state.subscribedToScheduled, totalCount: strongSelf.stateValue.state.totalCount, + isVideoEnabled: strongSelf.stateValue.state.isVideoEnabled, version: strongSelf.stateValue.state.version ), overlayState: strongSelf.stateValue.overlayState @@ -1430,12 +1441,13 @@ public final class GroupCallParticipantsContext { for update in updates { if case let .state(update) = update { stateUpdates.append(update) - } else if case let .call(_, defaultParticipantsAreMuted, title, recordingStartTimestamp, scheduleTimestamp) = update { + } else if case let .call(_, defaultParticipantsAreMuted, title, recordingStartTimestamp, scheduleTimestamp, isVideoEnabled) = update { var state = self.stateValue.state state.defaultParticipantsAreMuted = defaultParticipantsAreMuted state.recordingStartTimestamp = recordingStartTimestamp state.title = title state.scheduleTimestamp = scheduleTimestamp + state.isVideoEnabled = isVideoEnabled self.stateValue.state = state } @@ -1511,6 +1523,7 @@ public final class GroupCallParticipantsContext { scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp, subscribedToScheduled: strongSelf.stateValue.state.subscribedToScheduled, totalCount: strongSelf.stateValue.state.totalCount, + isVideoEnabled: strongSelf.stateValue.state.isVideoEnabled, version: strongSelf.stateValue.state.version ), overlayState: strongSelf.stateValue.overlayState @@ -1698,14 +1711,14 @@ public final class GroupCallParticipantsContext { let participant = Participant( peer: peer, ssrc: participantUpdate.ssrc, - jsonParams: participantUpdate.jsonParams, + videoJsonDescription: participantUpdate.videoJsonDescription, + presentationJsonDescription: participantUpdate.presentationJsonDescription, joinTimestamp: previousJoinTimestamp ?? participantUpdate.joinTimestamp, raiseHandRating: participantUpdate.raiseHandRating, hasRaiseHand: participantUpdate.raiseHandRating != nil, activityTimestamp: activityTimestamp, activityRank: previousActivityRank, muteState: muteState, - isVideoMuted: participantUpdate.isVideoMuted, volume: volume, about: participantUpdate.about ) @@ -1728,6 +1741,7 @@ public final class GroupCallParticipantsContext { let title = strongSelf.stateValue.state.title let scheduleTimestamp = strongSelf.stateValue.state.scheduleTimestamp let subscribedToScheduled = strongSelf.stateValue.state.subscribedToScheduled + let isVideoEnabled = strongSelf.stateValue.state.isVideoEnabled updatedParticipants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: strongSelf.stateValue.state.sortAscending) }) @@ -1744,6 +1758,7 @@ public final class GroupCallParticipantsContext { scheduleTimestamp: scheduleTimestamp, subscribedToScheduled: subscribedToScheduled, totalCount: updatedTotalCount, + isVideoEnabled: isVideoEnabled, version: update.version ), overlayState: updatedOverlayState @@ -1783,7 +1798,7 @@ public final class GroupCallParticipantsContext { })) } - public func updateMuteState(peerId: PeerId, muteState: Participant.MuteState?, isVideoMuted: Bool?, volume: Int32?, raiseHand: Bool?) { + public func updateMuteState(peerId: PeerId, muteState: Participant.MuteState?, volume: Int32?, raiseHand: Bool?) { if let current = self.stateValue.overlayState.pendingMuteStateChanges[peerId] { if current.state == muteState { return @@ -1835,11 +1850,6 @@ public final class GroupCallParticipantsContext { flags |= 1 << 0 muted = .boolTrue } - var videoMuted: Api.Bool? - if let isVideoMuted = isVideoMuted { - videoMuted = isVideoMuted ? .boolTrue : .boolFalse - flags |= 1 << 3 - } let raiseHandApi: Api.Bool? if let raiseHand = raiseHand { flags |= 1 << 2 @@ -1848,7 +1858,7 @@ public final class GroupCallParticipantsContext { raiseHandApi = nil } - return account.network.request(Api.functions.phone.editGroupCallParticipant(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), participant: inputPeer, muted: muted, volume: volume, raiseHand: raiseHandApi, videoMuted: videoMuted)) + return account.network.request(Api.functions.phone.editGroupCallParticipant(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), participant: inputPeer, muted: muted, volume: volume, raiseHand: raiseHandApi, videoMuted: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -1947,11 +1957,11 @@ public final class GroupCallParticipantsContext { } public func raiseHand() { - self.updateMuteState(peerId: self.myPeerId, muteState: nil, isVideoMuted: nil, volume: nil, raiseHand: true) + self.updateMuteState(peerId: self.myPeerId, muteState: nil, volume: nil, raiseHand: true) } public func lowerHand() { - self.updateMuteState(peerId: self.myPeerId, muteState: nil, isVideoMuted: nil, volume: nil, raiseHand: false) + self.updateMuteState(peerId: self.myPeerId, muteState: nil, volume: nil, raiseHand: false) } public func updateShouldBeRecording(_ shouldBeRecording: Bool, title: String?) { @@ -2033,8 +2043,7 @@ public final class GroupCallParticipantsContext { extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate { init(_ apiParticipant: Api.GroupCallParticipant) { switch apiParticipant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): - //let params: Api.DataJSON? = nil + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, video, presentation): let peerId: PeerId = apiPeerId.peerId let ssrc = UInt32(bitPattern: source) let muted = (flags & (1 << 0)) != 0 @@ -2059,24 +2068,30 @@ extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate { participationStatusChange = .none } - var jsonParams: String? = nil - if let params = params { - switch params { + var videoJsonDescription: String? = nil + var presentationJsonDescription: String? = nil + if let video = video { + switch video { case let .dataJSON(data): - jsonParams = data + videoJsonDescription = data + } + } + if let presentation = presentation { + switch presentation { + case let .dataJSON(data): + presentationJsonDescription = data } } - let isVideoMuted = (flags & (1 << 14)) != 0 self.init( peerId: peerId, ssrc: ssrc, - jsonParams: jsonParams, + videoJsonDescription: videoJsonDescription, + presentationJsonDescription: presentationJsonDescription, joinTimestamp: date, activityTimestamp: activeDate.flatMap(Double.init), raiseHandRating: raiseHandRating, muteState: muteState, - isVideoMuted: isVideoMuted, participationStatusChange: participationStatusChange, volume: volume, about: about, @@ -2091,8 +2106,7 @@ extension GroupCallParticipantsContext.Update.StateUpdate { var participantUpdates: [GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate] = [] for participant in participants { switch participant { - case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params): - //let params: Api.DataJSON? = nil + case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, video, presentation): let peerId: PeerId = apiPeerId.peerId let ssrc = UInt32(bitPattern: source) let muted = (flags & (1 << 0)) != 0 @@ -2117,24 +2131,30 @@ extension GroupCallParticipantsContext.Update.StateUpdate { participationStatusChange = .none } - var jsonParams: String? = nil - if let params = params { - switch params { + var videoJsonDescription: String? = nil + var presentationJsonDescription: String? = nil + if let video = video { + switch video { case let .dataJSON(data): - jsonParams = data + videoJsonDescription = data + } + } + if let presentation = presentation { + switch presentation { + case let .dataJSON(data): + presentationJsonDescription = data } } - let isVideoMuted = (flags & (1 << 14)) != 0 participantUpdates.append(GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate( peerId: peerId, ssrc: ssrc, - jsonParams: jsonParams, + videoJsonDescription: videoJsonDescription, + presentationJsonDescription: presentationJsonDescription, joinTimestamp: date, activityTimestamp: activeDate.flatMap(Double.init), raiseHandRating: raiseHandRating, muteState: muteState, - isVideoMuted: isVideoMuted, participationStatusChange: participationStatusChange, volume: volume, about: about, diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 1a5c57a4aa..b604c6b532 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -2991,13 +2991,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP }) switch call { - case let .groupCall(flags, _, _, _, _, title, _, recordStartDate, scheduleDate, _): + case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _): let isMuted = (flags & (1 << 1)) != 0 let canChange = (flags & (1 << 2)) != 0 + let isVideoEnabled = (flags & (1 << 9)) != 0 let defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange) updatedGroupCallParticipants.append(( info.id, - .call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, title: title, recordingStartTimestamp: recordStartDate, scheduleTimestamp: scheduleDate) + .call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, title: title, recordingStartTimestamp: recordStartDate, scheduleTimestamp: scheduleDate, isVideoEnabled: isVideoEnabled) )) default: break @@ -3006,7 +3007,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP case let .groupCallDiscarded(callId, _, _): updatedGroupCallParticipants.append(( callId, - .call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), title: nil, recordingStartTimestamp: nil, scheduleTimestamp: nil) + .call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), title: nil, recordingStartTimestamp: nil, scheduleTimestamp: nil, isVideoEnabled: false) )) transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index 332b43b81f..0ea3aa0e9f 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 128 + return 129 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index a0387af49b..c8ad45a0d4 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -287,10 +287,8 @@ public final class OngoingGroupCallContext { deinit { } - func setJoinResponse(payload: String, participants: [(UInt32, String?)]) { - self.context.setJoinResponsePayload(payload, participants: participants.map { participant -> OngoingGroupCallParticipantDescription in - return OngoingGroupCallParticipantDescription(audioSsrc: participant.0, jsonParams: participant.1) - }) + func setJoinResponse(payload: String) { + self.context.setJoinResponsePayload(payload) } func addSsrcs(ssrcs: [UInt32]) { @@ -317,12 +315,12 @@ public final class OngoingGroupCallContext { self.context.setFullSizeVideoSsrc(ssrc ?? 0) } - func addParticipants(participants: [(UInt32, String?)]) { + func addParticipants(participants: [(UInt32, String?, String?)]) { if participants.isEmpty { return } self.context.addParticipants(participants.map { participant -> OngoingGroupCallParticipantDescription in - return OngoingGroupCallParticipantDescription(audioSsrc: participant.0, jsonParams: participant.1) + return OngoingGroupCallParticipantDescription(audioSsrc: participant.0, videoJsonDescription: participant.1, screencastJsonDescription: participant.2) }) } @@ -596,9 +594,9 @@ public final class OngoingGroupCallContext { impl.switchAudioOutput(deviceId) } } - public func setJoinResponse(payload: String, participants: [(UInt32, String?)]) { + public func setJoinResponse(payload: String) { self.impl.with { impl in - impl.setJoinResponse(payload: payload, participants: participants) + impl.setJoinResponse(payload: payload) } } @@ -632,7 +630,7 @@ public final class OngoingGroupCallContext { } } - public func addParticipants(participants: [(UInt32, String?)]) { + public func addParticipants(participants: [(UInt32, String?, String?)]) { self.impl.with { impl in impl.addParticipants(participants: participants) } diff --git a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h index f27af30947..15b1db45ff 100644 --- a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h +++ b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h @@ -159,9 +159,10 @@ typedef struct { @interface OngoingGroupCallParticipantDescription : NSObject @property (nonatomic, readonly) uint32_t audioSsrc; -@property (nonatomic, strong, readonly) NSString * _Nullable jsonParams; +@property (nonatomic, strong, readonly) NSString * _Nullable videoJsonDescription; +@property (nonatomic, strong, readonly) NSString * _Nullable screencastJsonDescription; -- (instancetype _Nonnull)initWithAudioSsrc:(uint32_t)audioSsrc jsonParams:(NSString * _Nullable)jsonParams; +- (instancetype _Nonnull)initWithAudioSsrc:(uint32_t)audioSsrc videoJsonDescription:(NSString * _Nullable)videoJsonDescription screencastJsonDescription:(NSString * _Nullable)screencastJsonDescription; @end @@ -209,7 +210,7 @@ typedef NS_ENUM(int32_t, OngoingGroupCallVideoContentType) { - (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled; - (void)emitJoinPayload:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion; -- (void)setJoinResponsePayload:(NSString * _Nonnull)payload participants:(NSArray * _Nonnull)participants; +- (void)setJoinResponsePayload:(NSString * _Nonnull)payload; - (void)removeSsrcs:(NSArray * _Nonnull)ssrcs; - (void)removeIncomingVideoSource:(uint32_t)ssrc; - (void)addParticipants:(NSArray * _Nonnull)participants; diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 0ad2388c0c..af087ebacd 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -433,7 +433,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; .enableNS = true, .enableAGC = true, .enableCallUpgrade = false, - .logPath = std::string(logPath.length == 0 ? "" : logPath.UTF8String), + .logPath = std::string(logPath.length == 0 ? "" : logPath.UTF8String), .statsLogPath = std::string(statsLogPath.length == 0 ? "" : statsLogPath.UTF8String), .maxApiLayer = [OngoingCallThreadLocalContextWebrtc maxLayer], .enableHighBitrateVideo = true, @@ -983,102 +983,6 @@ private: } } -static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonnull completion)(NSString * _Nonnull, uint32_t)) { - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - - int32_t signedSsrc = *(int32_t *)&payload.ssrc; - - dict[@"ssrc"] = @(signedSsrc); - dict[@"ufrag"] = [NSString stringWithUTF8String:payload.ufrag.c_str()]; - dict[@"pwd"] = [NSString stringWithUTF8String:payload.pwd.c_str()]; - - NSMutableArray *fingerprints = [[NSMutableArray alloc] init]; - for (auto &fingerprint : payload.fingerprints) { - [fingerprints addObject:@{ - @"hash": [NSString stringWithUTF8String:fingerprint.hash.c_str()], - @"fingerprint": [NSString stringWithUTF8String:fingerprint.fingerprint.c_str()], - @"setup": [NSString stringWithUTF8String:fingerprint.setup.c_str()] - }]; - } - - dict[@"fingerprints"] = fingerprints; - - NSMutableArray *parsedVideoSsrcGroups = [[NSMutableArray alloc] init]; - NSMutableArray *parsedVideoSources = [[NSMutableArray alloc] init]; - for (auto &group : payload.videoSourceGroups) { - NSMutableDictionary *parsedGroup = [[NSMutableDictionary alloc] init]; - parsedGroup[@"semantics"] = [NSString stringWithUTF8String:group.semantics.c_str()]; - NSMutableArray *sources = [[NSMutableArray alloc] init]; - for (auto &source : group.ssrcs) { - [sources addObject:@(source)]; - if (![parsedVideoSources containsObject:@(source)]) { - [parsedVideoSources addObject:@(source)]; - } - } - parsedGroup[@"sources"] = sources; - [parsedVideoSsrcGroups addObject:parsedGroup]; - } - if (parsedVideoSsrcGroups.count != 0) { - dict[@"ssrc-groups"] = parsedVideoSsrcGroups; - } - - NSMutableArray *videoPayloadTypes = [[NSMutableArray alloc] init]; - for (auto &payloadType : payload.videoPayloadTypes) { - NSMutableDictionary *parsedType = [[NSMutableDictionary alloc] init]; - parsedType[@"id"] = @(payloadType.id); - NSString *name = [NSString stringWithUTF8String:payloadType.name.c_str()]; - parsedType[@"name"] = name; - parsedType[@"clockrate"] = @(payloadType.clockrate); - if (![name isEqualToString:@"rtx"]) { - parsedType[@"channels"] = @(payloadType.channels); - } - - NSMutableDictionary *parsedParameters = [[NSMutableDictionary alloc] init]; - for (auto &it : payloadType.parameters) { - NSString *key = [NSString stringWithUTF8String:it.first.c_str()]; - NSString *value = [NSString stringWithUTF8String:it.second.c_str()]; - parsedParameters[key] = value; - } - if (parsedParameters.count != 0) { - parsedType[@"parameters"] = parsedParameters; - } - - if (![name isEqualToString:@"rtx"]) { - NSMutableArray *parsedFbs = [[NSMutableArray alloc] init]; - for (auto &it : payloadType.feedbackTypes) { - NSMutableDictionary *parsedFb = [[NSMutableDictionary alloc] init]; - parsedFb[@"type"] = [NSString stringWithUTF8String:it.type.c_str()]; - if (it.subtype.size() != 0) { - parsedFb[@"subtype"] = [NSString stringWithUTF8String:it.subtype.c_str()]; - } - [parsedFbs addObject:parsedFb]; - } - parsedType[@"rtcp-fbs"] = parsedFbs; - } - - [videoPayloadTypes addObject:parsedType]; - } - if (videoPayloadTypes.count != 0) { - dict[@"payload-types"] = videoPayloadTypes; - } - - NSMutableArray *parsedExtensions = [[NSMutableArray alloc] init]; - for (auto &it : payload.videoExtensionMap) { - NSMutableDictionary *parsedExtension = [[NSMutableDictionary alloc] init]; - parsedExtension[@"id"] = @(it.first); - parsedExtension[@"uri"] = [NSString stringWithUTF8String:it.second.c_str()]; - [parsedExtensions addObject:parsedExtension]; - } - if (parsedExtensions.count != 0) { - dict[@"rtp-hdrexts"] = parsedExtensions; - } - - NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil]; - NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - - completion(string, payload.ssrc); -} - - (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled { if (_instance) { tgcalls::GroupConnectionMode mappedConnectionMode; @@ -1106,184 +1010,15 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn - (void)emitJoinPayload:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion { if (_instance) { - _instance->emitJoinPayload([completion](tgcalls::GroupJoinPayload payload) { - processJoinPayload(payload, completion); + _instance->emitJoinPayload([completion](tgcalls::GroupJoinPayload const &payload) { + completion([NSString stringWithUTF8String:payload.json.c_str()], payload.audioSsrc); }); } } -- (void)setJoinResponsePayload:(NSString * _Nonnull)payload participants:(NSArray * _Nonnull)participants { - tgcalls::GroupJoinResponsePayload result; - - NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding]; - if (payloadData == nil) { - return; - } - - NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil]; - if (![dict isKindOfClass:[NSDictionary class]]) { - return; - } - - NSDictionary *transport = dict[@"transport"]; - if (![transport isKindOfClass:[NSDictionary class]]) { - return; - } - - NSString *pwd = transport[@"pwd"]; - if (![pwd isKindOfClass:[NSString class]]) { - return; - } - - NSString *ufrag = transport[@"ufrag"]; - if (![ufrag isKindOfClass:[NSString class]]) { - return; - } - - result.pwd = [pwd UTF8String]; - result.ufrag = [ufrag UTF8String]; - - NSArray *fingerprintsValue = transport[@"fingerprints"]; - if (![fingerprintsValue isKindOfClass:[NSArray class]]) { - //return; - } - - for (NSDictionary *fingerprintValue in fingerprintsValue) { - if (![fingerprintValue isKindOfClass:[NSDictionary class]]) { - continue; - } - NSString *hashValue = fingerprintValue[@"hash"]; - if (![hashValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *fingerprint = fingerprintValue[@"fingerprint"]; - if (![fingerprint isKindOfClass:[NSString class]]) { - continue; - } - NSString *setup = fingerprintValue[@"setup"]; - if (![setup isKindOfClass:[NSString class]]) { - continue; - } - tgcalls::GroupJoinPayloadFingerprint parsed; - parsed.fingerprint = [fingerprint UTF8String]; - parsed.setup = [setup UTF8String]; - parsed.hash = [hashValue UTF8String]; - result.fingerprints.push_back(parsed); - } - - NSArray *candidatesValue = transport[@"candidates"]; - if (![candidatesValue isKindOfClass:[NSArray class]]) { - return; - } - - for (NSDictionary *candidateValue in candidatesValue) { - if (![candidateValue isKindOfClass:[NSDictionary class]]) { - continue; - } - - NSString *portValue = candidateValue[@"port"]; - if (![portValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *protocolValue = candidateValue[@"protocol"]; - if (![protocolValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *networkValue = candidateValue[@"network"]; - if (![networkValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *generationValue = candidateValue[@"generation"]; - if (![generationValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *idValue = candidateValue[@"id"]; - if (![idValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *componentValue = candidateValue[@"component"]; - if (![componentValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *foundationValue = candidateValue[@"foundation"]; - if (![foundationValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *priorityValue = candidateValue[@"priority"]; - if (![priorityValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *ipValue = candidateValue[@"ip"]; - if (![ipValue isKindOfClass:[NSString class]]) { - continue; - } - NSString *typeValue = candidateValue[@"type"]; - if (![typeValue isKindOfClass:[NSString class]]) { - continue; - } - - NSString *tcpTypeValue = candidateValue[@"tcptype"]; - if (![tcpTypeValue isKindOfClass:[NSString class]]) { - tcpTypeValue = @""; - } - NSString *relAddrValue = candidateValue[@"rel-addr"]; - if (![relAddrValue isKindOfClass:[NSString class]]) { - relAddrValue = @""; - } - NSString *relPortValue = candidateValue[@"rel-port"]; - if (![relPortValue isKindOfClass:[NSString class]]) { - relPortValue = @""; - } - - tgcalls::GroupJoinResponseCandidate candidate; - - candidate.port = [portValue UTF8String]; - candidate.protocol = [protocolValue UTF8String]; - candidate.network = [networkValue UTF8String]; - candidate.generation = [generationValue UTF8String]; - candidate.id = [idValue UTF8String]; - candidate.component = [componentValue UTF8String]; - candidate.foundation = [foundationValue UTF8String]; - candidate.priority = [priorityValue UTF8String]; - candidate.ip = [ipValue UTF8String]; - candidate.type = [typeValue UTF8String]; - - candidate.tcpType = [tcpTypeValue UTF8String]; - candidate.relAddr = [relAddrValue UTF8String]; - candidate.relPort = [relPortValue UTF8String]; - - result.candidates.push_back(candidate); - } - - std::vector parsedParticipants; - for (OngoingGroupCallParticipantDescription *participant in participants) { - tgcalls::GroupParticipantDescription parsedParticipant; - parsedParticipant.audioSsrc = participant.audioSsrc; - - if (participant.jsonParams.length != 0) { - [self parseJsonIntoParticipant:participant.jsonParams participant:parsedParticipant]; - } - parsedParticipants.push_back(parsedParticipant); - } - - NSDictionary *video = dict[@"video"]; - if ([video isKindOfClass:[NSDictionary class]]) { - NSArray *serverSources = video[@"server_sources"]; - if ([serverSources isKindOfClass:[NSArray class]]) { - for (NSNumber *sourceNumber in serverSources) { - if ([sourceNumber isKindOfClass:[NSNumber class]]) { - int32_t signedSource = [sourceNumber intValue]; - result.serverVideoBandwidthProbingSsrc = *(int32_t *)&signedSource; - } else if ([sourceNumber isKindOfClass:[NSString class]]) { - uint32_t source = (uint32_t)[sourceNumber longLongValue]; - result.serverVideoBandwidthProbingSsrc = source; - } - } - } - } - +- (void)setJoinResponsePayload:(NSString * _Nonnull)payload { if (_instance) { - _instance->setJoinResponsePayload(result, std::move(parsedParticipants)); + _instance->setJoinResponsePayload(payload.UTF8String); } } @@ -1303,139 +1038,6 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn } } -- (void)parseJsonIntoParticipant:(NSString *)payload participant:(tgcalls::GroupParticipantDescription &)participant { - NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding]; - if (payloadData == nil) { - return; - } - - NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil]; - if (![dict isKindOfClass:[NSDictionary class]]) { - return; - } - - NSString *endpointId = dict[@"endpoint"]; - if (![endpointId isKindOfClass:[NSString class]]) { - return; - } - - participant.endpointId = [endpointId UTF8String]; - - NSArray *ssrcGroups = dict[@"ssrc-groups"]; - if ([ssrcGroups isKindOfClass:[NSArray class]]) { - for (NSDictionary *group in ssrcGroups) { - if (![group isKindOfClass:[NSDictionary class]]) { - continue; - } - NSString *semantics = group[@"semantics"]; - if (![semantics isKindOfClass:[NSString class]]) { - continue; - } - NSArray *sources = group[@"sources"]; - if (![sources isKindOfClass:[NSArray class]]) { - continue; - } - tgcalls::GroupJoinPayloadVideoSourceGroup groupDesc; - for (NSNumber *nSsrc in sources) { - if ([nSsrc isKindOfClass:[NSNumber class]]) { - groupDesc.ssrcs.push_back([nSsrc unsignedIntValue]); - } - } - groupDesc.semantics = [semantics UTF8String]; - participant.videoSourceGroups.push_back(groupDesc); - } - } - - NSArray *hdrExts = dict[@"rtp-hdrexts"]; - if ([hdrExts isKindOfClass:[NSArray class]]) { - for (NSDictionary *extDict in hdrExts) { - if (![extDict isKindOfClass:[NSDictionary class]]) { - continue; - } - NSNumber *nId = extDict[@"id"]; - if (![nId isKindOfClass:[NSNumber class]]) { - continue; - } - NSString *uri = extDict[@"uri"]; - if (![uri isKindOfClass:[NSString class]]) { - continue; - } - participant.videoExtensionMap.push_back(std::make_pair((uint32_t)[nId unsignedIntValue], (std::string)[uri UTF8String])); - } - } - - NSArray *payloadTypes = dict[@"payload-types"]; - if ([payloadTypes isKindOfClass:[NSArray class]]) { - for (NSDictionary *payloadDict in payloadTypes) { - if (![payloadDict isKindOfClass:[NSDictionary class]]) { - continue; - } - NSNumber *nId = payloadDict[@"id"]; - if (![nId isKindOfClass:[NSNumber class]]) { - continue; - } - NSNumber *nClockrate = payloadDict[@"clockrate"]; - if (nClockrate != nil && ![nClockrate isKindOfClass:[NSNumber class]]) { - continue; - } - NSNumber *nChannels = payloadDict[@"channels"]; - if (nChannels != nil && ![nChannels isKindOfClass:[NSNumber class]]) { - continue; - } - NSString *name = payloadDict[@"name"]; - if (![name isKindOfClass:[NSString class]]) { - continue; - } - - tgcalls::GroupJoinPayloadVideoPayloadType parsedPayload; - parsedPayload.id = [nId unsignedIntValue]; - parsedPayload.clockrate = [nClockrate unsignedIntValue]; - parsedPayload.channels = [nChannels unsignedIntValue]; - parsedPayload.name = [name UTF8String]; - - NSArray *fbs = payloadDict[@"rtcp-fbs"]; - if ([fbs isKindOfClass:[NSArray class]]) { - for (NSDictionary *fbDict in fbs) { - if (![fbDict isKindOfClass:[NSDictionary class]]) { - continue; - } - NSString *type = fbDict[@"type"]; - if (![type isKindOfClass:[NSString class]]) { - continue; - } - - NSString *subtype = fbDict[@"subtype"]; - if (subtype != nil && ![subtype isKindOfClass:[NSString class]]) { - continue; - } - - tgcalls::GroupJoinPayloadVideoPayloadFeedbackType parsedFeedback; - parsedFeedback.type = [type UTF8String]; - if (subtype != nil) { - parsedFeedback.subtype = [subtype UTF8String]; - } - parsedPayload.feedbackTypes.push_back(parsedFeedback); - } - } - - NSDictionary *parameters = payloadDict[@"parameters"]; - if ([parameters isKindOfClass:[NSDictionary class]]) { - for (NSString *nKey in parameters) { - if (![nKey isKindOfClass:[NSString class]]) { - continue; - } - NSString *value = parameters[nKey]; - if (![value isKindOfClass:[NSString class]]) { - continue; - } - parsedPayload.parameters.push_back(std::make_pair((std::string)[nKey UTF8String], (std::string)[value UTF8String])); - } - } - participant.videoPayloadTypes.push_back(parsedPayload); - } - } -} - - (void)addParticipants:(NSArray * _Nonnull)participants { if (_instance) { std::vector parsedParticipants; @@ -1443,9 +1045,13 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn tgcalls::GroupParticipantDescription parsedParticipant; parsedParticipant.audioSsrc = participant.audioSsrc; - if (participant.jsonParams.length != 0) { - [self parseJsonIntoParticipant:participant.jsonParams participant:parsedParticipant]; + if (participant.videoJsonDescription.length != 0) { + parsedParticipant.videoInformation = participant.videoJsonDescription.UTF8String; } + if (participant.screencastJsonDescription.length != 0) { + parsedParticipant.screencastInformation = participant.screencastJsonDescription.UTF8String; + } + parsedParticipants.push_back(parsedParticipant); } _instance->addParticipants(std::move(parsedParticipants)); @@ -1466,17 +1072,13 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn - (void)requestVideo:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer completion:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion { if (_instance) { - _instance->setVideoCapture([videoCapturer getInterface], [completion](auto payload){ - processJoinPayload(payload, completion); - }); + _instance->setVideoCapture([videoCapturer getInterface]); } } - (void)disableVideo:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion { if (_instance) { - _instance->setVideoCapture(nullptr, [completion](auto payload){ - processJoinPayload(payload, completion); - }); + _instance->setVideoCapture(nullptr); } } @@ -1548,11 +1150,12 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn @implementation OngoingGroupCallParticipantDescription -- (instancetype _Nonnull)initWithAudioSsrc:(uint32_t)audioSsrc jsonParams:(NSString * _Nullable)jsonParams { +- (instancetype _Nonnull)initWithAudioSsrc:(uint32_t)audioSsrc videoJsonDescription:(NSString * _Nullable)videoJsonDescription screencastJsonDescription:(NSString * _Nullable)screencastJsonDescription { self = [super init]; if (self != nil) { _audioSsrc = audioSsrc; - _jsonParams = jsonParams; + _videoJsonDescription = videoJsonDescription; + _screencastJsonDescription = screencastJsonDescription; } return self; } diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index cd921e97bf..00f592fd56 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit cd921e97bfc6af347ff7f938bd2f40e839f64f79 +Subproject commit 00f592fd569246dca9bd10822b7d6291c2ce53e5