Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2020-12-02 08:30:08 +04:00
commit de73c57d9d
6 changed files with 161 additions and 66 deletions

View File

@ -51,7 +51,6 @@ BAZEL_OPTIONS=(\
--spawn_strategy=standalone \ --spawn_strategy=standalone \
--strategy=SwiftCompile=standalone \ --strategy=SwiftCompile=standalone \
--features=swift.enable_batch_mode \ --features=swift.enable_batch_mode \
--apple_generate_dsym \
--swiftcopt=-j${CORE_COUNT_MINUS_ONE} \ --swiftcopt=-j${CORE_COUNT_MINUS_ONE} \
) )

View File

@ -202,6 +202,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
private var audioLevelsDisposable = MetaDisposable() private var audioLevelsDisposable = MetaDisposable()
private let speakingParticipantsContext = SpeakingParticipantsContext() private let speakingParticipantsContext = SpeakingParticipantsContext()
private var speakingParticipantsReportTimestamp: [PeerId: Double] = [:]
public var speakingAudioLevels: Signal<[(PeerId, Float)], NoError> { public var speakingAudioLevels: Signal<[(PeerId, Float)], NoError> {
return self.speakingParticipantsContext.getAudioLevels() return self.speakingParticipantsContext.getAudioLevels()
} }
@ -396,7 +397,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
removedSsrc.append(participantUpdate.ssrc) removedSsrc.append(participantUpdate.ssrc)
if participantUpdate.peerId == strongSelf.accountContext.account.peerId { 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 { } else if participantUpdate.peerId == strongSelf.accountContext.account.peerId {
if case let .estabilished(_, _, ssrc, _) = strongSelf.internalState, ssrc != participantUpdate.ssrc { if case let .estabilished(_, _, ssrc, _) = strongSelf.internalState, ssrc != participantUpdate.ssrc {
@ -616,8 +619,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.participantsContext = participantsContext self.participantsContext = participantsContext
self.participantsContextStateDisposable.set(combineLatest(queue: .mainQueue(), self.participantsContextStateDisposable.set(combineLatest(queue: .mainQueue(),
participantsContext.state, participantsContext.state,
participantsContext.numberOfActiveSpeakers, participantsContext.numberOfActiveSpeakers |> deliverOnMainQueue,
self.speakingParticipantsContext.get() self.speakingParticipantsContext.get() |> deliverOnMainQueue
).start(next: { [weak self] state, numberOfActiveSpeakers, speakingParticipants in ).start(next: { [weak self] state, numberOfActiveSpeakers, speakingParticipants in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -625,6 +628,27 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
var topParticipants: [GroupCallParticipantsContext.Participant] = [] 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 {
Queue.mainQueue().justDispatch {
self?.participantsContext?.reportSpeakingParticipants(ids: reportSpeakingParticipants)
}
}
var members = PresentationGroupCallMembers( var members = PresentationGroupCallMembers(
participants: [], participants: [],
speakingParticipants: speakingParticipants, speakingParticipants: speakingParticipants,

View File

@ -314,11 +314,11 @@ public final class VoiceChatController: ViewController {
let revealOptions: [VoiceChatParticipantItem.RevealOption] = [] let revealOptions: [VoiceChatParticipantItem.RevealOption] = []
return VoiceChatParticipantItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: peer, presence: peerEntry.presence, text: text, icon: icon, enabled: true, getAudioLevel: { return interaction.getAudioLevel(peer.id) }, revealOptions: revealOptions, revealed: peerEntry.revealed, setPeerIdWithRevealedOptions: { peerId, fromPeerId in return VoiceChatParticipantItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: peer, presence: peerEntry.presence, text: text, icon: icon, enabled: true, selectable: peer.id != context.account.peerId, getAudioLevel: { return interaction.getAudioLevel(peer.id) }, revealOptions: revealOptions, revealed: peerEntry.revealed, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
interaction.setPeerIdWithRevealedOptions(peerId, fromPeerId) interaction.setPeerIdWithRevealedOptions(peerId, fromPeerId)
}, action: { }, action: {
interaction.openPeer(peer.id) interaction.openPeer(peer.id)
}, contextAction: { node, gesture in }, contextAction: peer.id == context.account.peerId ? nil : { node, gesture in
interaction.peerContextAction(peerEntry, node, gesture) interaction.peerContextAction(peerEntry, node, gesture)
}) })
} }
@ -443,7 +443,8 @@ public final class VoiceChatController: ViewController {
updateIsMuted: { [weak self] peerId, isMuted in updateIsMuted: { [weak self] peerId, isMuted in
self?.call.updateMuteState(peerId: peerId, isMuted: isMuted) self?.call.updateMuteState(peerId: peerId, isMuted: isMuted)
}, openPeer: { [weak self] peerId in }, openPeer: { [weak self] peerId in
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { if let strongSelf = self, let navigationController = strongSelf.controller?.parentNavigationController {
strongSelf.controller?.dismiss()
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), keepStack: .always, purposefulAction: {}, peekData: nil)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), keepStack: .always, purposefulAction: {}, peekData: nil))
} }
}, openInvite: { }, openInvite: {
@ -1190,17 +1191,19 @@ public final class VoiceChatController: ViewController {
} }
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, groupMembers: [RenderedChannelParticipant], callMembers: [GroupCallParticipantsContext.Participant], speakingPeers: Set<PeerId>) { private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, groupMembers: [RenderedChannelParticipant], callMembers: [GroupCallParticipantsContext.Participant], speakingPeers: Set<PeerId>) {
var callMembers = callMembers var sortedCallMembers = callMembers
callMembers.sort() sortedCallMembers.sort()
for i in 0 ..< callMembers.count { /*for i in 0 ..< sortedCallMembers.count {
if callMembers[i].peer.id == self.context.account.peerId { if sortedCallMembers[i].peer.id == self.context.account.peerId {
let member = callMembers[i] let member = sortedCallMembers[i]
callMembers.remove(at: i) sortedCallMembers.remove(at: i)
callMembers.insert(member, at: 0) sortedCallMembers.insert(member, at: 0)
break break
} }
} }*/
//assert(sortedCallMembers == callMembers)
self.currentGroupMembers = groupMembers self.currentGroupMembers = groupMembers
self.currentCallMembers = callMembers self.currentCallMembers = callMembers
@ -1214,7 +1217,7 @@ public final class VoiceChatController: ViewController {
var processedPeerIds = Set<PeerId>() var processedPeerIds = Set<PeerId>()
entries.append(.invite(self.presentationData.theme, self.presentationData.strings, "Invite Member")) entries.append(.invite(self.presentationData.theme, self.presentationData.strings, "Invite Member"))
for member in callMembers { for member in callMembers {
if processedPeerIds.contains(member.peer.id) { if processedPeerIds.contains(member.peer.id) {
continue continue
@ -1300,6 +1303,7 @@ public final class VoiceChatController: ViewController {
private let sharedContext: SharedAccountContext private let sharedContext: SharedAccountContext
public let call: PresentationGroupCall public let call: PresentationGroupCall
private let presentationData: PresentationData private let presentationData: PresentationData
public var parentNavigationController: NavigationController?
fileprivate let contentsReady = ValuePromise<Bool>(false, ignoreRepeated: true) fileprivate let contentsReady = ValuePromise<Bool>(false, ignoreRepeated: true)
fileprivate let dataReady = ValuePromise<Bool>(false, ignoreRepeated: true) fileprivate let dataReady = ValuePromise<Bool>(false, ignoreRepeated: true)

View File

@ -65,6 +65,7 @@ public final class VoiceChatParticipantItem: ListViewItem {
let text: ParticipantText let text: ParticipantText
let icon: Icon let icon: Icon
let enabled: Bool let enabled: Bool
public let selectable: Bool
let getAudioLevel: (() -> Signal<Float, NoError>)? let getAudioLevel: (() -> Signal<Float, NoError>)?
let revealOptions: [RevealOption] let revealOptions: [RevealOption]
let revealed: Bool? let revealed: Bool?
@ -72,7 +73,7 @@ public final class VoiceChatParticipantItem: ListViewItem {
let action: (() -> Void)? let action: (() -> Void)?
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, presence: PeerPresence?, text: ParticipantText, icon: Icon, enabled: Bool, getAudioLevel: (() -> Signal<Float, NoError>)?, revealOptions: [RevealOption], revealed: Bool?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, action: (() -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil) { public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, presence: PeerPresence?, text: ParticipantText, icon: Icon, enabled: Bool, selectable: Bool, getAudioLevel: (() -> Signal<Float, NoError>)?, revealOptions: [RevealOption], revealed: Bool?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, action: (() -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil) {
self.presentationData = presentationData self.presentationData = presentationData
self.dateTimeFormat = dateTimeFormat self.dateTimeFormat = dateTimeFormat
self.nameDisplayOrder = nameDisplayOrder self.nameDisplayOrder = nameDisplayOrder
@ -82,6 +83,7 @@ public final class VoiceChatParticipantItem: ListViewItem {
self.text = text self.text = text
self.icon = icon self.icon = icon
self.enabled = enabled self.enabled = enabled
self.selectable = selectable
self.getAudioLevel = getAudioLevel self.getAudioLevel = getAudioLevel
self.revealOptions = revealOptions self.revealOptions = revealOptions
self.revealed = revealed self.revealed = revealed
@ -89,9 +91,7 @@ public final class VoiceChatParticipantItem: ListViewItem {
self.action = action self.action = action
self.contextAction = contextAction self.contextAction = contextAction
} }
public var selectable: Bool = true
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async { async {
let node = VoiceChatParticipantItemNode() let node = VoiceChatParticipantItemNode()

View File

@ -232,7 +232,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
peer: peer, peer: peer,
ssrc: ssrc, ssrc: ssrc,
joinTimestamp: date, joinTimestamp: date,
activityTimestamp: activeDate, activityTimestamp: activeDate.flatMap(Double.init),
muteState: muteState muteState: muteState
)) ))
} }
@ -494,7 +494,7 @@ public final class GroupCallParticipantsContext {
public var peer: Peer public var peer: Peer
public var ssrc: UInt32 public var ssrc: UInt32
public var joinTimestamp: Int32 public var joinTimestamp: Int32
public var activityTimestamp: Int32? public var activityTimestamp: Double?
public var muteState: MuteState? public var muteState: MuteState?
public static func ==(lhs: Participant, rhs: Participant) -> Bool { public static func ==(lhs: Participant, rhs: Participant) -> Bool {
@ -587,7 +587,7 @@ public final class GroupCallParticipantsContext {
public var peerId: PeerId public var peerId: PeerId
public var ssrc: UInt32 public var ssrc: UInt32
public var joinTimestamp: Int32 public var joinTimestamp: Int32
public var activityTimestamp: Int32? public var activityTimestamp: Double?
public var muteState: Participant.MuteState? public var muteState: Participant.MuteState?
public var isRemoved: Bool public var isRemoved: Bool
} }
@ -606,9 +606,13 @@ public final class GroupCallParticipantsContext {
private let id: Int64 private let id: Int64
private let accessHash: Int64 private let accessHash: Int64
private var hasReceivedSpeackingParticipantsReport: Bool = false
private var stateValue: InternalState { private var stateValue: InternalState {
didSet { didSet {
self.statePromise.set(self.stateValue) if self.stateValue != oldValue {
self.statePromise.set(self.stateValue)
}
} }
} }
private let statePromise: ValuePromise<InternalState> private let statePromise: ValuePromise<InternalState>
@ -682,52 +686,56 @@ public final class GroupCallParticipantsContext {
strongSelf.numberOfActiveSpeakersValue = activities.count strongSelf.numberOfActiveSpeakersValue = activities.count
var updatedParticipants = strongSelf.stateValue.state.participants if !strongSelf.hasReceivedSpeackingParticipantsReport {
var indexMap: [PeerId: Int] = [:] var updatedParticipants = strongSelf.stateValue.state.participants
for i in 0 ..< updatedParticipants.count { var indexMap: [PeerId: Int] = [:]
indexMap[updatedParticipants[i].peer.id] = i for i in 0 ..< updatedParticipants.count {
} indexMap[updatedParticipants[i].peer.id] = i
var updated = false }
var updated = false
for (activityPeerId, activity) in activities {
if case let .speakingInGroupCall(timestamp) = activity { for (activityPeerId, activity) in activities {
if let index = indexMap[activityPeerId] { if case let .speakingInGroupCall(intTimestamp) = activity {
if let activityTimestamp = updatedParticipants[index].activityTimestamp { let timestamp = Double(intTimestamp)
if activityTimestamp < timestamp {
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 updatedParticipants[index].activityTimestamp = timestamp
updated = true 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( if updated {
state: State( updatedParticipants.sort()
participants: updatedParticipants, for i in 0 ..< updatedParticipants.count {
nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset, if updatedParticipants[i].peer.id == strongSelf.account.peerId {
adminIds: strongSelf.stateValue.state.adminIds, let member = updatedParticipants[i]
isCreator: strongSelf.stateValue.state.isCreator, updatedParticipants.remove(at: i)
defaultParticipantsAreMuted: strongSelf.stateValue.state.defaultParticipantsAreMuted, updatedParticipants.insert(member, at: 0)
totalCount: strongSelf.stateValue.state.totalCount, break
version: strongSelf.stateValue.state.version }
), }
overlayState: strongSelf.stateValue.overlayState
) 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 +763,65 @@ 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
}
}
}
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
)
}
}
private func beginProcessingUpdatesIfNeeded() { private func beginProcessingUpdatesIfNeeded() {
if self.isProcessingUpdate { if self.isProcessingUpdate {
return return
@ -824,7 +891,7 @@ public final class GroupCallParticipantsContext {
assertionFailure() assertionFailure()
continue continue
} }
var previousActivityTimestamp: Int32? var previousActivityTimestamp: Double?
if let index = updatedParticipants.firstIndex(where: { $0.peer.id == participantUpdate.peerId }) { if let index = updatedParticipants.firstIndex(where: { $0.peer.id == participantUpdate.peerId }) {
previousActivityTimestamp = updatedParticipants[index].activityTimestamp previousActivityTimestamp = updatedParticipants[index].activityTimestamp
updatedParticipants.remove(at: index) updatedParticipants.remove(at: index)
@ -832,7 +899,7 @@ public final class GroupCallParticipantsContext {
updatedTotalCount += 1 updatedTotalCount += 1
} }
var activityTimestamp: Int32? var activityTimestamp: Double?
if let previousActivityTimestamp = previousActivityTimestamp, let updatedActivityTimestamp = participantUpdate.activityTimestamp { if let previousActivityTimestamp = previousActivityTimestamp, let updatedActivityTimestamp = participantUpdate.activityTimestamp {
activityTimestamp = max(updatedActivityTimestamp, previousActivityTimestamp) activityTimestamp = max(updatedActivityTimestamp, previousActivityTimestamp)
} else { } else {
@ -1014,7 +1081,7 @@ extension GroupCallParticipantsContext.Update.StateUpdate {
peerId: peerId, peerId: peerId,
ssrc: ssrc, ssrc: ssrc,
joinTimestamp: date, joinTimestamp: date,
activityTimestamp: activeDate, activityTimestamp: activeDate.flatMap(Double.init),
muteState: muteState, muteState: muteState,
isRemoved: isRemoved isRemoved: isRemoved
)) ))

View File

@ -640,6 +640,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
if let call = call { if let call = call {
mainWindow.hostView.containerView.endEditing(true) mainWindow.hostView.containerView.endEditing(true)
let groupCallController = VoiceChatController(sharedContext: strongSelf, accountContext: call.accountContext, call: call) let groupCallController = VoiceChatController(sharedContext: strongSelf, accountContext: call.accountContext, call: call)
groupCallController.parentNavigationController = mainWindow.viewController as? NavigationController
strongSelf.groupCallController = groupCallController strongSelf.groupCallController = groupCallController
strongSelf.mainWindow?.present(groupCallController, on: .calls) strongSelf.mainWindow?.present(groupCallController, on: .calls)
strongSelf.hasOngoingCall.set(true) strongSelf.hasOngoingCall.set(true)