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

This commit is contained in:
Ilya Laktyushin 2021-03-15 22:06:47 +04:00
commit 080a8b780a
8 changed files with 64 additions and 21 deletions

Binary file not shown.

View File

@ -286,6 +286,11 @@ public final class PresentationGroupCallMemberEvent {
} }
} }
public enum PresentationGroupCallTone {
case unmuted
case recordingStarted
}
public protocol PresentationGroupCall: class { public protocol PresentationGroupCall: class {
var account: Account { get } var account: Account { get }
var accountContext: AccountContext { get } var accountContext: AccountContext { get }
@ -321,6 +326,8 @@ public protocol PresentationGroupCall: class {
func setVolume(peerId: PeerId, volume: Int32, sync: Bool) func setVolume(peerId: PeerId, volume: Int32, sync: Bool)
func setFullSizeVideo(peerId: PeerId?) func setFullSizeVideo(peerId: PeerId?)
func setCurrentAudioOutput(_ output: AudioSessionOutput) func setCurrentAudioOutput(_ output: AudioSessionOutput)
func playTone(_ tone: PresentationGroupCallTone)
func updateMuteState(peerId: PeerId, isMuted: Bool) -> GroupCallParticipantsContext.Participant.MuteState? func updateMuteState(peerId: PeerId, isMuted: Bool) -> GroupCallParticipantsContext.Participant.MuteState?
func setShouldBeRecording(_ shouldBeRecording: Bool, title: String?) func setShouldBeRecording(_ shouldBeRecording: Bool, title: String?)

View File

@ -413,7 +413,7 @@ public final class ManagedAudioSession {
}, deactivate: deactivate) }, deactivate: deactivate)
} }
public func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, manualActivate: @escaping (ManagedAudioSessionControl) -> Void, deactivate: @escaping () -> Signal<Void, NoError>, headsetConnectionStatusChanged: @escaping (Bool) -> Void = { _ in }, availableOutputsChanged: @escaping ([AudioSessionOutput], AudioSessionOutput?) -> Void = { _, _ in }) -> Disposable { public func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, activateImmediately: Bool = false, manualActivate: @escaping (ManagedAudioSessionControl) -> Void, deactivate: @escaping () -> Signal<Void, NoError>, headsetConnectionStatusChanged: @escaping (Bool) -> Void = { _ in }, availableOutputsChanged: @escaping ([AudioSessionOutput], AudioSessionOutput?) -> Void = { _, _ in }) -> Disposable {
let id = OSAtomicIncrement32(&self.nextId) let id = OSAtomicIncrement32(&self.nextId)
let queue = self.queue let queue = self.queue
queue.async { queue.async {
@ -422,7 +422,7 @@ public final class ManagedAudioSession {
if let strongSelf = self { if let strongSelf = self {
for holder in strongSelf.holders { for holder in strongSelf.holders {
if holder.id == id && holder.active { if holder.id == id && holder.active {
strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode, activateNow: false) strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode, activateNow: activateImmediately)
break break
} }
} }

View File

@ -74,7 +74,7 @@ private func loadToneData(name: String, addSilenceDuration: Double = 0.0) -> Dat
return data return data
} }
enum PresentationCallTone { enum PresentationCallTone: Equatable {
case ringing case ringing
case connecting case connecting
case busy case busy
@ -83,6 +83,7 @@ enum PresentationCallTone {
case groupJoined case groupJoined
case groupLeft case groupLeft
case groupConnecting case groupConnecting
case custom(name: String, loopCount: Int?)
var loopCount: Int? { var loopCount: Int? {
switch self { switch self {
@ -96,6 +97,8 @@ enum PresentationCallTone {
return 1 return 1
case .groupConnecting: case .groupConnecting:
return nil return nil
case let .custom(_, loopCount):
return loopCount
default: default:
return nil return nil
} }
@ -120,5 +123,7 @@ func presentationCallToneData(_ tone: PresentationCallTone) -> Data? {
return loadToneData(name: "voip_group_left.mp3") return loadToneData(name: "voip_group_left.mp3")
case .groupConnecting: case .groupConnecting:
return loadToneData(name: "voip_group_connecting.mp3", addSilenceDuration: 2.0) return loadToneData(name: "voip_group_connecting.mp3", addSilenceDuration: 2.0)
case let .custom(name, _):
return loadToneData(name: name)
} }
} }

View File

@ -100,7 +100,8 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
myPeerId: account.peerId, myPeerId: account.peerId,
id: call.id, id: call.id,
accessHash: call.accessHash, accessHash: call.accessHash,
state: state state: state,
previousServiceState: nil
) )
strongSelf.participantsContext = context strongSelf.participantsContext = context
@ -581,7 +582,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.audioOutputStatePromise.set(.single(([], .speaker))) self.audioOutputStatePromise.set(.single(([], .speaker)))
} }
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, activateImmediately: true, manualActivate: { [weak self] control in
Queue.mainQueue().async { Queue.mainQueue().async {
if let strongSelf = self { if let strongSelf = self {
strongSelf.updateSessionState(internalState: strongSelf.internalState, audioSessionControl: control) strongSelf.updateSessionState(internalState: strongSelf.internalState, audioSessionControl: control)
@ -842,7 +843,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
} }
if let sourceContext = sourceContext, let initialState = sourceContext.immediateState { if let sourceContext = sourceContext, let initialState = sourceContext.immediateState {
let temporaryParticipantsContext = GroupCallParticipantsContext(account: self.account, peerId: self.peerId, myPeerId: myPeerId, id: sourceContext.id, accessHash: sourceContext.accessHash, state: initialState) let temporaryParticipantsContext = GroupCallParticipantsContext(account: self.account, peerId: self.peerId, myPeerId: myPeerId, id: sourceContext.id, accessHash: sourceContext.accessHash, state: initialState, previousServiceState: sourceContext.serviceState)
self.temporaryParticipantsContext = temporaryParticipantsContext self.temporaryParticipantsContext = temporaryParticipantsContext
self.participantsContextStateDisposable.set((combineLatest(queue: .mainQueue(), self.participantsContextStateDisposable.set((combineLatest(queue: .mainQueue(),
myPeer, myPeer,
@ -1364,8 +1365,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
let myPeerId = self.joinAsPeerId let myPeerId = self.joinAsPeerId
var initialState = initialState var initialState = initialState
var serviceState: GroupCallParticipantsContext.ServiceState?
if let participantsContext = self.participantsContext, let immediateState = participantsContext.immediateState { if let participantsContext = self.participantsContext, let immediateState = participantsContext.immediateState {
initialState.mergeActivity(from: immediateState, myPeerId: myPeerId, previousMyPeerId: self.ignorePreviousJoinAsPeerId?.0) initialState.mergeActivity(from: immediateState, myPeerId: myPeerId, previousMyPeerId: self.ignorePreviousJoinAsPeerId?.0)
serviceState = participantsContext.serviceState
} }
let participantsContext = GroupCallParticipantsContext( let participantsContext = GroupCallParticipantsContext(
@ -1374,7 +1377,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
myPeerId: self.joinAsPeerId, myPeerId: self.joinAsPeerId,
id: callInfo.id, id: callInfo.id,
accessHash: callInfo.accessHash, accessHash: callInfo.accessHash,
state: initialState state: initialState,
previousServiceState: serviceState
) )
self.temporaryParticipantsContext = nil self.temporaryParticipantsContext = nil
self.participantsContext = participantsContext self.participantsContext = participantsContext
@ -1397,6 +1401,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.participantsContext?.updateAdminIds(adminIds)
var topParticipants: [GroupCallParticipantsContext.Participant] = [] var topParticipants: [GroupCallParticipantsContext.Participant] = []
@ -1482,6 +1488,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
if participant.peer.id == strongSelf.joinAsPeerId { if participant.peer.id == strongSelf.joinAsPeerId {
var filteredMuteState = participant.muteState
if isReconnectingAsSpeaker || strongSelf.currentConnectionMode != .rtc {
filteredMuteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: false, mutedByYou: false)
participant.muteState = filteredMuteState
}
let previousRaisedHand = strongSelf.stateValue.raisedHand let previousRaisedHand = strongSelf.stateValue.raisedHand
if !(strongSelf.stateValue.muteState?.canUnmute ?? false) { if !(strongSelf.stateValue.muteState?.canUnmute ?? false) {
strongSelf.stateValue.raisedHand = participant.raiseHandRating != nil strongSelf.stateValue.raisedHand = participant.raiseHandRating != nil
@ -1512,15 +1524,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
text = presentationData.strings.VoiceChat_YouCanNowSpeak text = presentationData.strings.VoiceChat_YouCanNowSpeak
} }
strongSelf.accountContext.sharedContext.mainWindow?.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: text), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), on: .root, blockInteraction: false, completion: {}) strongSelf.accountContext.sharedContext.mainWindow?.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: text), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), on: .root, blockInteraction: false, completion: {})
strongSelf.playTone(.unmuted)
} }
}) })
} }
var filteredMuteState = participant.muteState
if isReconnectingAsSpeaker || strongSelf.currentConnectionMode != .rtc {
filteredMuteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: false, mutedByYou: false)
participant.muteState = filteredMuteState
}
if let muteState = filteredMuteState { if let muteState = filteredMuteState {
if muteState.canUnmute { if muteState.canUnmute {
@ -1733,6 +1740,20 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.toneRenderer?.setAudioSessionActive(value) self.toneRenderer?.setAudioSessionActive(value)
} }
} }
public func playTone(_ tone: PresentationGroupCallTone) {
let name: String
switch tone {
case .unmuted:
name = "voip_group_unmuted.mp3"
case .recordingStarted:
name = "voip_group_recording_started.mp3"
}
let toneRenderer = PresentationCallToneRenderer(tone: .custom(name: name, loopCount: 1))
self.toneRenderer = toneRenderer
toneRenderer.setAudioSessionActive(self.isAudioSessionActive)
}
private func markAsCanBeRemoved() { private func markAsCanBeRemoved() {
if self.markedAsCanBeRemoved { if self.markedAsCanBeRemoved {

View File

@ -1880,6 +1880,7 @@ public final class VoiceChatController: ViewController {
strongSelf.call.setShouldBeRecording(true, title: title) strongSelf.call.setShouldBeRecording(true, title: title)
strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: strongSelf.presentationData.strings.VoiceChat_RecordingStarted), action: { _ in return false }) strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: strongSelf.presentationData.strings.VoiceChat_RecordingStarted), action: { _ in return false })
strongSelf.call.playTone(.recordingStarted)
} }
}) })
self?.controller?.present(controller, in: .window(.root)) self?.controller?.present(controller, in: .window(.root))

