From 026ea55ca221f89491c65643cfc6f92af318906f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 12 Mar 2021 15:21:53 +0400 Subject: [PATCH] Voice chat improvements --- submodules/TelegramCallsUI/BUILD | 1 + .../Sources/PresentationGroupCall.swift | 89 +++++++- .../TelegramCore/Sources/GroupCalls.swift | 202 ++++++------------ submodules/TgVoipWebrtc/tgcalls | 2 +- 4 files changed, 142 insertions(+), 152 deletions(-) diff --git a/submodules/TelegramCallsUI/BUILD b/submodules/TelegramCallsUI/BUILD index 855db3d562..50825f66db 100644 --- a/submodules/TelegramCallsUI/BUILD +++ b/submodules/TelegramCallsUI/BUILD @@ -41,6 +41,7 @@ swift_library( "//submodules/AnimatedCountLabelNode:AnimatedCountLabelNode", "//submodules/DeviceProximity:DeviceProximity", "//submodules/ManagedAnimationNode:ManagedAnimationNode", + "//submodules/TemporaryCachedPeerDataManager:TemporaryCachedPeerDataManager", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 02c4ee31c3..e2d921fa52 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -16,6 +16,7 @@ import UniversalMediaPlayer import AccountContext import DeviceProximity import UndoUI +import TemporaryCachedPeerDataManager private extension GroupCallParticipantsContext.Participant { var allSsrcs: Set { @@ -353,10 +354,13 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { public let peerId: PeerId private let invite: String? private var joinAsPeerId: PeerId + private var ignorePreviousJoinAsPeerId: (PeerId, UInt32)? public private(set) var isVideo: Bool - private let temporaryJoinTimestamp: Int32 + private var temporaryJoinTimestamp: Int32 + private var temporaryActivityTimestamp: Double? + private var temporaryActivityRank: Int? private var internalState: InternalState = .requesting private let internalStatePromise = Promise(.requesting) @@ -874,8 +878,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: nil, hasRaiseHand: false, - activityTimestamp: nil, - activityRank: nil, + activityTimestamp: strongSelf.temporaryActivityTimestamp, + activityRank: strongSelf.temporaryActivityRank, muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false), volume: nil, about: about @@ -1005,6 +1009,35 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { guard let strongSelf = self else { return } + + let peerAdminIds: Signal<[PeerId], NoError> + let peerId = strongSelf.peerId + if strongSelf.peerId.namespace == Namespaces.Peer.CloudChannel { + peerAdminIds = strongSelf.account.postbox.transaction { transaction -> [PeerId] in + var result: [PeerId] = [] + if let entry = transaction.retrieveItemCacheEntry(id: cachedChannelAdminRanksEntryId(peerId: peerId)) as? CachedChannelAdminRanks { + result = Array(entry.ranks.keys) + } + return result + } + } else { + peerAdminIds = strongSelf.account.postbox.transaction { transaction -> [PeerId] in + var result: [PeerId] = [] + if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData { + if let participants = cachedData.participants { + for participant in participants.participants { + if case .creator = participant { + result.append(participant.peerId) + } else if case .admin = participant { + result.append(participant.peerId) + } + } + } + } + return result + } + } + strongSelf.currentLocalSsrc = ssrc strongSelf.requestDisposable.set((joinGroupCall( account: strongSelf.account, @@ -1014,6 +1047,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { accessHash: callInfo.accessHash, preferMuted: true, joinPayload: joinPayload, + peerAdminIds: peerAdminIds, inviteHash: strongSelf.invite ) |> deliverOnMainQueue).start(next: { joinCallResult in @@ -1223,8 +1257,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.temporaryParticipantsContext = nil self.participantsContext = participantsContext let myPeerId = self.joinAsPeerId - let myPeer = self.accountContext.account.postbox.transaction { transaction -> Peer? in - return transaction.getPeer(myPeerId) + let myPeer = self.accountContext.account.postbox.transaction { transaction -> (Peer, CachedPeerData?)? in + if let peer = transaction.getPeer(myPeerId) { + return (peer, transaction.getPeerCachedData(peerId: myPeerId)) + } else { + return nil + } } self.participantsContextStateDisposable.set(combineLatest(queue: .mainQueue(), participantsContext.state, @@ -1234,7 +1272,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { myPeer, accountContext.account.postbox.peerView(id: peerId), self.isReconnectingAsSpeakerPromise.get() - ).start(next: { [weak self] state, activeSpeakers, speakingParticipants, adminIds, myPeer, view, isReconnectingAsSpeaker in + ).start(next: { [weak self] state, activeSpeakers, speakingParticipants, adminIds, myPeerAndCachedData, view, isReconnectingAsSpeaker in guard let strongSelf = self else { return } @@ -1271,10 +1309,29 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { var updatedInvitedPeers = strongSelf.invitedPeersValue var didUpdateInvitedPeers = false - + var participants = state.participants + + if let (ignorePeerId, ignoreSsrc) = strongSelf.ignorePreviousJoinAsPeerId { + for i in 0 ..< participants.count { + if participants[i].peer.id == ignorePeerId && participants[i].ssrc == ignoreSsrc { + participants.remove(at: i) + break + } + } + } + if !participants.contains(where: { $0.peer.id == myPeerId }) { - if let myPeer = myPeer { + if let (myPeer, cachedData) = myPeerAndCachedData { + let about: String? + if let cachedData = cachedData as? CachedUserData { + about = cachedData.about + } else if let cachedData = cachedData as? CachedUserData { + about = cachedData.about + } else { + about = nil + } + participants.append(GroupCallParticipantsContext.Participant( peer: myPeer, ssrc: nil, @@ -1282,11 +1339,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { joinTimestamp: strongSelf.temporaryJoinTimestamp, raiseHandRating: nil, hasRaiseHand: false, - activityTimestamp: nil, - activityRank: nil, + activityTimestamp: strongSelf.temporaryActivityTimestamp, + activityRank: strongSelf.temporaryActivityRank, muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false), volume: nil, - about: nil + about: about )) participants.sort() } @@ -1601,9 +1658,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } let previousPeerId = strongSelf.joinAsPeerId + if let localSsrc = strongSelf.currentLocalSsrc { + strongSelf.ignorePreviousJoinAsPeerId = (previousPeerId, localSsrc) + } strongSelf.joinAsPeerId = peerId if let participantsContext = strongSelf.participantsContext, let immediateState = participantsContext.immediateState { + for participant in immediateState.participants { + if participant.peer.id == previousPeerId { + strongSelf.temporaryJoinTimestamp = participant.joinTimestamp + strongSelf.temporaryActivityTimestamp = participant.activityTimestamp + strongSelf.temporaryActivityRank = participant.activityRank + } + } strongSelf.switchToTemporaryParticipantsContext(sourceContext: participantsContext, initialState: immediateState, oldMyPeerId: previousPeerId) } else { strongSelf.stateValue.myPeerId = peerId diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index 5ab6e1f8e4..49bf98c06b 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -356,7 +356,7 @@ public struct JoinGroupCallResult { public var connectionMode: ConnectionMode } -public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String, inviteHash: String? = nil) -> Signal { +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 { return account.postbox.transaction { transaction -> Api.InputPeer? in if let joinAs = joinAs { return transaction.getPeer(joinAs).flatMap(apiInputPeer) @@ -377,8 +377,8 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal if let _ = inviteHash { flags |= (1 << 1) } - - return account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), joinAs: inputJoinAs, inviteHash: inviteHash, params: .dataJSON(data: joinPayload))) + + let joinRequest = account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), joinAs: inputJoinAs, inviteHash: inviteHash, params: .dataJSON(data: joinPayload))) |> mapError { error -> JoinGroupCallError in if error.errorDescription == "GROUPCALL_ANONYMOUS_FORBIDDEN" { return .anonymousNotAllowed @@ -387,92 +387,32 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal } return .generic } - |> mapToSignal { updates -> Signal in - let admins: Signal<(Set, [Api.User]), JoinGroupCallError> - if peerId.namespace == Namespaces.Peer.CloudChannel { - admins = account.postbox.transaction { transaction -> Api.InputChannel? in - return transaction.getPeer(peerId).flatMap(apiInputChannel) - } - |> castError(JoinGroupCallError.self) - |> mapToSignal { inputChannel -> Signal in - guard let inputChannel = inputChannel else { - return .fail(.generic) - } - - return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: 0)) - |> `catch` { _ in - return .single(.channelParticipantsNotModified) - } - } - |> map { admins -> (Set, [Api.User]) in - var adminIds = Set() - var apiUsers: [Api.User] = [] - - switch admins { - case let .channelParticipants(_, participants, users): - apiUsers.append(contentsOf: users) - - for participant in participants { - let parsedParticipant = ChannelParticipant(apiParticipant: participant) - switch parsedParticipant { - case .creator: - adminIds.insert(parsedParticipant.peerId) - case let .member(_, _, adminInfo, _, _): - if let adminInfo = adminInfo, adminInfo.rights.rights.contains(.canManageCalls) { - adminIds.insert(parsedParticipant.peerId) - } - } - } - default: - break - } - - return (adminIds, apiUsers) - } - } else if peerId.namespace == Namespaces.Peer.CloudGroup { - admins = account.postbox.transaction { transaction -> (Set, [Api.User]) in - var result = Set() - if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData { - if let participants = cachedData.participants { - for participant in participants.participants { - if case .creator = participant { - result.insert(participant.peerId) - } else if case .admin = participant { - result.insert(participant.peerId) - } - } - } - } - return (result, []) - } - |> castError(JoinGroupCallError.self) - } else { - admins = .fail(.generic) - } - + + let getParticipantsRequest = getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", ssrcs: [], limit: 100) + |> mapError { _ -> JoinGroupCallError in + return .generic + } + + return combineLatest( + joinRequest, + getParticipantsRequest + ) + |> mapToSignal { updates, participantsState -> Signal in let peer = account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) } |> castError(JoinGroupCallError.self) return combineLatest( - account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash))) - |> mapError { _ -> JoinGroupCallError in - return .generic - }, - getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", ssrcs: [], limit: 100) - |> mapError { _ -> JoinGroupCallError in - return .generic - }, - admins, + peerAdminIds |> castError(JoinGroupCallError.self) |> take(1), peer ) - |> mapToSignal { result, state, admins, peer -> Signal in + |> mapToSignal { peerAdminIds, peer -> Signal in guard let peer = peer else { return .fail(.generic) } - var state = state + var state = participantsState if let channel = peer as? TelegramChannel { state.isCreator = channel.flags.contains(.isCreator) } else if let group = peer as? TelegramGroup { @@ -514,71 +454,53 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal var apiUsers: [Api.User] = [] - let (adminIds, adminUsers) = admins - apiUsers.append(contentsOf: adminUsers) - - state.adminIds = adminIds - - switch result { - case let .groupCall(call, _, _, chats, users): - guard let _ = GroupCallInfo(call) else { - return .fail(.generic) + state.adminIds = Set(peerAdminIds) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + + for user in apiUsers { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence } - - apiUsers.append(contentsOf: users) - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - - for user in apiUsers { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - for chat in chats { - if let peer = parseTelegramGroupOrChannel(chat: chat) { - peers.append(peer) - } - } - - 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 stream = dict["stream"] as? Bool, stream { - connectionMode = .broadcast - } else { - connectionMode = .rtc - } - } else { - connectionMode = .broadcast - } - - return account.postbox.transaction { transaction -> JoinGroupCallResult in - transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in - if let cachedData = cachedData as? CachedChannelData { - return cachedData.withUpdatedCallJoinPeerId(joinAs) - } else if let cachedData = cachedData as? CachedGroupData { - return cachedData.withUpdatedCallJoinPeerId(joinAs) - } else { - return cachedData - } - }) - - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) - - return JoinGroupCallResult( - callInfo: parsedCall, - state: state, - connectionMode: connectionMode - ) - } - |> castError(JoinGroupCallError.self) } + + 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 stream = dict["stream"] as? Bool, stream { + connectionMode = .broadcast + } else { + connectionMode = .rtc + } + } else { + connectionMode = .broadcast + } + + return account.postbox.transaction { transaction -> JoinGroupCallResult in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData { + return cachedData.withUpdatedCallJoinPeerId(joinAs) + } else if let cachedData = cachedData as? CachedGroupData { + return cachedData.withUpdatedCallJoinPeerId(joinAs) + } else { + return cachedData + } + }) + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) + + return JoinGroupCallResult( + callInfo: parsedCall, + state: state, + connectionMode: connectionMode + ) + } + |> castError(JoinGroupCallError.self) } } } diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 4a95374737..30070e3d27 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 4a953747375b8648f8b66e9572b59b10f7b769a1 +Subproject commit 30070e3d277debf4a69e0df001faffe571465614