From 78007cedfd697f47ae79f6383e175a63747e04a1 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Wed, 19 Dec 2018 22:44:00 +0300 Subject: [PATCH] Support tgvoip derived state --- TelegramUI.xcodeproj/project.pbxproj | 4 ++ TelegramUI/DeclareEncodables.swift | 1 + TelegramUI/OngoingCallContext.swift | 10 ++++- TelegramUI/OngoingCallThreadLocalContext.h | 3 +- TelegramUI/OngoingCallThreadLocalContext.mm | 15 ++++++- TelegramUI/PostboxKeys.swift | 2 + TelegramUI/PresentationCall.swift | 4 +- TelegramUI/PresentationCallManager.swift | 11 ++--- TelegramUI/VoipDerivedState.swift | 45 +++++++++++++++++++++ 9 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 TelegramUI/VoipDerivedState.swift diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index 745a6cf778..1c110a481a 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -101,6 +101,7 @@ 09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; }; 9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */; }; 9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */; }; + D005808B21CAB8F000CB7CD3 /* VoipDerivedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005808A21CAB8F000CB7CD3 /* VoipDerivedState.swift */; }; D0068FA821760FA300D1B315 /* StoreDownloadedMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0068FA721760FA300D1B315 /* StoreDownloadedMedia.swift */; }; D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; }; D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; }; @@ -1210,6 +1211,7 @@ D003702D1DA43052004308D3 /* ItemListAvatarAndNameItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListAvatarAndNameItem.swift; sourceTree = ""; }; D003702F1DA43077004308D3 /* ItemListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListItem.swift; sourceTree = ""; }; D00370311DA46C06004308D3 /* ItemListTextWithLabelItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListTextWithLabelItem.swift; sourceTree = ""; }; + D005808A21CAB8F000CB7CD3 /* VoipDerivedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoipDerivedState.swift; sourceTree = ""; }; D0068FA721760FA300D1B315 /* StoreDownloadedMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDownloadedMedia.swift; sourceTree = ""; }; D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegqacyICloudFileController.swift; sourceTree = ""; }; D007019D2029EFDD006B9E34 /* ICloudResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICloudResources.swift; sourceTree = ""; }; @@ -3304,6 +3306,7 @@ D08A10BA211DF7A80077488B /* StickerSettings.swift */, 0952D1762177FB5400194860 /* WatchPresetSettings.swift */, 0962E67C21BA048D00245FD9 /* WebSearchSettings.swift */, + D005808A21CAB8F000CB7CD3 /* VoipDerivedState.swift */, ); name = Settings; sourceTree = ""; @@ -5916,6 +5919,7 @@ D0EC6E7B1EB9F58900EBF1C3 /* DebugAccountsController.swift in Sources */, D093D8262069A31700BC3599 /* FormControllerItem.swift in Sources */, D0EC6E7C1EB9F58900EBF1C3 /* UsernameSetupController.swift in Sources */, + D005808B21CAB8F000CB7CD3 /* VoipDerivedState.swift in Sources */, D0471B621EFEB5B70074D609 /* BotPaymentSwitchItemNode.swift in Sources */, D09250041FE5363D003F693F /* ExperimentalSettings.swift in Sources */, D0E8175B201254FA00B82BBB /* ChatRecentActionsEmptyNode.swift in Sources */, diff --git a/TelegramUI/DeclareEncodables.swift b/TelegramUI/DeclareEncodables.swift index 097f18315f..8997712ab5 100644 --- a/TelegramUI/DeclareEncodables.swift +++ b/TelegramUI/DeclareEncodables.swift @@ -31,6 +31,7 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) declareEncodable(RecentWebSearchQueryItem.self, f: { RecentWebSearchQueryItem(decoder: $0) }) + declareEncodable(VoipDerivedState.self, f: { VoipDerivedState(decoder: $0) }) return }() diff --git a/TelegramUI/OngoingCallContext.swift b/TelegramUI/OngoingCallContext.swift index 23f68f7782..4dc22dd8cb 100644 --- a/TelegramUI/OngoingCallContext.swift +++ b/TelegramUI/OngoingCallContext.swift @@ -115,6 +115,7 @@ final class OngoingCallContext { let internalId: CallSessionInternalId private let queue = Queue() + private let postbox: Postbox private let callSessionManager: CallSessionManager private var contextRef: Unmanaged? @@ -148,11 +149,12 @@ final class OngoingCallContext { return OngoingCallThreadLocalContext.maxLayer() } - init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal, serializedData: String?, dataSaving: VoiceCallDataSaving, logPath: String) { + init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, logPath: String) { let _ = setupLogs OngoingCallThreadLocalContext.applyServerConfig(serializedData) self.internalId = internalId + self.postbox = account.postbox self.callSessionManager = callSessionManager let queue = self.queue @@ -166,7 +168,7 @@ final class OngoingCallContext { break } } - let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), logPath: logPath) + let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), logPath: logPath, derivedState: derivedState.data) self.contextRef = Unmanaged.passRetained(context) context.stateChanged = { [weak self] state in self?.contextState.set(.single(state)) @@ -228,6 +230,10 @@ final class OngoingCallContext { func stop() { self.withContext { context in context.stop() + let derivedState = context.getDerivedState() + let _ = updateVoipDerivedStateInteractively(postbox: self.postbox, { _ in + return VoipDerivedState(data: derivedState) + }).start() } } diff --git a/TelegramUI/OngoingCallThreadLocalContext.h b/TelegramUI/OngoingCallThreadLocalContext.h index 70abe60f6f..a15897f048 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.h +++ b/TelegramUI/OngoingCallThreadLocalContext.h @@ -63,12 +63,13 @@ typedef NS_ENUM(int32_t, OngoingCallDataSaving) { @property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t); @property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile); -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath; +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath derivedState:(NSData * _Nonnull)derivedState; - (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P; - (void)stop; - (NSString * _Nullable)debugInfo; - (NSString * _Nullable)version; +- (NSData * _Nonnull)getDerivedState; - (void)setIsMuted:(bool)isMuted; - (void)setNetworkType:(OngoingCallNetworkType)networkType; diff --git a/TelegramUI/OngoingCallThreadLocalContext.mm b/TelegramUI/OngoingCallThreadLocalContext.mm index a318747fd1..5dfd4ac5d8 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.mm +++ b/TelegramUI/OngoingCallThreadLocalContext.mm @@ -214,7 +214,7 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { return tgvoip::VoIPController::GetConnectionMaxLayer(); } -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath { +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath derivedState:(NSData * _Nonnull)derivedState { self = [super init]; if (self != nil) { _queue = queue; @@ -231,6 +231,10 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { _controller = new tgvoip::VoIPController(); _controller->implData = (void *)((intptr_t)_contextId); + std::vector derivedStateValue; + derivedStateValue.resize(derivedState.length); + [derivedState getBytes:derivedStateValue.data() length:derivedState.length]; + _controller->SetPersistentState(derivedStateValue); if (proxy != nil) { _controller->SetProxy(tgvoip::PROXY_SOCKS5, proxy.host.UTF8String, (uint16_t)proxy.port, proxy.username.UTF8String ?: "", proxy.password.UTF8String ?: ""); @@ -337,6 +341,15 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { } } +- (NSData * _Nonnull)getDerivedState { + if (_controller != nil) { + std::vector derivedStateValue = _controller->GetPersistentState(); + return [[NSData alloc] initWithBytes:derivedStateValue.data() length:derivedStateValue.size()]; + } else { + return [NSData data]; + } +} + - (void)controllerStateChanged:(int)state { OngoingCallState callState = OngoingCallStateInitializing; switch (state) { diff --git a/TelegramUI/PostboxKeys.swift b/TelegramUI/PostboxKeys.swift index 0ff762770f..f03752284b 100644 --- a/TelegramUI/PostboxKeys.swift +++ b/TelegramUI/PostboxKeys.swift @@ -19,6 +19,7 @@ private enum ApplicationSpecificPreferencesKeyValues: Int32 { case stickerSettings = 13 case watchPresetSettings = 14 case webSearchSettings = 15 + case voipDerivedState = 16 } public struct ApplicationSpecificPreferencesKeys { @@ -38,6 +39,7 @@ public struct ApplicationSpecificPreferencesKeys { public static let stickerSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.stickerSettings.rawValue) public static let watchPresetSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.watchPresetSettings.rawValue) public static let webSearchSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.webSearchSettings.rawValue) + public static let voipDerivedState = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.voipDerivedState.rawValue) } private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 { diff --git a/TelegramUI/PresentationCall.swift b/TelegramUI/PresentationCall.swift index 01281de417..20ff4d73fd 100644 --- a/TelegramUI/PresentationCall.swift +++ b/TelegramUI/PresentationCall.swift @@ -220,7 +220,7 @@ public final class PresentationCall { private var droppedCall = false private var dropCallKitCallTimer: SwiftSignalKit.Timer? - init(account: Account, audioSession: ManagedAudioSession, callSessionManager: CallSessionManager, callKitIntegration: CallKitIntegration?, serializedData: String?, dataSaving: VoiceCallDataSaving, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), internalId: CallSessionInternalId, peerId: PeerId, isOutgoing: Bool, peer: Peer?, proxyServer: ProxyServerSettings?, currentNetworkType: NetworkType, updatedNetworkType: Signal) { + init(account: Account, audioSession: ManagedAudioSession, callSessionManager: CallSessionManager, callKitIntegration: CallKitIntegration?, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), internalId: CallSessionInternalId, peerId: PeerId, isOutgoing: Bool, peer: Peer?, proxyServer: ProxyServerSettings?, currentNetworkType: NetworkType, updatedNetworkType: Signal) { self.account = account self.audioSession = audioSession self.callSessionManager = callSessionManager @@ -232,7 +232,7 @@ public final class PresentationCall { self.isOutgoing = isOutgoing self.peer = peer - self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType, serializedData: serializedData, dataSaving: dataSaving, logPath: "") + self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType, serializedData: serializedData, dataSaving: dataSaving, derivedState: derivedState, logPath: "") var didReceiveAudioOutputs = false self.sessionStateDisposable = (callSessionManager.callState(internalId: internalId) diff --git a/TelegramUI/PresentationCallManager.swift b/TelegramUI/PresentationCallManager.swift index 0e805f79be..074f2e3476 100644 --- a/TelegramUI/PresentationCallManager.swift +++ b/TelegramUI/PresentationCallManager.swift @@ -59,7 +59,7 @@ public final class PresentationCallManager { private var proxyServer: ProxyServerSettings? private var proxyServerDisposable: Disposable? - private var callSettings: (VoiceCallSettings, VoipConfiguration)? + private var callSettings: (VoiceCallSettings, VoipConfiguration, VoipDerivedState)? private var callSettingsDisposable: Disposable? public static var voipMaxLayer: Int32 { @@ -192,12 +192,13 @@ public final class PresentationCallManager { } }) - self.callSettingsDisposable = (postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.voiceCallSettings, PreferencesKeys.voipConfiguration]) + self.callSettingsDisposable = (postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.voiceCallSettings, PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState]) |> deliverOnMainQueue).start(next: { [weak self] preferences in let callSettings = preferences.values[ApplicationSpecificPreferencesKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue + let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default if let strongSelf = self { - strongSelf.callSettings = (callSettings, configuration) + strongSelf.callSettings = (callSettings, configuration, derivedState) if let legacyP2PMode = callSettings.legacyP2PMode { _ = updateVoiceCallSettingsSettingsInteractively(postbox: postbox, { settings -> VoiceCallSettings in @@ -232,7 +233,7 @@ public final class PresentationCallManager { private func ringingStatesUpdated(_ ringingStates: [(Peer, CallSessionRingingState, Bool)], currentNetworkType: NetworkType, enableCallKit: Bool) { if let firstState = ringingStates.first { if self.currentCall == nil { - let call = PresentationCall(account: self.account, audioSession: self.audioSession, callSessionManager: self.callSessionManager, callKitIntegration: enableCallKit ? callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings?.0) : nil, serializedData: self.callSettings?.1.serializedData, dataSaving: self.callSettings?.0.dataSaving ?? .never, getDeviceAccessData: self.getDeviceAccessData, internalId: firstState.1.id, peerId: firstState.1.peerId, isOutgoing: false, peer: firstState.0, proxyServer: self.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: self.networkType) + let call = PresentationCall(account: self.account, audioSession: self.audioSession, callSessionManager: self.callSessionManager, callKitIntegration: enableCallKit ? callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings?.0) : nil, serializedData: self.callSettings?.1.serializedData, dataSaving: self.callSettings?.0.dataSaving ?? .never, derivedState: self.callSettings?.2 ?? VoipDerivedState.default, getDeviceAccessData: self.getDeviceAccessData, internalId: firstState.1.id, peerId: firstState.1.peerId, isOutgoing: false, peer: firstState.0, proxyServer: self.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: self.networkType) self.currentCall = call self.currentCallPromise.set(.single(call)) self.hasActiveCallsPromise.set(true) @@ -358,7 +359,7 @@ public final class PresentationCallManager { currentCall.rejectBusy() } - let call = PresentationCall(account: strongSelf.account, audioSession: strongSelf.audioSession, callSessionManager: strongSelf.callSessionManager, callKitIntegration: callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings?.0), serializedData: strongSelf.callSettings?.1.serializedData, dataSaving: strongSelf.callSettings?.0.dataSaving ?? .never, getDeviceAccessData: strongSelf.getDeviceAccessData, internalId: internalId, peerId: peerId, isOutgoing: true, peer: nil, proxyServer: strongSelf.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: strongSelf.networkType) + let call = PresentationCall(account: strongSelf.account, audioSession: strongSelf.audioSession, callSessionManager: strongSelf.callSessionManager, callKitIntegration: callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings?.0), serializedData: strongSelf.callSettings?.1.serializedData, dataSaving: strongSelf.callSettings?.0.dataSaving ?? .never, detivedState: strongSelf.callSettings?.2 ?? VoipDerivedState.default, getDeviceAccessData: strongSelf.getDeviceAccessData, internalId: internalId, peerId: peerId, isOutgoing: true, peer: nil, proxyServer: strongSelf.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: strongSelf.networkType) strongSelf.currentCall = call strongSelf.currentCallPromise.set(.single(call)) strongSelf.hasActiveCallsPromise.set(true) diff --git a/TelegramUI/VoipDerivedState.swift b/TelegramUI/VoipDerivedState.swift new file mode 100644 index 0000000000..3e370e7905 --- /dev/null +++ b/TelegramUI/VoipDerivedState.swift @@ -0,0 +1,45 @@ +import Foundation +import Postbox +import SwiftSignalKit + +struct VoipDerivedState: Equatable, PreferencesEntry { + var data: Data + + static var `default`: VoipDerivedState { + return VoipDerivedState(data: Data()) + } + + init(data: Data) { + self.data = data + } + + init(decoder: PostboxDecoder) { + self.data = decoder.decodeDataForKey("data") ?? Data() + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeData(self.data, forKey: "data") + } + + func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? VoipDerivedState { + return self == to + } else { + return false + } + } +} + +func updateVoipDerivedStateInteractively(postbox: Postbox, _ f: @escaping (VoipDerivedState) -> VoipDerivedState) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.voipDerivedState, { entry in + let currentSettings: VoipDerivedState + if let entry = entry as? VoipDerivedState { + currentSettings = entry + } else { + currentSettings = .default + } + return f(currentSettings) + }) + } +}