[WIP] Conference calls

This commit is contained in:
Isaac 2025-02-07 15:22:47 +04:00
parent 3e74304640
commit 962ca74101
15 changed files with 395 additions and 155 deletions

View file

@ -414,6 +414,7 @@ public protocol PresentationGroupCall: AnyObject {
var isStream: Bool { get }
var isConference: Bool { get }
var conferenceSource: CallSessionInternalId? { get }
var encryptionKeyValue: Data? { get }
var audioOutputState: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> { get }

View file

@ -236,7 +236,7 @@ open class ViewControllerComponentContainer: ViewController {
private let context: AccountContext
private var theme: Theme
private let component: AnyComponent<ViewControllerComponentContainer.Environment>
public private(set) var component: AnyComponent<ViewControllerComponentContainer.Environment>
private var presentationDataDisposable: Disposable?
public private(set) var validLayout: ContainerViewLayout?
@ -387,6 +387,7 @@ open class ViewControllerComponentContainer: ViewController {
}
public func updateComponent(component: AnyComponent<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) {
self.component = component
self.node.updateComponent(component: component, transition: transition)
}
}

View file

@ -811,7 +811,11 @@ open class NavigationController: UINavigationController, ContainableController,
modalContainer.update(layout: modalContainer.isFlat ? globalOverlayLayout : layout, controllers: navigationLayout.modal[i].controllers, coveredByModalTransition: effectiveModalTransition, transition: containerTransition)
if modalContainer.supernode == nil && modalContainer.isReady {
if let previousModalContainer = previousModalContainer {
if let previousModalContainer {
assert(previousModalContainer.supernode != nil)
}
if let previousModalContainer, previousModalContainer.supernode != nil {
self.displayNode.insertSubnode(modalContainer, belowSubnode: previousModalContainer)
} else if let inCallStatusBar = self.inCallStatusBar {
self.displayNode.insertSubnode(modalContainer, belowSubnode: inCallStatusBar)
@ -1601,6 +1605,16 @@ open class NavigationController: UINavigationController, ContainableController,
}
public func setViewControllers(_ viewControllers: [UIViewController], animated: Bool, completion: @escaping () -> Void) {
let requestedViewControllers = viewControllers
var viewControllers: [UIViewController] = []
for controller in requestedViewControllers {
if !viewControllers.contains(where: { $0 === controller }) {
viewControllers.append(controller)
} else {
assert(true)
}
}
for i in 0 ..< viewControllers.count {
guard let controller = viewControllers[i] as? ViewController else {
continue

View file

@ -94,6 +94,10 @@ public final class CallKitIntegration {
public func applyVoiceChatOutputMode(outputMode: AudioSessionOutputMode) {
sharedProviderDelegate?.applyVoiceChatOutputMode(outputMode: outputMode)
}
public func updateCallIsConference(uuid: UUID) {
sharedProviderDelegate?.updateCallIsConference(uuid: uuid)
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
@ -276,6 +280,20 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.provider.reportOutgoingCall(with: uuid, connectedAt: date)
}
func updateCallIsConference(uuid: UUID) {
let update = CXCallUpdate()
let handle = CXHandle(type: .generic, value: "\(uuid)")
update.remoteHandle = handle
//TODO:localize
update.localizedCallerName = "Group Call"
update.supportsHolding = false
update.supportsGrouping = false
update.supportsUngrouping = false
update.supportsDTMF = false
self.provider.reportCall(with: uuid, updated: update)
}
func providerDidReset(_ provider: CXProvider) {
Logger.shared.log("CallKitIntegration", "providerDidReset")

View file

@ -1038,6 +1038,9 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
fatalError("init(coder:) has not been implemented")
}
public func updateCall(call: VideoChatCall) {
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

View file

@ -325,6 +325,8 @@ public final class PresentationCallImpl: PresentationCall {
private var localVideoEndpointId: String?
private var remoteVideoEndpointId: String?
private var isMovedToConference: Bool = false
init(
context: AccountContext,
audioSession: ManagedAudioSession,
@ -541,6 +543,89 @@ public final class PresentationCallImpl: PresentationCall {
}
}
public func resetAsMovedToConference() {
if self.isMovedToConference {
return
}
self.isMovedToConference = true
self.sharedAudioContext = nil
self.sessionState = nil
self.callContextState = nil
self.ongoingContext = nil
self.ongoingContextStateDisposable?.dispose()
self.ongoingContextStateDisposable = nil
self.ongoingContextIsFailedDisposable?.dispose()
self.ongoingContextIsFailedDisposable = nil
self.ongoingContextIsDroppedDisposable?.dispose()
self.ongoingContextIsDroppedDisposable = nil
self.didDropCall = false
self.requestedVideoAspect = nil
self.reception = nil
self.receptionDisposable?.dispose()
self.receptionDisposable = nil
self.audioLevelDisposable?.dispose()
self.audioLevelDisposable = nil
self.reportedIncomingCall = false
self.batteryLevelDisposable?.dispose()
self.batteryLevelDisposable = nil
self.callWasActive = false
self.shouldPresentCallRating = false
self.previousVideoState = nil
self.previousRemoteVideoState = nil
self.previousRemoteAudioState = nil
self.previousRemoteBatteryLevel = nil
self.sessionStateDisposable?.dispose()
self.sessionStateDisposable = nil
self.activeTimestamp = nil
self.audioSessionControl = nil
self.audioSessionDisposable?.dispose()
self.audioSessionDisposable = nil
self.audioSessionShouldBeActiveDisposable?.dispose()
self.audioSessionShouldBeActiveDisposable = nil
self.audioSessionActiveDisposable?.dispose()
self.audioSessionActiveDisposable = nil
self.isAudioSessionActive = false
self.currentTone = nil
self.dropCallKitCallTimer?.invalidate()
self.dropCallKitCallTimer = nil
self.droppedCall = true
self.videoCapturer = nil
self.screencastBufferServerContext = nil
self.screencastCapturer = nil
self.isScreencastActive = false
if let proximityManagerIndex = self.proximityManagerIndex {
DeviceProximityManager.shared().remove(proximityManagerIndex)
self.proximityManagerIndex = nil
}
self.screencastFramesDisposable.set(nil)
self.screencastAudioDataDisposable.set(nil)
self.screencastStateDisposable.set(nil)
self.conferenceCallImpl = nil
self.conferenceCallDisposable?.dispose()
self.conferenceCallDisposable = nil
self.upgradedToConferenceCompletions.removeAll()
self.waitForConferenceCallReadyDisposable?.dispose()
self.waitForConferenceCallReadyDisposable = nil
self.pendingInviteToConferencePeerIds.removeAll()
self.localVideoEndpointId = nil
self.remoteVideoEndpointId = nil
self.callKitIntegration?.updateCallIsConference(uuid: self.internalId)
}
func internal_markAsCanBeRemoved() {
if !self.didSetCanBeRemoved {
self.didSetCanBeRemoved = true
@ -549,6 +634,9 @@ public final class PresentationCallImpl: PresentationCall {
}
private func updateSessionState(sessionState: CallSession, callContextState: OngoingCallContextState?, reception: Int32?, audioSessionControl: ManagedAudioSessionControl?) {
if self.isMovedToConference {
return
}
self.reception = reception
if let ongoingContext = self.ongoingContext {
@ -730,11 +818,11 @@ public final class PresentationCallImpl: PresentationCall {
presentationState = PresentationCallState(state: .terminated(id, reason, self.callWasActive && (options.contains(.reportRating) || self.shouldPresentCallRating)), videoState: mappedVideoState, remoteVideoState: .inactive, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
case let .requesting(ringing, _):
presentationState = PresentationCallState(state: .requesting(ringing), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
case let .active(_, _, keyVisualHash, _, _, _, _, _, _), let .switchedToConference(_, keyVisualHash, _):
case let .active(_, _, keyVisualHash, _, _, _, _, _, _, _), let .switchedToConference(_, keyVisualHash, _):
self.callWasActive = true
var isConference = false
if case let .active(_, _, _, _, _, _, _, _, conferenceCall) = sessionState.state {
if case let .active(_, _, _, _, _, _, _, _, conferenceCall, _) = sessionState.state {
isConference = conferenceCall != nil
} else if case .switchedToConference = sessionState.state {
isConference = true
@ -774,8 +862,8 @@ public final class PresentationCallImpl: PresentationCall {
var conferenceCallData: (key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)?
var conferenceFromCallId: CallId?
switch sessionState.state {
case let .active(id, key, keyVisualHash, _, _, _, _, _, conferenceCall):
if let conferenceCall {
case let .active(id, key, keyVisualHash, _, _, _, _, _, conferenceCall, isIncomingConference):
if let conferenceCall, !isIncomingConference {
conferenceFromCallId = id
conferenceCallData = (key, keyVisualHash, conferenceCall)
}
@ -789,6 +877,10 @@ public final class PresentationCallImpl: PresentationCall {
if self.conferenceCallDisposable == nil {
self.conferenceCallDisposable = EmptyDisposable
#if DEBUG
print("Switching to conference call with encryption key: \(key.base64EncodedString())")
#endif
let conferenceCall = PresentationGroupCallImpl(
accountContext: self.context,
audioSession: self.audioSession,
@ -810,6 +902,7 @@ public final class PresentationCallImpl: PresentationCall {
isStream: false,
encryptionKey: (key, 1),
conferenceFromCallId: conferenceFromCallId,
conferenceSourceId: self.internalId,
isConference: true,
sharedAudioContext: self.sharedAudioContext
)
@ -917,7 +1010,7 @@ public final class PresentationCallImpl: PresentationCall {
if let _ = audioSessionControl {
self.audioSessionShouldBeActive.set(true)
}
case let .active(id, key, _, connections, maxLayer, version, customParameters, allowsP2P, _):
case let .active(id, key, _, connections, maxLayer, version, customParameters, allowsP2P, _, _):
self.audioSessionShouldBeActive.set(true)
if conferenceCallData != nil {
@ -1044,7 +1137,7 @@ public final class PresentationCallImpl: PresentationCall {
}
var isConference = false
if case let .active(_, _, _, _, _, _, _, _, conferenceCall) = sessionState.state {
if case let .active(_, _, _, _, _, _, _, _, conferenceCall, _) = sessionState.state {
isConference = conferenceCall != nil
} else if case .switchedToConference = sessionState.state {
isConference = true
@ -1072,59 +1165,10 @@ public final class PresentationCallImpl: PresentationCall {
}
}
private func requestMediaChannelDescriptions(ssrcs: Set<UInt32>, completion: @escaping ([OngoingGroupCallContext.MediaChannelDescription]) -> Void) -> Disposable {
/*func extractMediaChannelDescriptions(remainingSsrcs: inout Set<UInt32>, participants: [GroupCallParticipantsContext.Participant], into result: inout [OngoingGroupCallContext.MediaChannelDescription]) {
for participant in participants {
guard let audioSsrc = participant.ssrc else {
continue
}
if remainingSsrcs.contains(audioSsrc) {
remainingSsrcs.remove(audioSsrc)
result.append(OngoingGroupCallContext.MediaChannelDescription(
kind: .audio,
audioSsrc: audioSsrc,
videoDescription: nil
))
}
if let screencastSsrc = participant.presentationDescription?.audioSsrc {
if remainingSsrcs.contains(screencastSsrc) {
remainingSsrcs.remove(screencastSsrc)
result.append(OngoingGroupCallContext.MediaChannelDescription(
kind: .audio,
audioSsrc: screencastSsrc,
videoDescription: nil
))
}
}
}
}
var remainingSsrcs = ssrcs
var result: [OngoingGroupCallContext.MediaChannelDescription] = []
if let membersValue = self.membersValue {
extractMediaChannelDescriptions(remainingSsrcs: &remainingSsrcs, participants: membersValue.participants, into: &result)
}
if !remainingSsrcs.isEmpty, let callInfo = self.internalState.callInfo {
return (self.accountContext.engine.calls.getGroupCallParticipants(callId: callInfo.id, accessHash: callInfo.accessHash, offset: "", ssrcs: Array(remainingSsrcs), limit: 100, sortAscending: callInfo.sortAscending)
|> deliverOnMainQueue).start(next: { state in
extractMediaChannelDescriptions(remainingSsrcs: &remainingSsrcs, participants: state.participants, into: &result)
completion(result)
})
} else {
completion(result)
return EmptyDisposable
}*/
return EmptyDisposable
}
private func updateTone(_ state: PresentationCallState, callContextState: OngoingCallContextState?, previous: CallSession?) {
if self.isMovedToConference {
return
}
var tone: PresentationCallTone?
if let callContextState = callContextState, case .reconnecting = callContextState.state {
if !self.isVideo {
@ -1174,16 +1218,25 @@ public final class PresentationCallImpl: PresentationCall {
}
private func updateIsAudioSessionActive(_ value: Bool) {
if self.isMovedToConference {
return
}
if self.isAudioSessionActive != value {
self.isAudioSessionActive = value
}
}
public func answer() {
if self.isMovedToConference {
return
}
self.answer(fromCallKitAction: false)
}
func answer(fromCallKitAction: Bool) {
if self.isMovedToConference {
return
}
let (presentationData, present, openSettings) = self.getDeviceAccessData()
DeviceAccess.authorizeAccess(to: .microphone(.voiceCall), presentationData: presentationData, present: { c, a in
@ -1234,6 +1287,9 @@ public final class PresentationCallImpl: PresentationCall {
}
public func hangUp() -> Signal<Bool, NoError> {
if self.isMovedToConference {
return .single(true)
}
let debugLogValue = Promise<String?>()
self.callSessionManager.drop(internalId: self.internalId, reason: .hangUp, debugLog: debugLogValue.get())
self.ongoingContext?.stop(debugLogValue: debugLogValue)
@ -1242,22 +1298,34 @@ public final class PresentationCallImpl: PresentationCall {
}
public func rejectBusy() {
if self.isMovedToConference {
return
}
self.callSessionManager.drop(internalId: self.internalId, reason: .busy, debugLog: .single(nil))
let debugLog = Promise<String?>()
self.ongoingContext?.stop(debugLogValue: debugLog)
}
public func toggleIsMuted() {
if self.isMovedToConference {
return
}
self.setIsMuted(!self.isMutedValue)
}
public func setIsMuted(_ value: Bool) {
if self.isMovedToConference {
return
}
self.isMutedValue = value
self.isMutedPromise.set(self.isMutedValue)
self.ongoingContext?.setIsMuted(self.isMutedValue)
}
public func requestVideo() {
if self.isMovedToConference {
return
}
if self.videoCapturer == nil {
let videoCapturer = OngoingCallVideoCapturer()
self.videoCapturer = videoCapturer
@ -1270,6 +1338,9 @@ public final class PresentationCallImpl: PresentationCall {
}
public func requestVideo(capturer: OngoingCallVideoCapturer) {
if self.isMovedToConference {
return
}
if self.videoCapturer == nil {
self.videoCapturer = capturer
}
@ -1281,11 +1352,17 @@ public final class PresentationCallImpl: PresentationCall {
}
public func setRequestedVideoAspect(_ aspect: Float) {
if self.isMovedToConference {
return
}
self.requestedVideoAspect = aspect
self.ongoingContext?.setRequestedVideoAspect(aspect)
}
public func disableVideo() {
if self.isMovedToConference {
return
}
if let _ = self.videoCapturer {
self.videoCapturer = nil
if let ongoingContext = self.ongoingContext {
@ -1295,6 +1372,9 @@ public final class PresentationCallImpl: PresentationCall {
}
private func resetScreencastContext() {
if self.isMovedToConference {
return
}
let basePath = self.context.sharedContext.basePath + "/broadcast-coordination"
let screencastBufferServerContext = IpcGroupCallBufferAppContext(basePath: basePath)
self.screencastBufferServerContext = screencastBufferServerContext
@ -1332,6 +1412,9 @@ public final class PresentationCallImpl: PresentationCall {
}
private func requestScreencast() {
if self.isMovedToConference {
return
}
self.disableVideo()
if let screencastCapturer = self.screencastCapturer {
@ -1343,6 +1426,9 @@ public final class PresentationCallImpl: PresentationCall {
}
func disableScreencast(reset: Bool = true) {
if self.isMovedToConference {
return
}
if self.isScreencastActive {
if let _ = self.videoCapturer {
self.videoCapturer = nil
@ -1357,10 +1443,16 @@ public final class PresentationCallImpl: PresentationCall {
}
public func setOutgoingVideoIsPaused(_ isPaused: Bool) {
if self.isMovedToConference {
return
}
self.videoCapturer?.setIsVideoEnabled(!isPaused)
}
public func upgradeToConference(invitePeerIds: [EnginePeer.Id], completion: @escaping (PresentationGroupCall) -> Void) -> Disposable {
if self.isMovedToConference {
return EmptyDisposable
}
if let conferenceCall = self.conferenceCall {
completion(conferenceCall)
return EmptyDisposable
@ -1385,6 +1477,9 @@ public final class PresentationCallImpl: PresentationCall {
}
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
if self.isMovedToConference {
return
}
if let sharedAudioContext = self.sharedAudioContext {
sharedAudioContext.setCurrentAudioOutput(output)
return
@ -1416,6 +1511,9 @@ public final class PresentationCallImpl: PresentationCall {
}
func video(isIncoming: Bool) -> Signal<OngoingGroupCallContext.VideoFrameData, NoError>? {
if self.isMovedToConference {
return nil
}
if isIncoming {
if let ongoingContext = self.ongoingContext {
return ongoingContext.video(isIncoming: isIncoming)
@ -1430,6 +1528,10 @@ public final class PresentationCallImpl: PresentationCall {
}
public func makeOutgoingVideoView(completion: @escaping (PresentationCallVideoView?) -> Void) {
if self.isMovedToConference {
completion(nil)
return
}
if self.videoCapturer == nil {
let videoCapturer = OngoingCallVideoCapturer()
self.videoCapturer = videoCapturer
@ -1504,6 +1606,9 @@ public final class PresentationCallImpl: PresentationCall {
}
public func switchVideoCamera() {
if self.isMovedToConference {
return
}
self.useFrontCamera = !self.useFrontCamera
self.videoCapturer?.switchVideoInput(isFront: self.useFrontCamera)
}

View file

@ -62,6 +62,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
private let removeCurrentCallDisposable = MetaDisposable()
private let removeCurrentGroupCallDisposable = MetaDisposable()
private var callToConferenceDisposable: Disposable?
private var isConferenceReadyDisposable: Disposable?
private var currentUpgradedToConferenceCallId: CallSessionInternalId?
private var currentGroupCallValue: VideoChatCall?
@ -251,7 +252,19 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
}
endCallImpl = { [weak self] uuid in
if let strongSelf = self, let currentCall = strongSelf.currentCall {
guard let self else {
return .single(false)
}
if let currentGroupCall = self.currentGroupCall {
switch currentGroupCall {
case let .conferenceSource(conferenceSource):
return conferenceSource.hangUp()
case let .group(groupCall):
return groupCall.leave(terminateIfPossible: false)
}
}
if let currentCall = self.currentCall {
return currentCall.hangUp()
} else {
return .single(false)
@ -300,6 +313,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
self.proxyServerDisposable?.dispose()
self.callSettingsDisposable?.dispose()
self.callToConferenceDisposable?.dispose()
self.isConferenceReadyDisposable?.dispose()
}
private func ringingStatesUpdated(_ ringingStates: [(AccountContext, Peer, CallSessionRingingState, Bool, NetworkType)], enableCallKit: Bool) {
@ -334,7 +348,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
internalId: firstState.2.id,
peerId: firstState.2.peerId,
isOutgoing: false,
isIncomingConference: firstState.2.isConference,
isIncomingConference: firstState.2.isIncomingConference,
peer: EnginePeer(firstState.1),
proxyServer: strongSelf.proxyServer,
auxiliaryServers: [],
@ -687,13 +701,21 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
}
if self.currentGroupCallValue != value {
if case let .group(groupCall) = self.currentGroupCallValue, let conferenceSourceId = groupCall.conferenceSource {
groupCall.accountContext.account.callSessionManager.drop(internalId: conferenceSourceId, reason: .hangUp, debugLog: .single(nil))
(groupCall as! PresentationGroupCallImpl).callKitIntegration?.dropCall(uuid: conferenceSourceId)
}
self.currentGroupCallValue = value
self.isConferenceReadyDisposable?.dispose()
self.isConferenceReadyDisposable = nil
if let value {
switch value {
case let .conferenceSource(conferenceSource):
self.callToConferenceDisposable?.dispose()
self.callToConferenceDisposable = (conferenceSource.conferenceState
self.isConferenceReadyDisposable?.dispose()
self.isConferenceReadyDisposable = (conferenceSource.conferenceState
|> filter { value in
if let value, case .ready = value {
return true
@ -709,6 +731,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
guard let groupCall = conferenceSource.conferenceCall else {
return
}
(conferenceSource as! PresentationCallImpl).resetAsMovedToConference()
self.updateCurrentGroupCall(.group(groupCall))
})
@ -826,6 +849,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
isStream: false,
encryptionKey: nil,
conferenceFromCallId: nil,
conferenceSourceId: nil,
isConference: false,
sharedAudioContext: nil
)
@ -1052,6 +1076,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
isStream: initialCall.isStream ?? false,
encryptionKey: nil,
conferenceFromCallId: nil,
conferenceSourceId: nil,
isConference: false,
sharedAudioContext: nil
)

View file

@ -770,7 +770,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
public let account: Account
public let accountContext: AccountContext
private let audioSession: ManagedAudioSession
private let callKitIntegration: CallKitIntegration?
public let callKitIntegration: CallKitIntegration?
public var isIntegratedWithCallKit: Bool {
return self.callKitIntegration != nil
}
@ -1057,6 +1057,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
}
}
private let conferenceSourceId: CallSessionInternalId?
public var conferenceSource: CallSessionInternalId? {
return self.conferenceSourceId
}
var internal_isRemoteConnected = Promise<Bool>()
private var internal_isRemoteConnectedDisposable: Disposable?
@ -1081,6 +1086,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
isStream: Bool,
encryptionKey: (key: Data, fingerprint: Int64)?,
conferenceFromCallId: CallId?,
conferenceSourceId: CallSessionInternalId?,
isConference: Bool,
sharedAudioContext: SharedCallAudioContext?
) {
@ -1109,6 +1115,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.hasScreencast = false
self.isStream = isStream
self.conferenceFromCallId = conferenceFromCallId
self.conferenceSourceId = conferenceSourceId
self.isConference = isConference
self.encryptionKey = encryptionKey

View file

@ -326,6 +326,11 @@ final class VideoChatMicButtonComponent: Component {
let previousComponent = self.component
self.component = component
if let previousComponent, previousComponent.call != component.call {
self.audioLevelDisposable?.dispose()
self.audioLevelDisposable = nil
}
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.2)
let titleText: String

View file

@ -230,6 +230,11 @@ final class VideoChatParticipantAvatarComponent: Component {
let previousComponent = self.component
self.component = component
if let previousComponent, previousComponent.call != component.call {
self.audioLevelDisposable?.dispose()
self.audioLevelDisposable = nil
}
let avatarNode: AvatarNode
if let current = self.avatarNode {
avatarNode = current

View file

@ -163,6 +163,16 @@ final class VideoChatScreenComponent: Component {
}
static func ==(lhs: VideoChatScreenComponent, rhs: VideoChatScreenComponent) -> Bool {
if lhs === rhs {
return true
}
if lhs.initialData !== rhs.initialData {
return false
}
if lhs.initialCall != rhs.initialCall {
return false
}
return true
}
@ -1082,7 +1092,12 @@ final class VideoChatScreenComponent: Component {
self.callState = component.initialData.callState
}
var call = self.currentCall ?? component.initialCall
var call: VideoChatCall
if let previousComponent = self.component, previousComponent.initialCall != component.initialCall {
call = component.initialCall
} else {
call = self.currentCall ?? component.initialCall
}
if case let .conferenceSource(conferenceSource) = call, let conferenceCall = conferenceSource.conferenceCall, conferenceSource.conferenceStateValue == .ready {
call = .group(conferenceCall)
}
@ -2517,6 +2532,17 @@ final class VideoChatScreenV2Impl: ViewControllerComponentContainer, VoiceChatCo
self.idleTimerExtensionDisposable?.dispose()
}
func updateCall(call: VideoChatCall) {
self.call = call
if let component = self.component.wrapped as? VideoChatScreenComponent {
// This is only to clear the reference to regular call
self.updateComponent(component: AnyComponent(VideoChatScreenComponent(
initialData: component.initialData,
initialCall: call
)), transition: .immediate)
}
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

View file

@ -248,6 +248,8 @@ public protocol VoiceChatController: ViewController {
var onViewDidAppear: (() -> Void)? { get set }
var onViewDidDisappear: (() -> Void)? { get set }
func updateCall(call: VideoChatCall)
func dismiss(closing: Bool, manual: Bool)
}
@ -6938,6 +6940,9 @@ final class VoiceChatControllerImpl: ViewController, VoiceChatController {
}
}
func updateCall(call: VideoChatCall) {
}
override public func loadDisplayNode() {
self.displayNode = Node(controller: self, sharedContext: self.sharedContext, call: self.callImpl)

View file

@ -79,7 +79,7 @@ enum CallSessionInternalState {
case requesting(a: Data, conferenceCall: GroupCallReference?, disposable: Disposable)
case requested(id: Int64, accessHash: Int64, a: Data, gA: Data, config: SecretChatEncryptionConfig, remoteConfirmationTimestamp: Int32?, conferenceCall: GroupCallReference?)
case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: Data, conferenceCall: GroupCallReference?, disposable: Disposable)
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?, willSwitchToConference: Bool)
case switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
case dropping(reason: CallSessionTerminationReason, disposable: Disposable)
case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool)
@ -98,7 +98,7 @@ enum CallSessionInternalState {
return id
case let .confirming(id, _, _, _, _, _, _):
return id
case let .active(id, _, _, _, _, _, _, _, _, _, _, _):
case let .active(id, _, _, _, _, _, _, _, _, _, _, _, _):
return id
case .switchedToConference:
return nil
@ -137,7 +137,7 @@ public struct CallSessionRingingState: Equatable {
public let peerId: PeerId
public let isVideo: Bool
public let isVideoPossible: Bool
public let isConference: Bool
public let isIncomingConference: Bool
}
public enum DropCallReason {
@ -166,7 +166,7 @@ public enum CallSessionState {
case ringing
case accepting
case requesting(ringing: Bool, conferenceCall: GroupCallReference?)
case active(id: CallId, key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?)
case active(id: CallId, key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowsP2P: Bool, conferenceCall: GroupCallReference?, willSwitchToConference: Bool)
case switchedToConference(key: Data, keyVisualHash: Data, conferenceCall: GroupCallReference)
case dropping(reason: CallSessionTerminationReason)
case terminated(id: CallId?, reason: CallSessionTerminationReason, options: CallTerminationOptions)
@ -183,8 +183,8 @@ public enum CallSessionState {
self = .requesting(ringing: true, conferenceCall: conferenceCall)
case let .requested(_, _, _, _, _, remoteConfirmationTimestamp, conferenceCall):
self = .requesting(ringing: remoteConfirmationTimestamp != nil, conferenceCall: conferenceCall)
case let .active(id, accessHash, _, key, _, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
self = .active(id: CallId(id: id, accessHash: accessHash), key: key, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall)
case let .active(id, accessHash, _, key, _, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall, willSwitchToConference):
self = .active(id: CallId(id: id, accessHash: accessHash), key: key, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall, willSwitchToConference: willSwitchToConference)
case let .dropping(reason, _):
self = .dropping(reason: reason)
case let .terminated(id, accessHash, reason, reportRating, sendDebugLogs):
@ -335,7 +335,7 @@ private func parseConnectionSet(primary: Api.PhoneConnection, alternative: [Api.
private final class CallSessionContext {
let peerId: PeerId
let isOutgoing: Bool
let isConference: Bool
let isIncomingConference: Bool
var type: CallSession.CallType
var isVideoPossible: Bool
let pendingConference: (conference: GroupCallReference, encryptionKey: Data)?
@ -355,10 +355,10 @@ private final class CallSessionContext {
}
}
init(peerId: PeerId, isOutgoing: Bool, isConference: Bool, type: CallSession.CallType, isVideoPossible: Bool, pendingConference: (conference: GroupCallReference, encryptionKey: Data)?, state: CallSessionInternalState) {
init(peerId: PeerId, isOutgoing: Bool, isIncomingConference: Bool, type: CallSession.CallType, isVideoPossible: Bool, pendingConference: (conference: GroupCallReference, encryptionKey: Data)?, state: CallSessionInternalState) {
self.peerId = peerId
self.isOutgoing = isOutgoing
self.isConference = isConference
self.isIncomingConference = isIncomingConference
self.type = type
self.isVideoPossible = isVideoPossible
self.pendingConference = pendingConference
@ -555,7 +555,7 @@ private final class CallSessionManagerContext {
peerId: context.peerId,
isVideo: context.type == .video,
isVideoPossible: context.isVideoPossible,
isConference: context.isConference
isIncomingConference: context.isIncomingConference
))
}
}
@ -599,7 +599,7 @@ private final class CallSessionManagerContext {
//#endif
let internalId = CallSessionManager.getStableIncomingUUID(stableId: stableId)
let context = CallSessionContext(peerId: peerId, isOutgoing: false, isConference: conferenceCall != nil, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, pendingConference: nil, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions, conferenceCall: conferenceCall))
let context = CallSessionContext(peerId: peerId, isOutgoing: false, isIncomingConference: conferenceCall != nil, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, pendingConference: nil, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions, conferenceCall: conferenceCall))
self.contexts[internalId] = context
let queue = self.queue
@ -653,7 +653,7 @@ private final class CallSessionManagerContext {
case let .accepting(id, accessHash, _, _, _, disposable):
dropData = (id, accessHash, .abort)
disposable.dispose()
case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _, _, _, _):
case let .active(id, accessHash, beginTimestamp, _, _, _, _, _, _, _, _, _, _):
let duration = max(0, Int32(CFAbsoluteTimeGetCurrent()) - beginTimestamp)
let internalReason: DropCallSessionReason
switch reason {
@ -755,7 +755,7 @@ private final class CallSessionManagerContext {
var dropData: (CallSessionStableId, Int64)?
let isVideo = context.type == .video
switch context.state {
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _):
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _, _):
dropData = (id, accessHash)
default:
break
@ -807,7 +807,7 @@ private final class CallSessionManagerContext {
strongSelf.contextUpdated(internalId: internalId)
case let .call(config, gA, timestamp, connections, maxLayer, version, customParameters, allowsP2P, conferenceCall):
if let (key, keyId, keyVisualHash) = strongSelf.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gA) {
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: timestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall)
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: timestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall, willSwitchToConference: context.isIncomingConference)
strongSelf.contextUpdated(internalId: internalId)
} else {
strongSelf.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
@ -828,7 +828,7 @@ private final class CallSessionManagerContext {
func sendSignalingData(internalId: CallSessionInternalId, data: Data) {
if let context = self.contexts[internalId] {
switch context.state {
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _):
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, _, _):
context.signalingDisposables.add(self.network.request(Api.functions.phone.sendSignalingData(peer: .inputPhoneCall(id: id, accessHash: accessHash), data: Buffer(data: data))).start())
default:
break
@ -844,7 +844,7 @@ private final class CallSessionManagerContext {
var idAndAccessHash: (id: Int64, accessHash: Int64)?
switch context.state {
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, conferenceCall):
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, conferenceCall, _):
if conferenceCall != nil {
return
}
@ -864,8 +864,8 @@ private final class CallSessionManagerContext {
}
if let result {
switch context.state {
case let .active(id, accessHash, beginTimestamp, key, keyId, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: beginTimestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: result)
case let .active(id, accessHash, beginTimestamp, key, keyId, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, _, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: beginTimestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: result, willSwitchToConference: false)
self.contextUpdated(internalId: internalId)
default:
break
@ -977,7 +977,7 @@ private final class CallSessionManagerContext {
disposable.dispose()
context.state = .terminated(id: id, accessHash: accessHash, reason: parsedReason, reportRating: reportRating, sendDebugLogs: sendDebugLogs)
self.contextUpdated(internalId: internalId)
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, conferenceCall):
case let .active(id, accessHash, _, _, _, _, _, _, _, _, _, conferenceCall, _):
if let conferenceCall, case let .phoneCallDiscardReasonAllowGroupCall(encryptedGroupKey) = reason {
context.state = .switchedToConference(key: encryptedGroupKey.makeData(), keyVisualHash: MTSha256(encryptedGroupKey.makeData()), conferenceCall: conferenceCall)
} else {
@ -1016,8 +1016,8 @@ private final class CallSessionManagerContext {
switch context.state {
case .accepting, .dropping, .requesting, .ringing, .terminated, .requested, .switchedToConference:
break
case let .active(id, accessHash, beginTimestamp, key, keyId, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: beginTimestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init))
case let .active(id, accessHash, beginTimestamp, key, keyId, keyVisualHash, connections, maxLayer, version, customParameters, allowsP2P, _, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: beginTimestamp, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: connections, maxLayer: maxLayer, version: version, customParameters: customParameters, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init), willSwitchToConference: context.isIncomingConference)
self.contextUpdated(internalId: internalId)
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) {
@ -1036,7 +1036,7 @@ private final class CallSessionManagerContext {
let isVideoPossible = self.videoVersions().contains(where: { versions.contains($0) })
context.isVideoPossible = isVideoPossible
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], customParameters: customParametersValue, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init))
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], customParameters: customParametersValue, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init), willSwitchToConference: context.isIncomingConference)
self.contextUpdated(internalId: internalId)
} else {
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
@ -1063,7 +1063,7 @@ private final class CallSessionManagerContext {
let isVideoPossible = self.videoVersions().contains(where: { versions.contains($0) })
context.isVideoPossible = isVideoPossible
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], customParameters: customParametersValue, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init))
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], customParameters: customParametersValue, allowsP2P: allowsP2P, conferenceCall: conferenceCall.flatMap(GroupCallReference.init), willSwitchToConference: context.isIncomingConference)
self.contextUpdated(internalId: internalId)
} else {
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
@ -1173,7 +1173,7 @@ private final class CallSessionManagerContext {
let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self))
let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free)
if randomStatus == 0 {
self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, isConference: conferenceCall != nil, type: isVideo ? .video : .audio, isVideoPossible: enableVideo || isVideo, pendingConference: conferenceCall, state: .requesting(a: a, conferenceCall: conferenceCall?.conference, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.filteredVersions(enableVideo: true), isVideo: isVideo, conferenceCall: conferenceCall?.conference) |> deliverOn(queue)).start(next: { [weak self] result in
self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, isIncomingConference: false, type: isVideo ? .video : .audio, isVideoPossible: enableVideo || isVideo, pendingConference: conferenceCall, state: .requesting(a: a, conferenceCall: conferenceCall?.conference, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.filteredVersions(enableVideo: true), isVideo: isVideo, conferenceCall: conferenceCall?.conference) |> deliverOn(queue)).start(next: { [weak self] result in
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
if case .requesting = context.state {
switch result {

View file

@ -183,6 +183,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public var currentGroupCallController: ViewController? {
return self.groupCallController
}
private var hasGroupCallOnScreenValue: Bool = false
private let hasGroupCallOnScreenPromise = Promise<Bool>(false)
public var hasGroupCallOnScreen: Signal<Bool, NoError> {
return self.hasGroupCallOnScreenPromise.get()
@ -1182,15 +1183,14 @@ public final class SharedAccountContextImpl: SharedAccountContext {
self.notificationController?.setBlocking(nil)
}
self.callStateDisposable?.dispose()
self.callStateDisposable = nil
}
self.currentCall = call
let beginDisplayingCallStatusBar = Promise<Void>()
var shouldResetGroupCallOnScreen = true
var transitioningToConferenceCallController: CallController?
if let call, case let .group(groupCall) = call, case let .conferenceSource(conferenceSource) = groupCall, let callController = self.callController, callController.call === conferenceSource {
transitioningToConferenceCallController = callController
@ -1198,8 +1198,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
callController.dismissWithoutAnimation()
}
self.callController = nil
} else {
self.hasGroupCallOnScreenPromise.set(.single(false))
shouldResetGroupCallOnScreen = false
}
if let callController = self.callController {
@ -1207,10 +1206,27 @@ public final class SharedAccountContextImpl: SharedAccountContext {
callController.dismiss()
}
if let groupCallController = self.groupCallController {
if case let .group(groupCall) = call, case let .group(groupCall) = groupCall, let conferenceSourceId = groupCall.conferenceSource {
if case let .conferenceSource(conferenceSource) = groupCallController.call, conferenceSource.internalId == conferenceSourceId {
groupCallController.updateCall(call: .group(groupCall))
self.updateInCallStatusBarData(hasGroupCallOnScreen: self.hasGroupCallOnScreenValue)
return
}
}
self.groupCallController = nil
groupCallController.dismiss()
}
if shouldResetGroupCallOnScreen {
self.hasGroupCallOnScreenPromise.set(.single(false))
}
self.callStateDisposable?.dispose()
self.callStateDisposable = nil
if case let .call(call) = call {
let callController = CallController(sharedContext: self, account: call.context.account, call: call, easyDebugAccess: !GlobalExperimentalSettings.isAppStoreBuild)
self.callController = callController
@ -1282,36 +1298,36 @@ public final class SharedAccountContextImpl: SharedAccountContext {
))
})
}
}
self.awaitingCallConnectionDisposable = (call.state
|> filter { state in
switch state.state {
case .ringing:
return false
case .terminating, .terminated:
return false
default:
return true
}
}
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self, weak callController] _ in
guard let self, let callController, self.callController === callController else {
return
}
self.notificationController?.setBlocking(nil)
self.callPeerDisposable?.dispose()
self.callPeerDisposable = nil
thisCallIsOnScreenPromise.set(true)
if useFlatModalCallsPresentation(context: callController.call.context) {
(self.mainWindow?.viewController as? NavigationController)?.pushViewController(callController)
} else {
self.mainWindow?.present(callController, on: .calls)
self.awaitingCallConnectionDisposable = (call.state
|> filter { state in
switch state.state {
case .ringing:
return false
case .terminating, .terminated:
return false
default:
return true
}
}
})
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self, weak callController] _ in
guard let self, let callController, self.callController === callController else {
return
}
self.notificationController?.setBlocking(nil)
self.callPeerDisposable?.dispose()
self.callPeerDisposable = nil
thisCallIsOnScreenPromise.set(true)
if useFlatModalCallsPresentation(context: callController.call.context) {
(self.mainWindow?.viewController as? NavigationController)?.pushViewController(callController)
} else {
self.mainWindow?.present(callController, on: .calls)
}
})
}
beginDisplayingCallStatusBar.set(call.state
|> filter { state in
@ -1389,40 +1405,11 @@ public final class SharedAccountContextImpl: SharedAccountContext {
guard let self else {
return
}
var statusBarContent: CallStatusBarNodeImpl.Content?
if !hasGroupCallOnScreen, let currentCall = self.currentCall {
switch currentCall {
case let .call(call):
statusBarContent = .call(self, call.context.account, call)
case let .group(groupCall):
switch groupCall {
case let .conferenceSource(conferenceSource):
statusBarContent = .call(self, conferenceSource.context.account, conferenceSource)
case let .group(groupCall):
statusBarContent = .groupCall(self, groupCall.account, groupCall)
}
}
}
var resolvedCallStatusBarNode: CallStatusBarNodeImpl?
if let statusBarContent {
if let current = self.currentCallStatusBarNode {
resolvedCallStatusBarNode = current
} else {
resolvedCallStatusBarNode = CallStatusBarNodeImpl()
self.currentCallStatusBarNode = resolvedCallStatusBarNode
}
resolvedCallStatusBarNode?.update(content: statusBarContent)
} else {
self.currentCallStatusBarNode = nil
}
if let navigationController = self.mainWindow?.viewController as? NavigationController {
navigationController.setForceInCallStatusBar(resolvedCallStatusBarNode)
}
self.hasGroupCallOnScreenValue = hasGroupCallOnScreen
self.updateInCallStatusBarData(hasGroupCallOnScreen: hasGroupCallOnScreen)
})
} else {
self.hasGroupCallOnScreenValue = false
self.currentCallStatusBarNode = nil
if let navigationController = self.mainWindow?.viewController as? NavigationController {
navigationController.setForceInCallStatusBar(nil)
@ -1430,6 +1417,40 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
}
private func updateInCallStatusBarData(hasGroupCallOnScreen: Bool) {
var statusBarContent: CallStatusBarNodeImpl.Content?
if !hasGroupCallOnScreen, let currentCall = self.currentCall {
switch currentCall {
case let .call(call):
statusBarContent = .call(self, call.context.account, call)
case let .group(groupCall):
switch groupCall {
case let .conferenceSource(conferenceSource):
statusBarContent = .call(self, conferenceSource.context.account, conferenceSource)
case let .group(groupCall):
statusBarContent = .groupCall(self, groupCall.account, groupCall)
}
}
}
var resolvedCallStatusBarNode: CallStatusBarNodeImpl?
if let statusBarContent {
if let current = self.currentCallStatusBarNode {
resolvedCallStatusBarNode = current
} else {
resolvedCallStatusBarNode = CallStatusBarNodeImpl()
self.currentCallStatusBarNode = resolvedCallStatusBarNode
}
resolvedCallStatusBarNode?.update(content: statusBarContent)
} else {
self.currentCallStatusBarNode = nil
}
if let navigationController = self.mainWindow?.viewController as? NavigationController {
navigationController.setForceInCallStatusBar(resolvedCallStatusBarNode)
}
}
private func presentControllerWithCurrentCall() {
/*guard let call = self.call else {
return

View file

@ -2275,6 +2275,10 @@ isConference:(bool)isConference {
auto encryptionKeyValue = std::make_shared<std::array<uint8_t, 256>>();
memcpy(encryptionKeyValue->data(), encryptionKey.bytes, encryptionKey.length);
#if DEBUG
NSLog(@"Encryption key: %@", [encryptionKey base64EncodedStringWithOptions:0]);
#endif
mappedEncryptionKey = tgcalls::EncryptionKey(encryptionKeyValue, true);
}