mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
080a8b780a
BIN
Telegram/Telegram-iOS/Resources/voip_group_recording_started.mp3
Normal file
BIN
Telegram/Telegram-iOS/Resources/voip_group_recording_started.mp3
Normal file
Binary file not shown.
BIN
Telegram/Telegram-iOS/Resources/voip_group_unmuted.mp3
Normal file
BIN
Telegram/Telegram-iOS/Resources/voip_group_unmuted.mp3
Normal file
Binary file not shown.
@ -286,6 +286,11 @@ public final class PresentationGroupCallMemberEvent {
|
||||
}
|
||||
}
|
||||
|
||||
public enum PresentationGroupCallTone {
|
||||
case unmuted
|
||||
case recordingStarted
|
||||
}
|
||||
|
||||
public protocol PresentationGroupCall: class {
|
||||
var account: Account { get }
|
||||
var accountContext: AccountContext { get }
|
||||
@ -321,6 +326,8 @@ public protocol PresentationGroupCall: class {
|
||||
func setVolume(peerId: PeerId, volume: Int32, sync: Bool)
|
||||
func setFullSizeVideo(peerId: PeerId?)
|
||||
func setCurrentAudioOutput(_ output: AudioSessionOutput)
|
||||
|
||||
func playTone(_ tone: PresentationGroupCallTone)
|
||||
|
||||
func updateMuteState(peerId: PeerId, isMuted: Bool) -> GroupCallParticipantsContext.Participant.MuteState?
|
||||
func setShouldBeRecording(_ shouldBeRecording: Bool, title: String?)
|
||||
|
@ -413,7 +413,7 @@ public final class ManagedAudioSession {
|
||||
}, 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 queue = self.queue
|
||||
queue.async {
|
||||
@ -422,7 +422,7 @@ public final class ManagedAudioSession {
|
||||
if let strongSelf = self {
|
||||
for holder in strongSelf.holders {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ private func loadToneData(name: String, addSilenceDuration: Double = 0.0) -> Dat
|
||||
return data
|
||||
}
|
||||
|
||||
enum PresentationCallTone {
|
||||
enum PresentationCallTone: Equatable {
|
||||
case ringing
|
||||
case connecting
|
||||
case busy
|
||||
@ -83,6 +83,7 @@ enum PresentationCallTone {
|
||||
case groupJoined
|
||||
case groupLeft
|
||||
case groupConnecting
|
||||
case custom(name: String, loopCount: Int?)
|
||||
|
||||
var loopCount: Int? {
|
||||
switch self {
|
||||
@ -96,6 +97,8 @@ enum PresentationCallTone {
|
||||
return 1
|
||||
case .groupConnecting:
|
||||
return nil
|
||||
case let .custom(_, loopCount):
|
||||
return loopCount
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@ -120,5 +123,7 @@ func presentationCallToneData(_ tone: PresentationCallTone) -> Data? {
|
||||
return loadToneData(name: "voip_group_left.mp3")
|
||||
case .groupConnecting:
|
||||
return loadToneData(name: "voip_group_connecting.mp3", addSilenceDuration: 2.0)
|
||||
case let .custom(name, _):
|
||||
return loadToneData(name: name)
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
myPeerId: account.peerId,
|
||||
id: call.id,
|
||||
accessHash: call.accessHash,
|
||||
state: state
|
||||
state: state,
|
||||
previousServiceState: nil
|
||||
)
|
||||
|
||||
strongSelf.participantsContext = context
|
||||
@ -581,7 +582,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
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 {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSessionState(internalState: strongSelf.internalState, audioSessionControl: control)
|
||||
@ -842,7 +843,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
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.participantsContextStateDisposable.set((combineLatest(queue: .mainQueue(),
|
||||
myPeer,
|
||||
@ -1364,8 +1365,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
let myPeerId = self.joinAsPeerId
|
||||
|
||||
var initialState = initialState
|
||||
var serviceState: GroupCallParticipantsContext.ServiceState?
|
||||
if let participantsContext = self.participantsContext, let immediateState = participantsContext.immediateState {
|
||||
initialState.mergeActivity(from: immediateState, myPeerId: myPeerId, previousMyPeerId: self.ignorePreviousJoinAsPeerId?.0)
|
||||
serviceState = participantsContext.serviceState
|
||||
}
|
||||
|
||||
let participantsContext = GroupCallParticipantsContext(
|
||||
@ -1374,7 +1377,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
myPeerId: self.joinAsPeerId,
|
||||
id: callInfo.id,
|
||||
accessHash: callInfo.accessHash,
|
||||
state: initialState
|
||||
state: initialState,
|
||||
previousServiceState: serviceState
|
||||
)
|
||||
self.temporaryParticipantsContext = nil
|
||||
self.participantsContext = participantsContext
|
||||
@ -1397,6 +1401,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.participantsContext?.updateAdminIds(adminIds)
|
||||
|
||||
var topParticipants: [GroupCallParticipantsContext.Participant] = []
|
||||
|
||||
@ -1482,6 +1488,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|
||||
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
|
||||
if !(strongSelf.stateValue.muteState?.canUnmute ?? false) {
|
||||
strongSelf.stateValue.raisedHand = participant.raiseHandRating != nil
|
||||
@ -1512,15 +1524,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
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.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 muteState.canUnmute {
|
||||
@ -1733,6 +1740,20 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
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() {
|
||||
if self.markedAsCanBeRemoved {
|
||||
|
@ -1880,6 +1880,7 @@ public final class VoiceChatController: ViewController {
|
||||
strongSelf.call.setShouldBeRecording(true, title: title)
|
||||
|
||||
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))
|
||||
|
@ -960,9 +960,6 @@ public final class GroupCallParticipantsContext {
|
||||
let accountPeerId = self.account.peerId
|
||||
return self.statePromise.get()
|
||||
|> map { state -> State in
|
||||
if state.overlayState.isEmpty {
|
||||
return state.state
|
||||
}
|
||||
var publicState = state.state
|
||||
var sortAgain = false
|
||||
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 shouldResetStateFromServer: Bool = false
|
||||
private var missingSsrcs = Set<UInt32>()
|
||||
|
||||
private var nextActivityRank: Int = 0
|
||||
|
||||
private var activityRankResetTimer: SwiftSignalKit.Timer?
|
||||
|
||||
private let updateDefaultMuteDisposable = 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.myPeerId = myPeerId
|
||||
self.id = id
|
||||
self.accessHash = accessHash
|
||||
self.stateValue = InternalState(state: state, overlayState: OverlayState())
|
||||
self.statePromise = ValuePromise<InternalState>(self.stateValue)
|
||||
self.serviceState = previousServiceState ?? ServiceState()
|
||||
|
||||
self.updatesDisposable.set((self.account.stateManager.groupCallParticipantUpdates
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updates in
|
||||
@ -1167,10 +1170,16 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
private func takeNextActivityRank() -> Int {
|
||||
let value = self.nextActivityRank
|
||||
self.nextActivityRank += 1
|
||||
let value = self.serviceState.nextActivityRank
|
||||
self.serviceState.nextActivityRank += 1
|
||||
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]) {
|
||||
if !ids.isEmpty {
|
||||
|
Loading…
x
Reference in New Issue
Block a user