diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index a17e0eabee..e33ed339f7 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -36,6 +36,11 @@ public final class CallKitIntegration { var audioSessionActive: Signal { return self.audioSessionActivePromise.get() } + + private let hasActiveCallsValue = ValuePromise(false, ignoreRepeated: true) + public var hasActiveCalls: Signal { + return self.hasActiveCallsValue.get() + } private static let sharedInstance: CallKitIntegration? = CallKitIntegration() public static var shared: CallKitIntegration? { @@ -50,7 +55,7 @@ public final class CallKitIntegration { audioSessionActivationChanged: @escaping (Bool) -> Void ) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { - (sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged) + (sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged, hasActiveCallsValue: hasActiveCallsValue) } } @@ -130,6 +135,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { private var endCall: ((UUID) -> Signal)? private var setCallMuted: ((UUID, Bool) -> Void)? private var audioSessionActivationChanged: ((Bool) -> Void)? + private var hasActiveCallsValue: ValuePromise? private var isAudioSessionActive: Bool = false private var pendingVoiceChatOutputMode: AudioSessionOutputMode? @@ -138,6 +144,12 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { fileprivate var audioSessionActivePromise: ValuePromise? + private var activeCalls = Set() { + didSet { + self.hasActiveCallsValue?.set(!self.activeCalls.isEmpty) + } + } + override init() { self.provider = CXProvider(configuration: CallKitProviderDelegate.providerConfiguration()) @@ -146,13 +158,14 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { self.provider.setDelegate(self, queue: nil) } - func setup(audioSessionActivePromise: ValuePromise, startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) { + func setup(audioSessionActivePromise: ValuePromise, startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void, hasActiveCallsValue: ValuePromise) { self.audioSessionActivePromise = audioSessionActivePromise self.startCall = startCall self.answerCall = answerCall self.endCall = endCall self.setCallMuted = setCallMuted self.audioSessionActivationChanged = audioSessionActivationChanged + self.hasActiveCallsValue = hasActiveCallsValue } private static func providerConfiguration() -> CXProviderConfiguration { @@ -185,12 +198,16 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { let endCallAction = CXEndCallAction(call: uuid) let transaction = CXTransaction(action: endCallAction) self.requestTransaction(transaction) + + self.activeCalls.remove(uuid) } func dropCall(uuid: UUID) { Logger.shared.log("CallKitIntegration", "report call ended \(uuid)") self.provider.reportCall(with: uuid, endedAt: nil, reason: CXCallEndedReason.remoteEnded) + + self.activeCalls.remove(uuid) } func answerCall(uuid: UUID) { @@ -231,6 +248,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { update.supportsDTMF = false self.provider.reportCall(with: uuid, updated: update) + + self.activeCalls.insert(uuid) }) } @@ -261,6 +280,10 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { OngoingCallContext.setupAudioSession() self.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in + if error == nil { + self.activeCalls.insert(uuid) + } + completion?(error as NSError?) }) } @@ -279,6 +302,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { func providerDidReset(_ provider: CXProvider) { Logger.shared.log("CallKitIntegration", "providerDidReset") + + self.activeCalls.removeAll() } func provider(_ provider: CXProvider, perform action: CXStartCallAction) { diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index d4892b7102..3f24eddb86 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -605,7 +605,20 @@ private func extractAccountManagerState(records: AccountRecordsView = .single(false) + if CallKitIntegration.isAvailable, let callKitIntegration = CallKitIntegration.shared { + hasActiveCalls = callKitIntegration.hasActiveCalls + } + self.hasActiveAudioSession.set( + combineLatest(queue: .mainQueue(), + hasActiveCalls, + MediaManagerImpl.globalAudioSession.isActive() + ) + |> map { hasActiveCalls, isActive -> Bool in + return hasActiveCalls || isActive + } + |> distinctUntilChanged + ) let applicationBindings = TelegramApplicationBindings(isMainApp: true, appBundleId: baseAppBundleId, appBuildType: buildConfig.isAppStoreBuild ? .public : .internal, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { url in var parsedUrl = URL(string: url)