View File

@ -960,9 +960,6 @@ public final class GroupCallParticipantsContext {
let accountPeerId = self.account.peerId let accountPeerId = self.account.peerId
return self.statePromise.get() return self.statePromise.get()
|> map { state -> State in |> map { state -> State in
if state.overlayState.isEmpty {
return state.state
}
var publicState = state.state var publicState = state.state
var sortAgain = false var sortAgain = false
let canSeeHands = state.state.isCreator || state.state.adminIds.contains(accountPeerId) let canSeeHands = state.state.isCreator || state.state.adminIds.contains(accountPeerId)
@ -1015,20 +1012,26 @@ public final class GroupCallParticipantsContext {
private var isLoadingMore: Bool = false private var isLoadingMore: Bool = false
private var shouldResetStateFromServer: Bool = false private var shouldResetStateFromServer: Bool = false
private var missingSsrcs = Set<UInt32>() private var missingSsrcs = Set<UInt32>()
private var nextActivityRank: Int = 0
private var activityRankResetTimer: SwiftSignalKit.Timer? private var activityRankResetTimer: SwiftSignalKit.Timer?
private let updateDefaultMuteDisposable = MetaDisposable() private let updateDefaultMuteDisposable = MetaDisposable()
private let updateShouldBeRecordingDisposable = MetaDisposable() private let updateShouldBeRecordingDisposable = MetaDisposable()
public struct ServiceState {
fileprivate var nextActivityRank: Int = 0
}
public private(set) var serviceState: ServiceState
public init(account: Account, peerId: PeerId, myPeerId: PeerId, id: Int64, accessHash: Int64, state: State) { public init(account: Account, peerId: PeerId, myPeerId: PeerId, id: Int64, accessHash: Int64, state: State, previousServiceState: ServiceState?) {
self.account = account self.account = account
self.myPeerId = myPeerId self.myPeerId = myPeerId
self.id = id self.id = id
self.accessHash = accessHash self.accessHash = accessHash
self.stateValue = InternalState(state: state, overlayState: OverlayState()) self.stateValue = InternalState(state: state, overlayState: OverlayState())
self.statePromise = ValuePromise<InternalState>(self.stateValue) self.statePromise = ValuePromise<InternalState>(self.stateValue)
self.serviceState = previousServiceState ?? ServiceState()
self.updatesDisposable.set((self.account.stateManager.groupCallParticipantUpdates self.updatesDisposable.set((self.account.stateManager.groupCallParticipantUpdates
|> deliverOnMainQueue).start(next: { [weak self] updates in |> deliverOnMainQueue).start(next: { [weak self] updates in
@ -1167,10 +1170,16 @@ public final class GroupCallParticipantsContext {
} }
private func takeNextActivityRank() -> Int { private func takeNextActivityRank() -> Int {
let value = self.nextActivityRank let value = self.serviceState.nextActivityRank
self.nextActivityRank += 1 self.serviceState.nextActivityRank += 1
return value return value
} }
public func updateAdminIds(_ adminIds: Set<PeerId>) {
if self.stateValue.state.adminIds != adminIds {
self.stateValue.state.adminIds = adminIds
}
}
public func reportSpeakingParticipants(ids: [PeerId: UInt32]) { public func reportSpeakingParticipants(ids: [PeerId: UInt32]) {
if !ids.isEmpty { if !ids.isEmpty {