From 92a9bc6e078a1be445a6b0a67d4793ae2324dfa7 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 1 Dec 2020 18:40:14 +0400 Subject: [PATCH] Voice-based ordering --- build-system/generate-xcode-project.sh | 1 - .../Sources/PresentationGroupCall.swift | 44 ++++- .../Sources/VoiceChatController.swift | 28 ++- .../TelegramCore/Sources/GroupCalls.swift | 179 +++++++++++++----- 4 files changed, 192 insertions(+), 60 deletions(-) diff --git a/build-system/generate-xcode-project.sh b/build-system/generate-xcode-project.sh index eb1e5538c8..9910f9d3b9 100755 --- a/build-system/generate-xcode-project.sh +++ b/build-system/generate-xcode-project.sh @@ -51,7 +51,6 @@ BAZEL_OPTIONS=(\ --spawn_strategy=standalone \ --strategy=SwiftCompile=standalone \ --features=swift.enable_batch_mode \ - --apple_generate_dsym \ --swiftcopt=-j${CORE_COUNT_MINUS_ONE} \ ) diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index dc4200ed01..65db070d75 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -191,6 +191,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { private let speakingParticipantsContext = SpeakingParticipantsContext() + private var speakingParticipantsReportTimestamp: [PeerId: Double] = [:] private var participantsContextStateDisposable = MetaDisposable() private var participantsContext: GroupCallParticipantsContext? @@ -382,7 +383,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { removedSsrc.append(participantUpdate.ssrc) if participantUpdate.peerId == strongSelf.accountContext.account.peerId { - strongSelf._canBeRemoved.set(.single(true)) + if case let .estabilished(_, _, ssrc, _) = strongSelf.internalState, ssrc == participantUpdate.ssrc { + strongSelf._canBeRemoved.set(.single(true)) + } } } else if participantUpdate.peerId == strongSelf.accountContext.account.peerId { if case let .estabilished(_, _, ssrc, _) = strongSelf.internalState, ssrc != participantUpdate.ssrc { @@ -601,9 +604,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { ) self.participantsContext = participantsContext self.participantsContextStateDisposable.set(combineLatest(queue: .mainQueue(), - participantsContext.state, - participantsContext.numberOfActiveSpeakers, - self.speakingParticipantsContext.get() + participantsContext.state |> beforeNext { state in + print("before received members") + for member in state.participants { + print(" \(member.peer.debugDisplayTitle) \(member.activityTimestamp ?? 0.0)") + } + }, + participantsContext.numberOfActiveSpeakers |> deliverOnMainQueue, + self.speakingParticipantsContext.get() |> deliverOnMainQueue ).start(next: { [weak self] state, numberOfActiveSpeakers, speakingParticipants in guard let strongSelf = self else { return @@ -611,6 +619,25 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { var topParticipants: [GroupCallParticipantsContext.Participant] = [] + var reportSpeakingParticipants: [PeerId] = [] + let timestamp = CACurrentMediaTime() + for peerId in speakingParticipants { + let shouldReport: Bool + if let previousTimestamp = strongSelf.speakingParticipantsReportTimestamp[peerId] { + shouldReport = previousTimestamp + 1.0 < timestamp + } else { + shouldReport = true + } + if shouldReport { + strongSelf.speakingParticipantsReportTimestamp[peerId] = timestamp + reportSpeakingParticipants.append(peerId) + } + } + + if !reportSpeakingParticipants.isEmpty { + strongSelf.participantsContext?.reportSpeakingParticipants(ids: reportSpeakingParticipants) + } + var members = PresentationGroupCallMembers( participants: [], speakingParticipants: speakingParticipants, @@ -640,6 +667,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { members.totalCount = state.totalCount members.loadMoreToken = state.nextParticipantsFetchOffset + print("received members") + for member in members.participants { + print(" \(member.peer.debugDisplayTitle) \(member.activityTimestamp ?? 0.0)") + } + print("received state members") + for member in state.participants { + print(" \(member.peer.debugDisplayTitle) \(member.activityTimestamp ?? 0.0)") + } + strongSelf.membersValue = members strongSelf.stateValue.adminIds = state.adminIds diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 4631ce10d6..814c6d140b 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -493,6 +493,11 @@ public final class VoiceChatController: ViewController { return } if let groupMembers = strongSelf.currentGroupMembers { + print("update UI members") + for member in callMembers.participants { + print(" \(member.peer.debugDisplayTitle) \(member.activityTimestamp ?? 0.0)") + } + strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, groupMembers: groupMembers, callMembers: callMembers.participants, speakingPeers: callMembers.speakingParticipants, invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } else { strongSelf.currentCallMembers = callMembers.participants @@ -604,7 +609,7 @@ public final class VoiceChatController: ViewController { return } var effectiveLevel: Float = 0.0 - if let state = strongSelf.callState, state.muteState == nil { + if let state = strongSelf.callState, state.muteState == nil, !strongSelf.pushingToTalk { effectiveLevel = level } strongSelf.itemInteraction?.updateAudioLevels([(strongSelf.context.account.peerId, effectiveLevel)]) @@ -1226,18 +1231,20 @@ public final class VoiceChatController: ViewController { return lhs.peer.id < rhs.peer.id }) - var callMembers = callMembers + var sortedCallMembers = callMembers - callMembers.sort() + sortedCallMembers.sort() - for i in 0 ..< callMembers.count { - if callMembers[i].peer.id == self.context.account.peerId { - let member = callMembers[i] - callMembers.remove(at: i) - callMembers.insert(member, at: 0) + /*for i in 0 ..< sortedCallMembers.count { + if sortedCallMembers[i].peer.id == self.context.account.peerId { + let member = sortedCallMembers[i] + sortedCallMembers.remove(at: i) + sortedCallMembers.insert(member, at: 0) break } - } + }*/ + + //assert(sortedCallMembers == callMembers) self.currentGroupMembers = groupMembers self.currentCallMembers = callMembers @@ -1251,12 +1258,15 @@ public final class VoiceChatController: ViewController { var processedPeerIds = Set() + print("UI members") for member in callMembers { if processedPeerIds.contains(member.peer.id) { continue } processedPeerIds.insert(member.peer.id) + print(" \(member.peer.debugDisplayTitle) \(member.activityTimestamp ?? 0.0)") + let memberState: PeerEntry.State var memberMuteState: GroupCallParticipantsContext.Participant.MuteState? if member.peer.id == self.context.account.peerId { diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index 7781c12750..26c68d23a6 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -232,7 +232,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash peer: peer, ssrc: ssrc, joinTimestamp: date, - activityTimestamp: activeDate, + activityTimestamp: activeDate.flatMap(Double.init), muteState: muteState )) } @@ -494,7 +494,7 @@ public final class GroupCallParticipantsContext { public var peer: Peer public var ssrc: UInt32 public var joinTimestamp: Int32 - public var activityTimestamp: Int32? + public var activityTimestamp: Double? public var muteState: MuteState? public static func ==(lhs: Participant, rhs: Participant) -> Bool { @@ -587,7 +587,7 @@ public final class GroupCallParticipantsContext { public var peerId: PeerId public var ssrc: UInt32 public var joinTimestamp: Int32 - public var activityTimestamp: Int32? + public var activityTimestamp: Double? public var muteState: Participant.MuteState? public var isRemoved: Bool } @@ -606,9 +606,20 @@ public final class GroupCallParticipantsContext { private let id: Int64 private let accessHash: Int64 + private var hasReceivedSpeackingParticipantsReport: Bool = false + private var stateValue: InternalState { didSet { - self.statePromise.set(self.stateValue) + if self.stateValue != oldValue { + if self.hasReceivedSpeackingParticipantsReport { + print("set stateValue") + for participant in self.stateValue.state.participants { + print(" \(participant.peer.debugDisplayTitle) \(participant.activityTimestamp ?? 0)") + } + } + + self.statePromise.set(self.stateValue) + } } } private let statePromise: ValuePromise @@ -682,52 +693,56 @@ public final class GroupCallParticipantsContext { strongSelf.numberOfActiveSpeakersValue = activities.count - var updatedParticipants = strongSelf.stateValue.state.participants - var indexMap: [PeerId: Int] = [:] - for i in 0 ..< updatedParticipants.count { - indexMap[updatedParticipants[i].peer.id] = i - } - var updated = false - - for (activityPeerId, activity) in activities { - if case let .speakingInGroupCall(timestamp) = activity { - if let index = indexMap[activityPeerId] { - if let activityTimestamp = updatedParticipants[index].activityTimestamp { - if activityTimestamp < timestamp { + if !strongSelf.hasReceivedSpeackingParticipantsReport { + var updatedParticipants = strongSelf.stateValue.state.participants + var indexMap: [PeerId: Int] = [:] + for i in 0 ..< updatedParticipants.count { + indexMap[updatedParticipants[i].peer.id] = i + } + var updated = false + + for (activityPeerId, activity) in activities { + if case let .speakingInGroupCall(intTimestamp) = activity { + let timestamp = Double(intTimestamp) + + if let index = indexMap[activityPeerId] { + if let activityTimestamp = updatedParticipants[index].activityTimestamp { + if activityTimestamp < timestamp { + updatedParticipants[index].activityTimestamp = timestamp + updated = true + } + } else { updatedParticipants[index].activityTimestamp = timestamp updated = true } - } else { - updatedParticipants[index].activityTimestamp = timestamp - updated = true } } } - } - - if updated { - updatedParticipants.sort() - for i in 0 ..< updatedParticipants.count { - if updatedParticipants[i].peer.id == strongSelf.account.peerId { - let member = updatedParticipants[i] - updatedParticipants.remove(at: i) - updatedParticipants.insert(member, at: 0) - break - } - } - strongSelf.stateValue = InternalState( - state: State( - participants: updatedParticipants, - nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset, - adminIds: strongSelf.stateValue.state.adminIds, - isCreator: strongSelf.stateValue.state.isCreator, - defaultParticipantsAreMuted: strongSelf.stateValue.state.defaultParticipantsAreMuted, - totalCount: strongSelf.stateValue.state.totalCount, - version: strongSelf.stateValue.state.version - ), - overlayState: strongSelf.stateValue.overlayState - ) + if updated { + updatedParticipants.sort() + for i in 0 ..< updatedParticipants.count { + if updatedParticipants[i].peer.id == strongSelf.account.peerId { + let member = updatedParticipants[i] + updatedParticipants.remove(at: i) + updatedParticipants.insert(member, at: 0) + break + } + } + + strongSelf.stateValue = InternalState( + state: State( + participants: updatedParticipants, + nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset, + adminIds: strongSelf.stateValue.state.adminIds, + isCreator: strongSelf.stateValue.state.isCreator, + defaultParticipantsAreMuted: strongSelf.stateValue.state.defaultParticipantsAreMuted, + totalCount: strongSelf.stateValue.state.totalCount, + version: strongSelf.stateValue.state.version + ), + overlayState: strongSelf.stateValue.overlayState + ) + } } }) } @@ -755,6 +770,71 @@ public final class GroupCallParticipantsContext { } } + public func reportSpeakingParticipants(ids: [PeerId]) { + if !ids.isEmpty { + self.hasReceivedSpeackingParticipantsReport = true + } + + let strongSelf = self + + var updatedParticipants = strongSelf.stateValue.state.participants + var indexMap: [PeerId: Int] = [:] + for i in 0 ..< updatedParticipants.count { + indexMap[updatedParticipants[i].peer.id] = i + } + var updated = false + + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + + for activityPeerId in ids { + if let index = indexMap[activityPeerId] { + var updateTimestamp = false + if let activityTimestamp = updatedParticipants[index].activityTimestamp { + if activityTimestamp < timestamp { + updateTimestamp = true + } + } else { + updateTimestamp = true + } + if updateTimestamp { + updatedParticipants[index].activityTimestamp = timestamp + updated = true + + print("update \(updatedParticipants[index].peer.debugDisplayTitle) to \(timestamp)") + } + } + } + + if updated { + updatedParticipants.sort() + for i in 0 ..< updatedParticipants.count { + if updatedParticipants[i].peer.id == strongSelf.account.peerId { + let member = updatedParticipants[i] + updatedParticipants.remove(at: i) + updatedParticipants.insert(member, at: 0) + break + } + } + + for participant in updatedParticipants { + print(" \(participant.peer.debugDisplayTitle) \(participant.activityTimestamp ?? 0)") + } + + strongSelf.stateValue = InternalState( + state: State( + participants: updatedParticipants, + nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset, + adminIds: strongSelf.stateValue.state.adminIds, + isCreator: strongSelf.stateValue.state.isCreator, + defaultParticipantsAreMuted: strongSelf.stateValue.state.defaultParticipantsAreMuted, + totalCount: strongSelf.stateValue.state.totalCount, + version: strongSelf.stateValue.state.version + ), + overlayState: strongSelf.stateValue.overlayState + ) + } + } + private func beginProcessingUpdatesIfNeeded() { if self.isProcessingUpdate { return @@ -824,7 +904,7 @@ public final class GroupCallParticipantsContext { assertionFailure() continue } - var previousActivityTimestamp: Int32? + var previousActivityTimestamp: Double? if let index = updatedParticipants.firstIndex(where: { $0.peer.id == participantUpdate.peerId }) { previousActivityTimestamp = updatedParticipants[index].activityTimestamp updatedParticipants.remove(at: index) @@ -832,7 +912,7 @@ public final class GroupCallParticipantsContext { updatedTotalCount += 1 } - var activityTimestamp: Int32? + var activityTimestamp: Double? if let previousActivityTimestamp = previousActivityTimestamp, let updatedActivityTimestamp = participantUpdate.activityTimestamp { activityTimestamp = max(updatedActivityTimestamp, previousActivityTimestamp) } else { @@ -870,6 +950,13 @@ public final class GroupCallParticipantsContext { } } + if strongSelf.hasReceivedSpeackingParticipantsReport { + print("processUpdate participants") + for participant in updatedParticipants { + print(" \(participant.peer.debugDisplayTitle) \(participant.activityTimestamp ?? 0)") + } + } + strongSelf.stateValue = InternalState( state: State( participants: updatedParticipants, @@ -1014,7 +1101,7 @@ extension GroupCallParticipantsContext.Update.StateUpdate { peerId: peerId, ssrc: ssrc, joinTimestamp: date, - activityTimestamp: activeDate, + activityTimestamp: activeDate.flatMap(Double.init), muteState: muteState, isRemoved: isRemoved ))