diff --git a/submodules/Postbox/Sources/MediaBox.swift b/submodules/Postbox/Sources/MediaBox.swift index 014f45c1fd..3a3ff6f109 100644 --- a/submodules/Postbox/Sources/MediaBox.swift +++ b/submodules/Postbox/Sources/MediaBox.swift @@ -1105,4 +1105,22 @@ public final class MediaBox { return EmptyDisposable } } + + + + public func allFileContexts() -> Signal<[(partial: String, complete: String)], NoError> { + return Signal { subscriber in + self.dataQueue.async { + var result: [(partial: String, complete: String)] = [] + for (id, _) in self.fileContexts { + let paths = self.storePathsForId(id.id) + result.append((partial: paths.partial, complete: paths.complete)) + } + subscriber.putNext(result) + subscriber.putCompletion() + } + return EmptyDisposable + } + } + } diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 03959746fe..9aa8835a17 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -1047,7 +1047,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, #if DEBUG //debugSaveState(basePath: basePath, name: "previous1") - debugRestoreState(basePath: basePath, name: "previous1") + //debugRestoreState(basePath: basePath, name: "previous1") #endif let startTime = CFAbsoluteTimeGetCurrent() diff --git a/submodules/SettingsUI/Sources/DebugController.swift b/submodules/SettingsUI/Sources/DebugController.swift index d06d8a8810..bbb4655be9 100644 --- a/submodules/SettingsUI/Sources/DebugController.swift +++ b/submodules/SettingsUI/Sources/DebugController.swift @@ -73,6 +73,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case playerEmbedding(Bool) case playlistPlayback(Bool) case videoCalls(Bool) + case videoCallsReference(Bool) case videoCallsInfo(PresentationTheme, String) case hostInfo(PresentationTheme, String) case versionInfo(PresentationTheme) @@ -89,7 +90,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.experiments.rawValue case .clearTips, .reimport, .resetData, .resetDatabase, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .alternativeFolderTabs, .playerEmbedding, .playlistPlayback: return DebugControllerSection.experiments.rawValue - case .videoCalls, .videoCallsInfo: + case .videoCalls, .videoCallsReference, .videoCallsInfo: return DebugControllerSection.videoExperiments.rawValue case .hostInfo, .versionInfo: return DebugControllerSection.info.rawValue @@ -150,12 +151,14 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 25 case .videoCalls: return 26 - case .videoCallsInfo: + case .videoCallsReference: return 27 - case .hostInfo: + case .videoCallsInfo: return 28 - case .versionInfo: + case .hostInfo: return 29 + case .versionInfo: + return 30 } } @@ -583,6 +586,16 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) }).start() }) + case let .videoCallsReference(value): + return ItemListSwitchItem(presentationData: presentationData, title: "Reference Implementation", value: value, sectionId: self.section, style: .blocks, updated: { value in + let _ = arguments.sharedContext.accountManager.transaction ({ transaction in + transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in + var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + settings.videoCallsReference = value + return settings + }) + }).start() + }) case let .videoCallsInfo(_, text): return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) case let .hostInfo(theme, string): @@ -631,6 +644,9 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS entries.append(.playerEmbedding(experimentalSettings.playerEmbedding)) entries.append(.playlistPlayback(experimentalSettings.playlistPlayback)) entries.append(.videoCalls(experimentalSettings.videoCalls)) + if experimentalSettings.videoCalls { + entries.append(.videoCallsReference(experimentalSettings.videoCallsReference)) + } entries.append(.videoCallsInfo(presentationData.theme, "Enables experimental transmission of electromagnetic radiation synchronized with pressure waves. Needs to be enabled on both sides.")) if let backupHostOverride = networkSettings?.backupHostOverride { diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index b7b01ea222..f23d965608 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -288,9 +288,9 @@ public final class PresentationCallImpl: PresentationCall { self.isVideo = startWithVideo if self.isVideo { self.videoCapturer = OngoingCallVideoCapturer() - self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .outgoingRequested, remoteVideoState: .inactive)) + self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .outgoingRequested, remoteVideoState: .active)) } else { - self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: self.isVideoPossible ? .possible : .notAvailable, remoteVideoState: .inactive)) + self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: self.isVideoPossible ? .possible : .notAvailable, remoteVideoState: .active)) } self.serializedData = serializedData @@ -483,7 +483,7 @@ public final class PresentationCallImpl: PresentationCall { } else { mappedVideoState = .notAvailable } - if videoWasActive { + if self.videoWasActive { mappedRemoteVideoState = .active } else { mappedRemoteVideoState = .inactive diff --git a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift index 07e10639f9..2e46db75d8 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift @@ -117,8 +117,8 @@ public final class PresentationCallManagerImpl: PresentationCallManager { return OngoingCallContext.maxLayer } - public static func voipVersions(includeExperimental: Bool) -> [String] { - return OngoingCallContext.versions(includeExperimental: includeExperimental) + public static func voipVersions(includeExperimental: Bool, includeReference: Bool) -> [String] { + return OngoingCallContext.versions(includeExperimental: includeExperimental, includeReference: includeReference) } public init(accountManager: AccountManager, enableVideoCalls: Bool, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), isMediaPlaying: @escaping () -> Bool, resumeMediaPlayback: @escaping () -> Void, audioSession: ManagedAudioSession, activeAccounts: Signal<[Account], NoError>) { diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index 415122b9be..2831a024c4 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -251,7 +251,7 @@ public final class AccountContextImpl: AccountContext { self.experimentalUISettingsDisposable = (sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> deliverOnMainQueue).start(next: { sharedData in if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings { - account.callSessionManager.updateVersions(versions: PresentationCallManagerImpl.voipVersions(includeExperimental: settings.videoCalls)) + account.callSessionManager.updateVersions(versions: PresentationCallManagerImpl.voipVersions(includeExperimental: settings.videoCalls, includeReference: settings.videoCallsReference)) } }) } diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 46a7105a54..34b6d9f77c 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -401,7 +401,7 @@ final class SharedApplicationContext { } } - let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer, voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: false), appData: self.deviceToken.get() + let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer, voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: false, includeReference: false), appData: self.deviceToken.get() |> map { token in let data = buildConfig.bundleData(withAppToken: token, signatureDict: signatureDict) if let data = data, let jsonString = String(data: data, encoding: .utf8) { diff --git a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift index 53d7c35a41..dfe4522ec2 100644 --- a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift +++ b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift @@ -10,6 +10,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { public var knockoutWallpaper: Bool public var foldersTabAtBottom: Bool public var videoCalls: Bool + public var videoCallsReference: Bool public var playerEmbedding: Bool public var playlistPlayback: Bool @@ -22,6 +23,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { knockoutWallpaper: false, foldersTabAtBottom: false, videoCalls: false, + videoCallsReference: true, playerEmbedding: false, playlistPlayback: false ) @@ -35,6 +37,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { knockoutWallpaper: Bool, foldersTabAtBottom: Bool, videoCalls: Bool, + videoCallsReference: Bool, playerEmbedding: Bool, playlistPlayback: Bool ) { @@ -45,6 +48,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { self.knockoutWallpaper = knockoutWallpaper self.foldersTabAtBottom = foldersTabAtBottom self.videoCalls = videoCalls + self.videoCallsReference = videoCallsReference self.playerEmbedding = playerEmbedding self.playlistPlayback = playlistPlayback } @@ -57,6 +61,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { self.knockoutWallpaper = decoder.decodeInt32ForKey("knockoutWallpaper", orElse: 0) != 0 self.foldersTabAtBottom = decoder.decodeInt32ForKey("foldersTabAtBottom", orElse: 0) != 0 self.videoCalls = decoder.decodeInt32ForKey("videoCalls", orElse: 0) != 0 + self.videoCallsReference = decoder.decodeInt32ForKey("videoCallsReference", orElse: 1) != 0 self.playerEmbedding = decoder.decodeInt32ForKey("playerEmbedding", orElse: 0) != 0 self.playlistPlayback = decoder.decodeInt32ForKey("playlistPlayback", orElse: 0) != 0 } @@ -69,6 +74,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry { encoder.encodeInt32(self.knockoutWallpaper ? 1 : 0, forKey: "knockoutWallpaper") encoder.encodeInt32(self.foldersTabAtBottom ? 1 : 0, forKey: "foldersTabAtBottom") encoder.encodeInt32(self.videoCalls ? 1 : 0, forKey: "videoCalls") + encoder.encodeInt32(self.videoCallsReference ? 1 : 0, forKey: "videoCallsReference") encoder.encodeInt32(self.playerEmbedding ? 1 : 0, forKey: "playerEmbedding") encoder.encodeInt32(self.playlistPlayback ? 1 : 0, forKey: "playlistPlayback") } diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 5665d5d782..decd2602b9 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -248,6 +248,7 @@ private protocol OngoingCallThreadLocalContextProtocol: class { func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) func nativeAcceptVideo(_ capturer: OngoingCallVideoCapturer) func nativeStop(_ completion: @escaping (String?, Int64, Int64, Int64, Int64) -> Void) + func nativeBeginTermination() func nativeDebugInfo() -> String func nativeVersion() -> String func nativeGetDerivedState() -> Data @@ -270,6 +271,9 @@ extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol { self.stop(completion) } + func nativeBeginTermination() { + } + func nativeSetIsMuted(_ value: Bool) { self.setIsMuted(value) } @@ -336,6 +340,10 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt self.stop(completion) } + func nativeBeginTermination() { + self.beginTermination() + } + func nativeSetIsMuted(_ value: Bool) { self.setIsMuted(value) } @@ -458,14 +466,12 @@ public final class OngoingCallContext { public static var maxLayer: Int32 { return OngoingCallThreadLocalContext.maxLayer() - //return max(OngoingCallThreadLocalContext.maxLayer(), OngoingCallThreadLocalContextWebrtc.maxLayer()) } - public static func versions(includeExperimental: Bool) -> [String] { + public static func versions(includeExperimental: Bool, includeReference: Bool) -> [String] { var result: [String] = [OngoingCallThreadLocalContext.version()] if includeExperimental { - result.append(OngoingCallThreadLocalContextWebrtc.version()) - //result.append(OngoingCallThreadLocalContextWebrtcCustom.version()) + result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: includeReference)) } return result } @@ -489,7 +495,7 @@ public final class OngoingCallContext { |> take(1) |> deliverOn(queue)).start(next: { [weak self] _ in if let strongSelf = self { - if version == OngoingCallThreadLocalContextWebrtc.version() { + if OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: true).contains(version) { var voipProxyServer: VoipProxyServerWebrtc? if let proxyServer = proxyServer { switch proxyServer.connection { @@ -520,7 +526,7 @@ public final class OngoingCallContext { )) } } - let context = OngoingCallThreadLocalContextWebrtc(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, rtcServers: rtcServers, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtc(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtc), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in + let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, rtcServers: rtcServers, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtc(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtc), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in callSessionManager?.sendSignalingData(internalId: internalId, data: data) }, videoCapturer: video?.impl) @@ -631,6 +637,12 @@ public final class OngoingCallContext { } } + public func beginTermination() { + self.withContext { context in + context.nativeBeginTermination() + } + } + public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise) { let account = self.account let logPath = self.logPath diff --git a/submodules/TgVoipWebrtc/Impl/NetworkManager.cpp b/submodules/TgVoipWebrtc/Impl/NetworkManager.cpp deleted file mode 100644 index ab12e6855e..0000000000 --- a/submodules/TgVoipWebrtc/Impl/NetworkManager.cpp +++ /dev/null @@ -1,353 +0,0 @@ -#include "NetworkManager.h" - -#include "p2p/base/basic_packet_socket_factory.h" -#include "p2p/client/basic_port_allocator.h" -#include "p2p/base/p2p_transport_channel.h" -#include "p2p/base/basic_async_resolver_factory.h" -#include "api/packet_socket_factory.h" -#include "rtc_base/task_utils/to_queued_task.h" -#include "p2p/base/ice_credentials_iterator.h" -#include "api/jsep_ice_candidate.h" - -extern "C" { -#include -#include -#include -#include -#include -} - -#ifdef TGVOIP_NAMESPACE -namespace TGVOIP_NAMESPACE { -#endif - -static void KDF2(unsigned char *encryptionKey, unsigned char *msgKey, size_t x, unsigned char *aesKey, unsigned char *aesIv) { - uint8_t sA[32], sB[32]; - uint8_t buf[16 + 36]; - memcpy(buf, msgKey, 16); - memcpy(buf + 16, encryptionKey + x, 36); - SHA256(buf, 16 + 36, sA); - memcpy(buf, encryptionKey + 40 + x, 36); - memcpy(buf + 36, msgKey, 16); - SHA256(buf, 36 + 16, sB); - memcpy(aesKey, sA, 8); - memcpy(aesKey + 8, sB + 8, 16); - memcpy(aesKey + 8 + 16, sA + 24, 8); - memcpy(aesIv, sB, 8); - memcpy(aesIv + 8, sA + 8, 16); - memcpy(aesIv + 8 + 16, sB + 24, 8); -} - -static void aesIgeEncrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { - AES_KEY akey; - AES_set_encrypt_key(key, 32*8, &akey); - AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT); -} - -static void aesIgeDecrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { - AES_KEY akey; - AES_set_decrypt_key(key, 32*8, &akey); - AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT); -} - -static absl::optional decryptPacket(const rtc::CopyOnWriteBuffer &packet, const TgVoipEncryptionKey &encryptionKey) { - if (packet.size() < 16 + 16) { - return absl::nullopt; - } - unsigned char msgKey[16]; - memcpy(msgKey, packet.data(), 16); - - int x = encryptionKey.isOutgoing ? 8 : 0; - - unsigned char aesKey[32]; - unsigned char aesIv[32]; - KDF2((unsigned char *)encryptionKey.value.data(), msgKey, x, aesKey, aesIv); - size_t decryptedSize = packet.size() - 16; - if (decryptedSize < 0 || decryptedSize > 128 * 1024) { - return absl::nullopt; - } - if (decryptedSize % 16 != 0) { - return absl::nullopt; - } - rtc::Buffer decryptionBuffer(decryptedSize); - aesIgeDecrypt(((uint8_t *)packet.data()) + 16, decryptionBuffer.begin(), decryptionBuffer.size(), aesKey, aesIv); - - rtc::ByteBufferWriter msgKeyData; - msgKeyData.WriteBytes((const char *)encryptionKey.value.data() + 88 + x, 32); - msgKeyData.WriteBytes((const char *)decryptionBuffer.data(), decryptionBuffer.size()); - unsigned char msgKeyLarge[32]; - SHA256((uint8_t *)msgKeyData.Data(), msgKeyData.Length(), msgKeyLarge); - - uint16_t innerSize; - memcpy(&innerSize, decryptionBuffer.data(), 2); - - unsigned char checkMsgKey[16]; - memcpy(checkMsgKey, msgKeyLarge + 8, 16); - - if (memcmp(checkMsgKey, msgKey, 16) != 0) { - return absl::nullopt; - } - - if (innerSize < 0 || innerSize > decryptionBuffer.size() - 2) { - return absl::nullopt; - } - - rtc::CopyOnWriteBuffer decryptedPacket; - decryptedPacket.AppendData((const char *)decryptionBuffer.data() + 2, innerSize); - return decryptedPacket; -} - -static absl::optional encryptPacket(const rtc::CopyOnWriteBuffer &packet, const TgVoipEncryptionKey &encryptionKey) { - if (packet.size() > UINT16_MAX) { - return absl::nullopt; - } - - rtc::ByteBufferWriter innerData; - uint16_t packetSize = (uint16_t)packet.size(); - innerData.WriteBytes((const char *)&packetSize, 2); - innerData.WriteBytes((const char *)packet.data(), packet.size()); - - size_t innerPadding = 16 - innerData.Length() % 16; - uint8_t paddingData[16]; - RAND_bytes(paddingData, (int)innerPadding); - innerData.WriteBytes((const char *)paddingData, innerPadding); - - if (innerData.Length() % 16 != 0) { - assert(false); - return absl::nullopt; - } - - int x = encryptionKey.isOutgoing ? 0 : 8; - - rtc::ByteBufferWriter msgKeyData; - msgKeyData.WriteBytes((const char *)encryptionKey.value.data() + 88 + x, 32); - msgKeyData.WriteBytes(innerData.Data(), innerData.Length()); - unsigned char msgKeyLarge[32]; - SHA256((uint8_t *)msgKeyData.Data(), msgKeyData.Length(), msgKeyLarge); - - unsigned char msgKey[16]; - memcpy(msgKey, msgKeyLarge + 8, 16); - - unsigned char aesKey[32]; - unsigned char aesIv[32]; - KDF2((unsigned char *)encryptionKey.value.data(), msgKey, x, aesKey, aesIv); - - rtc::Buffer encryptedPacket; - encryptedPacket.AppendData((const char *)msgKey, 16); - - rtc::Buffer encryptionBuffer(innerData.Length()); - aesIgeEncrypt((uint8_t *)innerData.Data(), encryptionBuffer.begin(), innerData.Length(), aesKey, aesIv); - - encryptedPacket.AppendData(encryptionBuffer.begin(), encryptionBuffer.size()); - - /*rtc::CopyOnWriteBuffer testBuffer; - testBuffer.AppendData(encryptedPacket.data(), encryptedPacket.size()); - TgVoipEncryptionKey testKey; - testKey.value = encryptionKey.value; - testKey.isOutgoing = !encryptionKey.isOutgoing; - decryptPacket(testBuffer, testKey);*/ - - return encryptedPacket; -} - -NetworkManager::NetworkManager( - rtc::Thread *thread, - TgVoipEncryptionKey encryptionKey, - bool enableP2P, - std::vector const &rtcServers, - std::function stateUpdated, - std::function packetReceived, - std::function &)> signalingDataEmitted -) : -_thread(thread), -_encryptionKey(encryptionKey), -_stateUpdated(stateUpdated), -_packetReceived(packetReceived), -_signalingDataEmitted(signalingDataEmitted) { - assert(_thread->IsCurrent()); - - _socketFactory.reset(new rtc::BasicPacketSocketFactory(_thread)); - - _networkManager = std::make_unique(); - _portAllocator.reset(new cricket::BasicPortAllocator(_networkManager.get(), _socketFactory.get(), nullptr, nullptr)); - - uint32_t flags = cricket::PORTALLOCATOR_DISABLE_TCP; - if (!enableP2P) { - flags |= cricket::PORTALLOCATOR_DISABLE_UDP; - flags |= cricket::PORTALLOCATOR_DISABLE_STUN; - } - _portAllocator->set_flags(_portAllocator->flags() | flags); - _portAllocator->Initialize(); - - cricket::ServerAddresses stunServers; - std::vector turnServers; - - if (rtcServers.size() == 0 || rtcServers[0].host == "hlgkfjdrtjfykgulhijkljhulyo.uksouth.cloudapp.azure.com") { - rtc::SocketAddress defaultStunAddress = rtc::SocketAddress("134.122.52.178", 3478); - stunServers.insert(defaultStunAddress); - - turnServers.push_back(cricket::RelayServerConfig( - rtc::SocketAddress("134.122.52.178", 3478), - "openrelay", - "openrelay", - cricket::PROTO_UDP - )); - } else { - for (auto &server : rtcServers) { - if (server.isTurn) { - turnServers.push_back(cricket::RelayServerConfig( - rtc::SocketAddress(server.host, server.port), - server.login, - server.password, - cricket::PROTO_UDP - )); - } else { - rtc::SocketAddress stunAddress = rtc::SocketAddress(server.host, server.port); - stunServers.insert(stunAddress); - } - } - } - - _portAllocator->SetConfiguration(stunServers, turnServers, 2, webrtc::NO_PRUNE); - - _asyncResolverFactory = std::make_unique(); - _transportChannel.reset(new cricket::P2PTransportChannel("transport", 0, _portAllocator.get(), _asyncResolverFactory.get(), nullptr)); - - cricket::IceConfig iceConfig; - iceConfig.continual_gathering_policy = cricket::GATHER_CONTINUALLY; - _transportChannel->SetIceConfig(iceConfig); - - cricket::IceParameters localIceParameters( - "gcp3", - "zWDKozH8/3JWt8he3M/CMj5R", - false - ); - cricket::IceParameters remoteIceParameters( - "acp3", - "aWDKozH8/3JWt8he3M/CMj5R", - false - ); - - _transportChannel->SetIceParameters(_encryptionKey.isOutgoing ? localIceParameters : remoteIceParameters); - _transportChannel->SetIceRole(_encryptionKey.isOutgoing ? cricket::ICEROLE_CONTROLLING : cricket::ICEROLE_CONTROLLED); - - _transportChannel->SignalCandidateGathered.connect(this, &NetworkManager::candidateGathered); - _transportChannel->SignalGatheringState.connect(this, &NetworkManager::candidateGatheringState); - _transportChannel->SignalIceTransportStateChanged.connect(this, &NetworkManager::transportStateChanged); - _transportChannel->SignalReadPacket.connect(this, &NetworkManager::transportPacketReceived); - - _transportChannel->MaybeStartGathering(); - - _transportChannel->SetRemoteIceMode(cricket::ICEMODE_FULL); - _transportChannel->SetRemoteIceParameters((!_encryptionKey.isOutgoing) ? localIceParameters : remoteIceParameters); -} - -NetworkManager::~NetworkManager() { - assert(_thread->IsCurrent()); - - _transportChannel.reset(); - _asyncResolverFactory.reset(); - _portAllocator.reset(); - _networkManager.reset(); - _socketFactory.reset(); -} - -void NetworkManager::receiveSignalingData(const rtc::CopyOnWriteBuffer &data) { - rtc::ByteBufferReader reader((const char *)data.data(), data.size()); - uint32_t candidateCount = 0; - if (!reader.ReadUInt32(&candidateCount)) { - return; - } - std::vector candidates; - for (uint32_t i = 0; i < candidateCount; i++) { - uint32_t candidateLength = 0; - if (!reader.ReadUInt32(&candidateLength)) { - return; - } - std::string candidate; - if (!reader.ReadString(&candidate, candidateLength)) { - return; - } - candidates.push_back(candidate); - } - - for (auto &serializedCandidate : candidates) { - webrtc::JsepIceCandidate parseCandidate("", 0); - if (parseCandidate.Initialize(serializedCandidate, nullptr)) { - auto parsedCandidate = parseCandidate.candidate(); - _transportChannel->AddRemoteCandidate(parsedCandidate); - } - } -} - -void NetworkManager::sendPacket(const rtc::CopyOnWriteBuffer &packet) { - auto encryptedPacket = encryptPacket(packet, _encryptionKey); - if (encryptedPacket.has_value()) { - rtc::PacketOptions packetOptions; - _transportChannel->SendPacket((const char *)encryptedPacket->data(), encryptedPacket->size(), packetOptions, 0); - } -} - -void NetworkManager::candidateGathered(cricket::IceTransportInternal *transport, const cricket::Candidate &candidate) { - assert(_thread->IsCurrent()); - webrtc::JsepIceCandidate iceCandidate("", 0); - iceCandidate.SetCandidate(candidate); - std::string serializedCandidate; - if (!iceCandidate.ToString(&serializedCandidate)) { - return; - } - std::vector candidates; - candidates.push_back(serializedCandidate); - - rtc::ByteBufferWriter writer; - writer.WriteUInt32((uint32_t)candidates.size()); - for (auto string : candidates) { - writer.WriteUInt32((uint32_t)string.size()); - writer.WriteString(string); - } - std::vector data; - data.resize(writer.Length()); - memcpy(data.data(), writer.Data(), writer.Length()); - _signalingDataEmitted(data); -} - -void NetworkManager::candidateGatheringState(cricket::IceTransportInternal *transport) { - assert(_thread->IsCurrent()); -} - -void NetworkManager::transportStateChanged(cricket::IceTransportInternal *transport) { - assert(_thread->IsCurrent()); - - auto state = transport->GetIceTransportState(); - bool isConnected = false; - switch (state) { - case webrtc::IceTransportState::kConnected: - case webrtc::IceTransportState::kCompleted: - isConnected = true; - break; - default: - break; - } - NetworkManager::State emitState; - emitState.isReadyToSendData = isConnected; - _stateUpdated(emitState); -} - -void NetworkManager::transportReadyToSend(cricket::IceTransportInternal *transport) { - assert(_thread->IsCurrent()); -} - -void NetworkManager::transportPacketReceived(rtc::PacketTransportInternal *transport, const char *bytes, size_t size, const int64_t ×tamp, int unused) { - assert(_thread->IsCurrent()); - rtc::CopyOnWriteBuffer packet; - packet.AppendData(bytes, size); - - auto decryptedPacket = decryptPacket(packet, _encryptionKey); - if (decryptedPacket.has_value()) { - _packetReceived(decryptedPacket.value()); - } -} - -#ifdef TGVOIP_NAMESPACE -} -#endif diff --git a/submodules/TgVoipWebrtc/PublicHeaders/TgVoip/OngoingCallThreadLocalContext.h b/submodules/TgVoipWebrtc/PublicHeaders/TgVoip/OngoingCallThreadLocalContext.h index 7915abba8b..aa26669cba 100644 --- a/submodules/TgVoipWebrtc/PublicHeaders/TgVoip/OngoingCallThreadLocalContext.h +++ b/submodules/TgVoipWebrtc/PublicHeaders/TgVoip/OngoingCallThreadLocalContext.h @@ -107,12 +107,14 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) { + (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction; + (void)applyServerConfig:(NSString * _Nullable)data; + (int32_t)maxLayer; -+ (NSString * _Nonnull)version; ++ (NSArray * _Nonnull)versionsWithIncludeReference:(bool)includeReference; @property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallStateWebrtc, OngoingCallVideoStateWebrtc, OngoingCallRemoteVideoStateWebrtc); @property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t); -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer; +- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer; + +- (void)beginTermination; - (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion; - (bool)needRate; diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 53d28d7bde..6cc65df000 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -7,6 +7,8 @@ #import "Instance.h" #import "InstanceImpl.h" +#import "reference/InstanceImplReference.h" + #import "VideoCaptureInterface.h" #ifndef WEBRTC_IOS @@ -102,7 +104,26 @@ @end +@interface OngoingCallThreadLocalContextWebrtcTerminationResult : NSObject + +@property (nonatomic, readonly) tgcalls::FinalState finalState; + +@end + +@implementation OngoingCallThreadLocalContextWebrtcTerminationResult + +- (instancetype)initWithFinalState:(tgcalls::FinalState)finalState { + self = [super init]; + if (self != nil) { + _finalState = finalState; + } + return self; +} + +@end + @interface OngoingCallThreadLocalContextWebrtc () { + NSString *_version; id _queue; int32_t _contextId; @@ -113,6 +134,7 @@ NSTimeInterval _callPacketTimeout; std::unique_ptr _tgVoip; + OngoingCallThreadLocalContextWebrtcTerminationResult *_terminationResult; OngoingCallStateWebrtc _state; OngoingCallVideoStateWebrtc _videoState; @@ -213,16 +235,23 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; return 92; } -+ (NSString *)version { - return @"2.7.7"; ++ (NSArray * _Nonnull)versionsWithIncludeReference:(bool)includeReference { + if (includeReference) { + return @[@"2.7.7", @"2.8.8"]; + } else { + return @[@"2.7.7"]; + } } -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer { +- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer { self = [super init]; if (self != nil) { + _version = version; _queue = queue; assert([queue isCurrent]); + assert([[OngoingCallThreadLocalContextWebrtc versionsWithIncludeReference:true] containsObject:version]); + _callReceiveTimeout = 20.0; _callRingTimeout = 90.0; _callConnectTimeout = 30.0; @@ -235,7 +264,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; _remoteVideoState = OngoingCallRemoteVideoStateActive; } else { _videoState = OngoingCallVideoStatePossible; - _remoteVideoState = OngoingCallRemoteVideoStateInactive; + _remoteVideoState = OngoingCallRemoteVideoStateActive; } std::vector derivedStateValue; @@ -302,9 +331,8 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; .maxApiLayer = [OngoingCallThreadLocalContextWebrtc maxLayer] }; - std::vector encryptionKeyValue; - encryptionKeyValue.resize(key.length); - memcpy(encryptionKeyValue.data(), key.bytes, key.length); + auto encryptionKeyValue = std::make_shared>(); + memcpy(encryptionKeyValue->data(), key.bytes, key.length); tgcalls::EncryptionKey encryptionKey(encryptionKeyValue, isOutgoing); @@ -312,8 +340,9 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ tgcalls::Register(); + tgcalls::Register(); }); - _tgVoip = tgcalls::Meta::Create("2.7.7", (tgcalls::Descriptor){ + _tgVoip = tgcalls::Meta::Create([version UTF8String], (tgcalls::Descriptor){ .config = config, .persistentState = (tgcalls::PersistentState){ derivedStateValue }, .endpoints = endpoints, @@ -346,8 +375,16 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; } }]; }, - .signalBarsUpdated = [](int value) { - + .signalBarsUpdated = [weakSelf, queue](int value) { + [queue dispatch:^{ + __strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_signalBars = value; + if (strongSelf->_signalBarsChanged) { + strongSelf->_signalBarsChanged(value); + } + } + }]; }, .remoteVideoIsActiveUpdated = [weakSelf, queue](bool isActive) { [queue dispatch:^{ @@ -396,15 +433,34 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; return false; } +- (void)stopInstanceIfNeeded { + if (!_tgVoip) { + return; + } + tgcalls::FinalState finalState = _tgVoip->stop(); + _tgVoip = nil; + _terminationResult = [[OngoingCallThreadLocalContextWebrtcTerminationResult alloc] initWithFinalState:finalState]; +} + +- (void)beginTermination { + [self stopInstanceIfNeeded]; +} + - (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion { - if (_tgVoip) { - tgcalls::FinalState finalState = _tgVoip->stop(); - - NSString *debugLog = [NSString stringWithUTF8String:finalState.debugLog.c_str()]; - _lastDerivedState = [[NSData alloc] initWithBytes:finalState.persistentState.value.data() length:finalState.persistentState.value.size()]; - - if (completion) { - completion(debugLog, finalState.trafficStats.bytesSentWifi, finalState.trafficStats.bytesReceivedWifi, finalState.trafficStats.bytesSentMobile, finalState.trafficStats.bytesReceivedMobile); + [self stopInstanceIfNeeded]; + + if (completion) { + if (_terminationResult) { + NSString *debugLog = [NSString stringWithUTF8String:_terminationResult.finalState.debugLog.c_str()]; + _lastDerivedState = [[NSData alloc] initWithBytes:_terminationResult.finalState.persistentState.value.data() length:_terminationResult.finalState.persistentState.value.size()]; + + if (completion) { + completion(debugLog, _terminationResult.finalState.trafficStats.bytesSentWifi, _terminationResult.finalState.trafficStats.bytesReceivedWifi, _terminationResult.finalState.trafficStats.bytesSentMobile, _terminationResult.finalState.trafficStats.bytesReceivedMobile); + } + } else { + if (completion) { + completion(@"", 0, 0, 0, 0); + } } } } @@ -421,7 +477,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; } - (NSString *)version { - return @"2.7.7"; + return _version; } - (NSData * _Nonnull)getDerivedState { diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 83c85d20cc..8e9d3e56d4 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 83c85d20ccdde154acca4b964317de1e695f95d1 +Subproject commit 8e9d3e56d43ffa4ed9ababd5fe7a4b5df8ec94d1