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/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/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 5665d5d782..05f0d10e4c 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] { var result: [String] = [OngoingCallThreadLocalContext.version()] if includeExperimental { - result.append(OngoingCallThreadLocalContextWebrtc.version()) - //result.append(OngoingCallThreadLocalContextWebrtcCustom.version()) + result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions()) } 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().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..ccfbb751fa 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)versions; @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..9d5074d98a 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,19 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; return 92; } -+ (NSString *)version { - return @"2.7.7"; ++ (NSArray * _Nonnull)versions { + return @[@"2.7.7", @"2.8.8"]; } -- (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 versions] containsObject:version]); + _callReceiveTimeout = 20.0; _callRingTimeout = 90.0; _callConnectTimeout = 30.0; @@ -235,7 +260,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; _remoteVideoState = OngoingCallRemoteVideoStateActive; } else { _videoState = OngoingCallVideoStatePossible; - _remoteVideoState = OngoingCallRemoteVideoStateInactive; + _remoteVideoState = OngoingCallRemoteVideoStateActive; } std::vector derivedStateValue; @@ -312,8 +337,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 +372,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 +430,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 +474,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..a022072ed3 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 83c85d20ccdde154acca4b964317de1e695f95d1 +Subproject commit a022072ed3f57f4cd4ec42c088f5baad8dfdd7c4