mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge remote-tracking branch 'origin/tgvoip-api' into tgvoip-webrtc
This commit is contained in:
commit
16539d5f69
3
.bazelrc
3
.bazelrc
@ -4,9 +4,6 @@ build --action_env=ZERO_AR_DATE=1
|
|||||||
build --strategy=Genrule=local
|
build --strategy=Genrule=local
|
||||||
build --apple_platform_type=ios
|
build --apple_platform_type=ios
|
||||||
build --cxxopt='-std=c++14'
|
build --cxxopt='-std=c++14'
|
||||||
build --copt='-w'
|
|
||||||
build --swiftcopt='-Xcc'
|
|
||||||
build --swiftcopt='-w'
|
|
||||||
build --spawn_strategy=local
|
build --spawn_strategy=local
|
||||||
build --strategy=SwiftCompile=local
|
build --strategy=SwiftCompile=local
|
||||||
build --features=debug_prefix_map_pwd_is_dot
|
build --features=debug_prefix_map_pwd_is_dot
|
||||||
|
@ -167,9 +167,16 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
public let isOutgoing: Bool
|
public let isOutgoing: Bool
|
||||||
public let peer: Peer?
|
public let peer: Peer?
|
||||||
|
|
||||||
|
private let serializedData: String?
|
||||||
|
private let dataSaving: VoiceCallDataSaving
|
||||||
|
private let derivedState: VoipDerivedState
|
||||||
|
private let proxyServer: ProxyServerSettings?
|
||||||
|
private let currentNetworkType: NetworkType
|
||||||
|
private let updatedNetworkType: Signal<NetworkType, NoError>
|
||||||
|
|
||||||
private var sessionState: CallSession?
|
private var sessionState: CallSession?
|
||||||
private var callContextState: OngoingCallContextState?
|
private var callContextState: OngoingCallContextState?
|
||||||
private var ongoingContext: OngoingCallContext
|
private var ongoingContext: OngoingCallContext?
|
||||||
private var ongoingContextStateDisposable: Disposable?
|
private var ongoingContextStateDisposable: Disposable?
|
||||||
private var reception: Int32?
|
private var reception: Int32?
|
||||||
private var receptionDisposable: Disposable?
|
private var receptionDisposable: Disposable?
|
||||||
@ -198,6 +205,8 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
return self.audioOutputStatePromise.get()
|
return self.audioOutputStatePromise.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let debugInfoValue = Promise<(String, String)>(("", ""))
|
||||||
|
|
||||||
private let canBeRemovedPromise = Promise<Bool>(false)
|
private let canBeRemovedPromise = Promise<Bool>(false)
|
||||||
private var didSetCanBeRemoved = false
|
private var didSetCanBeRemoved = false
|
||||||
public var canBeRemoved: Signal<Bool, NoError> {
|
public var canBeRemoved: Signal<Bool, NoError> {
|
||||||
@ -233,7 +242,12 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.isOutgoing = isOutgoing
|
self.isOutgoing = isOutgoing
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
|
|
||||||
self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType, serializedData: serializedData, dataSaving: dataSaving, derivedState: derivedState)
|
self.serializedData = serializedData
|
||||||
|
self.dataSaving = dataSaving
|
||||||
|
self.derivedState = derivedState
|
||||||
|
self.proxyServer = proxyServer
|
||||||
|
self.currentNetworkType = currentNetworkType
|
||||||
|
self.updatedNetworkType = updatedNetworkType
|
||||||
|
|
||||||
var didReceiveAudioOutputs = false
|
var didReceiveAudioOutputs = false
|
||||||
|
|
||||||
@ -251,28 +265,6 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.ongoingContextStateDisposable = (self.ongoingContext.state
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] contextState in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if let sessionState = strongSelf.sessionState {
|
|
||||||
strongSelf.updateSessionState(sessionState: sessionState, callContextState: contextState, reception: strongSelf.reception, audioSessionControl: strongSelf.audioSessionControl)
|
|
||||||
} else {
|
|
||||||
strongSelf.callContextState = contextState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.receptionDisposable = (self.ongoingContext.reception
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] reception in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if let sessionState = strongSelf.sessionState {
|
|
||||||
strongSelf.updateSessionState(sessionState: sessionState, callContextState: strongSelf.callContextState, reception: reception, audioSessionControl: strongSelf.audioSessionControl)
|
|
||||||
} else {
|
|
||||||
strongSelf.reception = reception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in
|
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -485,7 +477,34 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
if let _ = audioSessionControl, !wasActive || previousControl == nil {
|
if let _ = audioSessionControl, !wasActive || previousControl == nil {
|
||||||
let logName = "\(id.id)_\(id.accessHash)"
|
let logName = "\(id.id)_\(id.accessHash)"
|
||||||
self.ongoingContext.start(key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get(), logName: logName)
|
|
||||||
|
let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get(), logName: logName)
|
||||||
|
self.ongoingContext = ongoingContext
|
||||||
|
|
||||||
|
self.debugInfoValue.set(ongoingContext.debugInfo())
|
||||||
|
|
||||||
|
self.ongoingContextStateDisposable = (ongoingContext.state
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] contextState in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let sessionState = strongSelf.sessionState {
|
||||||
|
strongSelf.updateSessionState(sessionState: sessionState, callContextState: contextState, reception: strongSelf.reception, audioSessionControl: strongSelf.audioSessionControl)
|
||||||
|
} else {
|
||||||
|
strongSelf.callContextState = contextState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.receptionDisposable = (ongoingContext.reception
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] reception in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let sessionState = strongSelf.sessionState {
|
||||||
|
strongSelf.updateSessionState(sessionState: sessionState, callContextState: strongSelf.callContextState, reception: reception, audioSessionControl: strongSelf.audioSessionControl)
|
||||||
|
} else {
|
||||||
|
strongSelf.reception = reception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if sessionState.isOutgoing {
|
if sessionState.isOutgoing {
|
||||||
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
||||||
}
|
}
|
||||||
@ -494,13 +513,13 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
if wasActive {
|
if wasActive {
|
||||||
let debugLogValue = Promise<String?>()
|
let debugLogValue = Promise<String?>()
|
||||||
self.ongoingContext.stop(callId: id, sendDebugLogs: options.contains(.sendDebugLogs), debugLogValue: debugLogValue)
|
self.ongoingContext?.stop(callId: id, sendDebugLogs: options.contains(.sendDebugLogs), debugLogValue: debugLogValue)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
self.audioSessionShouldBeActive.set(false)
|
self.audioSessionShouldBeActive.set(false)
|
||||||
if wasActive {
|
if wasActive {
|
||||||
let debugLogValue = Promise<String?>()
|
let debugLogValue = Promise<String?>()
|
||||||
self.ongoingContext.stop(debugLogValue: debugLogValue)
|
self.ongoingContext?.stop(debugLogValue: debugLogValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if case .terminated = sessionState.state, !wasTerminated {
|
if case .terminated = sessionState.state, !wasTerminated {
|
||||||
@ -531,12 +550,6 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.statePromise.set(presentationState)
|
self.statePromise.set(presentationState)
|
||||||
self.updateTone(presentationState, callContextState: callContextState, previous: previous)
|
self.updateTone(presentationState, callContextState: callContextState, previous: previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.shouldPresentCallRating {
|
|
||||||
self.ongoingContext.needsRating { needsRating in
|
|
||||||
self.shouldPresentCallRating = needsRating
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateTone(_ state: PresentationCallState, callContextState: OngoingCallContextState?, previous: CallSession?) {
|
private func updateTone(_ state: PresentationCallState, callContextState: OngoingCallContextState?, previous: CallSession?) {
|
||||||
@ -617,7 +630,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
public func hangUp() -> Signal<Bool, NoError> {
|
public func hangUp() -> Signal<Bool, NoError> {
|
||||||
let debugLogValue = Promise<String?>()
|
let debugLogValue = Promise<String?>()
|
||||||
self.callSessionManager.drop(internalId: self.internalId, reason: .hangUp, debugLog: debugLogValue.get())
|
self.callSessionManager.drop(internalId: self.internalId, reason: .hangUp, debugLog: debugLogValue.get())
|
||||||
self.ongoingContext.stop(debugLogValue: debugLogValue)
|
self.ongoingContext?.stop(debugLogValue: debugLogValue)
|
||||||
|
|
||||||
return self.hungUpPromise.get()
|
return self.hungUpPromise.get()
|
||||||
}
|
}
|
||||||
@ -625,7 +638,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
public func rejectBusy() {
|
public func rejectBusy() {
|
||||||
self.callSessionManager.drop(internalId: self.internalId, reason: .busy, debugLog: .single(nil))
|
self.callSessionManager.drop(internalId: self.internalId, reason: .busy, debugLog: .single(nil))
|
||||||
let debugLog = Promise<String?>()
|
let debugLog = Promise<String?>()
|
||||||
self.ongoingContext.stop(debugLogValue: debugLog)
|
self.ongoingContext?.stop(debugLogValue: debugLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func toggleIsMuted() {
|
public func toggleIsMuted() {
|
||||||
@ -635,7 +648,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
public func setIsMuted(_ value: Bool) {
|
public func setIsMuted(_ value: Bool) {
|
||||||
self.isMutedValue = value
|
self.isMutedValue = value
|
||||||
self.isMutedPromise.set(self.isMutedValue)
|
self.isMutedPromise.set(self.isMutedValue)
|
||||||
self.ongoingContext.setIsMuted(self.isMutedValue)
|
self.ongoingContext?.setIsMuted(self.isMutedValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
||||||
@ -656,6 +669,6 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func debugInfo() -> Signal<(String, String), NoError> {
|
public func debugInfo() -> Signal<(String, String), NoError> {
|
||||||
return self.ongoingContext.debugInfo()
|
return self.debugInfoValue.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,12 +172,12 @@ public final class OngoingCallContext {
|
|||||||
public static var maxLayer: Int32 {
|
public static var maxLayer: Int32 {
|
||||||
return OngoingCallThreadLocalContext.maxLayer()
|
return OngoingCallThreadLocalContext.maxLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var version: String {
|
public static var version: String {
|
||||||
return OngoingCallThreadLocalContext.version()!
|
return OngoingCallThreadLocalContext.version()
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState) {
|
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String) {
|
||||||
let _ = setupLogs
|
let _ = setupLogs
|
||||||
OngoingCallThreadLocalContext.applyServerConfig(serializedData)
|
OngoingCallThreadLocalContext.applyServerConfig(serializedData)
|
||||||
|
|
||||||
@ -186,34 +186,42 @@ public final class OngoingCallContext {
|
|||||||
self.callSessionManager = callSessionManager
|
self.callSessionManager = callSessionManager
|
||||||
|
|
||||||
let queue = self.queue
|
let queue = self.queue
|
||||||
self.queue.async {
|
|
||||||
var voipProxyServer: VoipProxyServer?
|
cleanupCallLogs(account: account)
|
||||||
if let proxyServer = proxyServer {
|
|
||||||
switch proxyServer.connection {
|
let logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log"
|
||||||
|
self.audioSessionDisposable.set((audioSessionActive
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOn(queue)).start(next: { [weak self] _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
var voipProxyServer: VoipProxyServer?
|
||||||
|
if let proxyServer = proxyServer {
|
||||||
|
switch proxyServer.connection {
|
||||||
case let .socks5(username, password):
|
case let .socks5(username, password):
|
||||||
voipProxyServer = VoipProxyServer(host: proxyServer.host, port: proxyServer.port, username: username, password: password)
|
voipProxyServer = VoipProxyServer(host: proxyServer.host, port: proxyServer.port, username: username, password: password)
|
||||||
case .mtp:
|
case .mtp:
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
|
||||||
|
|
||||||
|
strongSelf.contextRef = Unmanaged.passRetained(context)
|
||||||
|
context.stateChanged = { state in
|
||||||
|
self?.contextState.set(.single(state))
|
||||||
|
}
|
||||||
|
context.signalBarsChanged = { signalBars in
|
||||||
|
self?.receptionPromise.set(.single(signalBars))
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.networkTypeDisposable = (updatedNetworkType
|
||||||
|
|> deliverOn(queue)).start(next: { networkType in
|
||||||
|
self?.withContext { context in
|
||||||
|
context.setNetworkType(ongoingNetworkTypeForType(networkType))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data)
|
}))
|
||||||
self.contextRef = Unmanaged.passRetained(context)
|
|
||||||
context.stateChanged = { [weak self] state in
|
|
||||||
self?.contextState.set(.single(state))
|
|
||||||
}
|
|
||||||
context.signalBarsChanged = { [weak self] signalBars in
|
|
||||||
self?.receptionPromise.set(.single(signalBars))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.networkTypeDisposable = (updatedNetworkType
|
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] networkType in
|
|
||||||
self?.withContext { context in
|
|
||||||
context.setNetworkType(ongoingNetworkTypeForType(networkType))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
cleanupCallLogs(account: account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -235,19 +243,6 @@ public final class OngoingCallContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func start(key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String) {
|
|
||||||
let logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log"
|
|
||||||
self.audioSessionDisposable.set((audioSessionActive
|
|
||||||
|> filter { $0 }
|
|
||||||
|> take(1)).start(next: { [weak self] _ in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.withContext { context in
|
|
||||||
context.start(withKey: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise<String?>) {
|
public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise<String?>) {
|
||||||
self.withContext { context in
|
self.withContext { context in
|
||||||
context.stop { debugLog, bytesSentWifi, bytesReceivedWifi, bytesSentMobile, bytesReceivedMobile in
|
context.stop { debugLog, bytesSentWifi, bytesReceivedWifi, bytesSentMobile, bytesReceivedMobile in
|
||||||
@ -293,14 +288,5 @@ public final class OngoingCallContext {
|
|||||||
}
|
}
|
||||||
return (poll |> then(.complete() |> delay(0.5, queue: Queue.concurrentDefaultQueue()))) |> restart
|
return (poll |> then(.complete() |> delay(0.5, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||||
}
|
}
|
||||||
|
|
||||||
public func needsRating(_ completion: @escaping (Bool) -> Void) {
|
|
||||||
self.withContext { context in
|
|
||||||
let needsRating = context.needRate()
|
|
||||||
Queue.mainQueue().async {
|
|
||||||
completion(needsRating)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,14 +59,13 @@ typedef NS_ENUM(int32_t, OngoingCallDataSaving) {
|
|||||||
+ (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction;
|
+ (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction;
|
||||||
+ (void)applyServerConfig:(NSString * _Nullable)data;
|
+ (void)applyServerConfig:(NSString * _Nullable)data;
|
||||||
+ (int32_t)maxLayer;
|
+ (int32_t)maxLayer;
|
||||||
+ (NSString *)version;
|
+ (NSString * _Nonnull)version;
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
||||||
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
|
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState;
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
|
||||||
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
|
- (void)stop:(void (^_Nonnull)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
||||||
- (void)stop:(void (^)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
|
||||||
|
|
||||||
- (bool)needRate;
|
- (bool)needRate;
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#import "OngoingCallThreadLocalContext.h"
|
#import "OngoingCallThreadLocalContext.h"
|
||||||
|
|
||||||
#import "VoIPController.h"
|
#import "TgVoip.h"
|
||||||
#import "VoIPServerConfig.h"
|
|
||||||
#import "os/darwin/SetupLogging.h"
|
|
||||||
|
|
||||||
#import <MtProtoKit/MtProtoKit.h>
|
#import <MtProtoKit/MtProtoKit.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
static void TGCallAesIgeEncrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
static void TGCallAesIgeEncrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
||||||
MTAesEncryptRaw(inBytes, outBytes, length, key, iv);
|
MTAesEncryptRaw(inBytes, outBytes, length, key, iv);
|
||||||
@ -127,34 +126,19 @@ static void withContext(int32_t contextId, void (^f)(OngoingCallThreadLocalConte
|
|||||||
NSTimeInterval _callRingTimeout;
|
NSTimeInterval _callRingTimeout;
|
||||||
NSTimeInterval _callConnectTimeout;
|
NSTimeInterval _callConnectTimeout;
|
||||||
NSTimeInterval _callPacketTimeout;
|
NSTimeInterval _callPacketTimeout;
|
||||||
int32_t _dataSavingMode;
|
|
||||||
|
|
||||||
tgvoip::VoIPController *_controller;
|
TgVoip *_tgVoip;
|
||||||
|
|
||||||
OngoingCallState _state;
|
OngoingCallState _state;
|
||||||
int32_t _signalBars;
|
int32_t _signalBars;
|
||||||
NSData *_lastDerivedState;
|
NSData *_lastDerivedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controllerStateChanged:(int)state;
|
- (void)controllerStateChanged:(TgVoipState)state;
|
||||||
- (void)signalBarsChanged:(int32_t)signalBars;
|
- (void)signalBarsChanged:(int32_t)signalBars;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static void controllerStateCallback(tgvoip::VoIPController *controller, int state) {
|
|
||||||
int32_t contextId = (int32_t)((intptr_t)controller->implData);
|
|
||||||
withContext(contextId, ^(OngoingCallThreadLocalContext *context) {
|
|
||||||
[context controllerStateChanged:state];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBars) {
|
|
||||||
int32_t contextId = (int32_t)((intptr_t)controller->implData);
|
|
||||||
withContext(contextId, ^(OngoingCallThreadLocalContext *context) {
|
|
||||||
[context signalBarsChanged:(int32_t)signalBars];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation VoipProxyServer
|
@implementation VoipProxyServer
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
||||||
@ -170,55 +154,62 @@ static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBar
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
static TgVoipNetworkType callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallNetworkTypeWifi:
|
case OngoingCallNetworkTypeWifi:
|
||||||
return tgvoip::NET_TYPE_WIFI;
|
return TgVoipNetworkType::WiFi;
|
||||||
case OngoingCallNetworkTypeCellularGprs:
|
case OngoingCallNetworkTypeCellularGprs:
|
||||||
return tgvoip::NET_TYPE_GPRS;
|
return TgVoipNetworkType::Gprs;
|
||||||
case OngoingCallNetworkTypeCellular3g:
|
case OngoingCallNetworkTypeCellular3g:
|
||||||
return tgvoip::NET_TYPE_3G;
|
return TgVoipNetworkType::ThirdGeneration;
|
||||||
case OngoingCallNetworkTypeCellularLte:
|
case OngoingCallNetworkTypeCellularLte:
|
||||||
return tgvoip::NET_TYPE_LTE;
|
return TgVoipNetworkType::Lte;
|
||||||
default:
|
default:
|
||||||
return tgvoip::NET_TYPE_WIFI;
|
return TgVoipNetworkType::ThirdGeneration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
static TgVoipDataSaving callControllerDataSavingForType(OngoingCallDataSaving type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallDataSavingNever:
|
case OngoingCallDataSavingNever:
|
||||||
return tgvoip::DATA_SAVING_NEVER;
|
return TgVoipDataSaving::Never;
|
||||||
case OngoingCallDataSavingCellular:
|
case OngoingCallDataSavingCellular:
|
||||||
return tgvoip::DATA_SAVING_MOBILE;
|
return TgVoipDataSaving::Mobile;
|
||||||
case OngoingCallDataSavingAlways:
|
case OngoingCallDataSavingAlways:
|
||||||
return tgvoip::DATA_SAVING_ALWAYS;
|
return TgVoipDataSaving::Always;
|
||||||
default:
|
default:
|
||||||
return tgvoip::DATA_SAVING_NEVER;
|
return TgVoipDataSaving::Never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation OngoingCallThreadLocalContext
|
@implementation OngoingCallThreadLocalContext
|
||||||
|
|
||||||
|
static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
||||||
|
|
||||||
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
|
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
|
||||||
TGVoipLoggingFunction = loggingFunction;
|
InternalVoipLoggingFunction = loggingFunction;
|
||||||
|
TgVoip::setLoggingFunction([](std::string const &string) {
|
||||||
|
if (InternalVoipLoggingFunction) {
|
||||||
|
InternalVoipLoggingFunction([[NSString alloc] initWithUTF8String:string.c_str()]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)applyServerConfig:(NSString *)string {
|
+ (void)applyServerConfig:(NSString *)string {
|
||||||
if (string.length != 0) {
|
if (string.length != 0) {
|
||||||
tgvoip::ServerConfig::GetSharedInstance()->Update(std::string(string.UTF8String));
|
TgVoip::setGlobalServerConfig(std::string(string.UTF8String));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (int32_t)maxLayer {
|
+ (int32_t)maxLayer {
|
||||||
return tgvoip::VoIPController::GetConnectionMaxLayer();
|
return 92;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)version {
|
+ (NSString *)version {
|
||||||
return [NSString stringWithUTF8String:tgvoip::VoIPController::GetVersion()];
|
return [NSString stringWithUTF8String:TgVoip::getVersion().c_str()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState {
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_queue = queue;
|
_queue = queue;
|
||||||
@ -229,37 +220,108 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
_callRingTimeout = 90.0;
|
_callRingTimeout = 90.0;
|
||||||
_callConnectTimeout = 30.0;
|
_callConnectTimeout = 30.0;
|
||||||
_callPacketTimeout = 10.0;
|
_callPacketTimeout = 10.0;
|
||||||
_dataSavingMode = callControllerDataSavingForType(dataSaving);
|
|
||||||
_networkType = networkType;
|
_networkType = networkType;
|
||||||
|
|
||||||
_controller = new tgvoip::VoIPController();
|
|
||||||
_controller->implData = (void *)((intptr_t)_contextId);
|
|
||||||
std::vector<uint8_t> derivedStateValue;
|
std::vector<uint8_t> derivedStateValue;
|
||||||
derivedStateValue.resize(derivedState.length);
|
derivedStateValue.resize(derivedState.length);
|
||||||
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
|
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
|
||||||
_controller->SetPersistentState(derivedStateValue);
|
|
||||||
|
|
||||||
|
std::unique_ptr<TgVoipProxy> proxyValue = nullptr;
|
||||||
if (proxy != nil) {
|
if (proxy != nil) {
|
||||||
_controller->SetProxy(tgvoip::PROXY_SOCKS5, proxy.host.UTF8String, (uint16_t)proxy.port, proxy.username.UTF8String ?: "", proxy.password.UTF8String ?: "");
|
TgVoipProxy *proxyObject = new TgVoipProxy();
|
||||||
|
proxyObject->host = proxy.host.UTF8String;
|
||||||
|
proxyObject->port = (uint16_t)proxy.port;
|
||||||
|
proxyObject->login = proxy.username.UTF8String ?: "";
|
||||||
|
proxyObject->password = proxy.password.UTF8String ?: "";
|
||||||
|
proxyValue = std::unique_ptr<TgVoipProxy>(proxyObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callbacks = tgvoip::VoIPController::Callbacks();
|
TgVoipCrypto crypto;
|
||||||
callbacks.connectionStateChanged = &controllerStateCallback;
|
crypto.sha1 = &TGCallSha1;
|
||||||
callbacks.groupCallKeyReceived = NULL;
|
crypto.sha256 = &TGCallSha256;
|
||||||
callbacks.groupCallKeySent = NULL;
|
crypto.rand_bytes = &TGCallRandomBytes;
|
||||||
callbacks.signalBarCountChanged = &signalBarsCallback;
|
crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
|
||||||
callbacks.upgradeToGroupCallRequested = NULL;
|
crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
|
||||||
_controller->SetCallbacks(callbacks);
|
crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;
|
||||||
|
|
||||||
tgvoip::VoIPController::crypto.sha1 = &TGCallSha1;
|
std::vector<TgVoipEndpoint> endpoints;
|
||||||
tgvoip::VoIPController::crypto.sha256 = &TGCallSha256;
|
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
||||||
tgvoip::VoIPController::crypto.rand_bytes = &TGCallRandomBytes;
|
for (OngoingCallConnectionDescription *connection in connections) {
|
||||||
tgvoip::VoIPController::crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
|
unsigned char peerTag[16];
|
||||||
tgvoip::VoIPController::crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
|
[connection.peerTag getBytes:peerTag length:16];
|
||||||
tgvoip::VoIPController::crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;
|
|
||||||
|
TgVoipEndpoint endpoint;
|
||||||
|
endpoint.endpointId = connection.connectionId;
|
||||||
|
endpoint.host = {
|
||||||
|
.ipv4 = std::string(connection.ip.UTF8String),
|
||||||
|
.ipv6 = std::string(connection.ipv6.UTF8String)
|
||||||
|
};
|
||||||
|
endpoint.port = (uint16_t)connection.port;
|
||||||
|
endpoint.type = TgVoipEndpointType::UdpRelay;
|
||||||
|
memcpy(endpoint.peerTag, peerTag, 16);
|
||||||
|
endpoints.push_back(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
TgVoipConfig config = {
|
||||||
|
.initializationTimeout = _callConnectTimeout,
|
||||||
|
.receiveTimeout = _callPacketTimeout,
|
||||||
|
.dataSaving = callControllerDataSavingForType(dataSaving),
|
||||||
|
.enableP2P = allowP2P,
|
||||||
|
.enableAEC = false,
|
||||||
|
.enableNS = true,
|
||||||
|
.enableAGC = true,
|
||||||
|
.enableCallUpgrade = false,
|
||||||
|
.logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String),
|
||||||
|
.maxApiLayer = [OngoingCallThreadLocalContext maxLayer]
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint8_t> encryptionKeyValue;
|
||||||
|
encryptionKeyValue.resize(key.length);
|
||||||
|
memcpy(encryptionKeyValue.data(), key.bytes, key.length);
|
||||||
|
|
||||||
|
TgVoipEncryptionKey encryptionKey = {
|
||||||
|
.value = encryptionKeyValue,
|
||||||
|
.isOutgoing = isOutgoing,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
TgVoipConfig const &config,
|
||||||
|
TgVoipPersistentState const &persistentState,
|
||||||
|
std::vector<TgVoipEndpoint> const &endpoints,
|
||||||
|
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||||
|
TgVoipNetworkType initialNetworkType,
|
||||||
|
TgVoipEncryptionKey const &encryptionKey
|
||||||
|
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||||
|
,
|
||||||
|
TgVoipCrypto const &crypto
|
||||||
|
*/
|
||||||
|
|
||||||
|
_tgVoip = TgVoip::makeInstance(
|
||||||
|
config,
|
||||||
|
{ derivedStateValue },
|
||||||
|
endpoints,
|
||||||
|
proxyValue,
|
||||||
|
callControllerNetworkTypeForType(networkType),
|
||||||
|
encryptionKey,
|
||||||
|
crypto
|
||||||
|
);
|
||||||
|
|
||||||
_state = OngoingCallStateInitializing;
|
_state = OngoingCallStateInitializing;
|
||||||
_signalBars = -1;
|
_signalBars = -1;
|
||||||
|
|
||||||
|
__weak OngoingCallThreadLocalContext *weakSelf = self;
|
||||||
|
_tgVoip->setOnStateUpdated([weakSelf](TgVoipState state) {
|
||||||
|
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
[strongSelf controllerStateChanged:state];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_tgVoip->setOnSignalBarsUpdated([weakSelf](int signalBars) {
|
||||||
|
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
[strongSelf signalBarsChanged:signalBars];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -267,79 +329,30 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
assert([_queue isCurrent]);
|
assert([_queue isCurrent]);
|
||||||
removeContext(_contextId);
|
removeContext(_contextId);
|
||||||
if (_controller != NULL) {
|
if (_tgVoip != NULL) {
|
||||||
[self stop:nil];
|
[self stop:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
|
|
||||||
std::vector<tgvoip::Endpoint> endpoints;
|
|
||||||
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
|
||||||
for (OngoingCallConnectionDescription *connection in connections) {
|
|
||||||
struct in_addr addrIpV4;
|
|
||||||
if (!inet_aton(connection.ip.UTF8String, &addrIpV4)) {
|
|
||||||
NSLog(@"CallSession: invalid ipv4 address");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct in6_addr addrIpV6;
|
|
||||||
if (!inet_pton(AF_INET6, connection.ipv6.UTF8String, &addrIpV6)) {
|
|
||||||
NSLog(@"CallSession: invalid ipv6 address");
|
|
||||||
}
|
|
||||||
|
|
||||||
tgvoip::IPv4Address address(std::string(connection.ip.UTF8String));
|
|
||||||
tgvoip::IPv6Address addressv6(std::string(connection.ipv6.UTF8String));
|
|
||||||
unsigned char peerTag[16];
|
|
||||||
[connection.peerTag getBytes:peerTag length:16];
|
|
||||||
endpoints.push_back(tgvoip::Endpoint(connection.connectionId, (uint16_t)connection.port, address, addressv6, tgvoip::Endpoint::Type::UDP_RELAY, peerTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
tgvoip::VoIPController::Config config(_callConnectTimeout, _callPacketTimeout, _dataSavingMode, false, true, true);
|
|
||||||
config.logFilePath = logPath.length > 0 ? std::string(logPath.UTF8String) : "";
|
|
||||||
config.statsDumpFilePath = "";
|
|
||||||
|
|
||||||
if (_controller != nil) {
|
|
||||||
_controller->SetConfig(config);
|
|
||||||
|
|
||||||
_controller->SetNetworkType(callControllerNetworkTypeForType(_networkType));
|
|
||||||
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
|
||||||
_controller->SetRemoteEndpoints(endpoints, allowP2P, maxLayer);
|
|
||||||
_controller->Start();
|
|
||||||
|
|
||||||
_controller->Connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->Stop();
|
TgVoipFinalState finalState = _tgVoip->stop();
|
||||||
|
|
||||||
auto debugString = _controller->GetDebugLog();
|
NSString *debugLog = [NSString stringWithUTF8String:finalState.debugLog.c_str()];
|
||||||
NSString *debugLog = [NSString stringWithUTF8String:debugString.c_str()];
|
_lastDerivedState = [[NSData alloc] initWithBytes:finalState.persistentState.value.data() length:finalState.persistentState.value.size()];
|
||||||
|
|
||||||
tgvoip::VoIPController::TrafficStats stats;
|
delete _tgVoip;
|
||||||
_controller->GetStats(&stats);
|
_tgVoip = NULL;
|
||||||
std::vector<uint8_t> derivedStateValue = _controller->GetPersistentState();
|
|
||||||
_lastDerivedState = [[NSData alloc] initWithBytes:derivedStateValue.data() length:derivedStateValue.size()];
|
|
||||||
delete _controller;
|
|
||||||
_controller = NULL;
|
|
||||||
|
|
||||||
if (completion) {
|
if (completion) {
|
||||||
completion(debugLog, stats.bytesSentWifi, stats.bytesRecvdWifi, stats.bytesSentMobile, stats.bytesRecvdMobile);
|
completion(debugLog, finalState.trafficStats.bytesSentWifi, finalState.trafficStats.bytesReceivedWifi, finalState.trafficStats.bytesSentMobile, finalState.trafficStats.bytesReceivedMobile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)needRate {
|
|
||||||
if (_controller != nil) {
|
|
||||||
return _controller->NeedRate();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)debugInfo {
|
- (NSString *)debugInfo {
|
||||||
if (_controller != nil) {
|
if (_tgVoip != nil) {
|
||||||
auto rawDebugString = _controller->GetDebugString();
|
auto rawDebugString = _tgVoip->getDebugInfo();
|
||||||
return [NSString stringWithUTF8String:rawDebugString.c_str()];
|
return [NSString stringWithUTF8String:rawDebugString.c_str()];
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
@ -347,17 +360,17 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)version {
|
- (NSString *)version {
|
||||||
if (_controller != nil) {
|
if (_tgVoip != nil) {
|
||||||
return [NSString stringWithUTF8String:_controller->GetVersion()];
|
return [NSString stringWithUTF8String:_tgVoip->getVersion().c_str()];
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData * _Nonnull)getDerivedState {
|
- (NSData * _Nonnull)getDerivedState {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
std::vector<uint8_t> derivedStateValue = _controller->GetPersistentState();
|
auto persistentState = _tgVoip->getPersistentState();
|
||||||
return [[NSData alloc] initWithBytes:derivedStateValue.data() length:derivedStateValue.size()];
|
return [[NSData alloc] initWithBytes:persistentState.value.data() length:persistentState.value.size()];
|
||||||
} else if (_lastDerivedState != nil) {
|
} else if (_lastDerivedState != nil) {
|
||||||
return _lastDerivedState;
|
return _lastDerivedState;
|
||||||
} else {
|
} else {
|
||||||
@ -365,16 +378,16 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controllerStateChanged:(int)state {
|
- (void)controllerStateChanged:(TgVoipState)state {
|
||||||
OngoingCallState callState = OngoingCallStateInitializing;
|
OngoingCallState callState = OngoingCallStateInitializing;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case tgvoip::STATE_ESTABLISHED:
|
case TgVoipState::Estabilished:
|
||||||
callState = OngoingCallStateConnected;
|
callState = OngoingCallStateConnected;
|
||||||
break;
|
break;
|
||||||
case tgvoip::STATE_FAILED:
|
case TgVoipState::Failed:
|
||||||
callState = OngoingCallStateFailed;
|
callState = OngoingCallStateFailed;
|
||||||
break;
|
break;
|
||||||
case tgvoip::STATE_RECONNECTING:
|
case TgVoipState::Reconnecting:
|
||||||
callState = OngoingCallStateReconnecting;
|
callState = OngoingCallStateReconnecting;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -401,16 +414,16 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)setIsMuted:(bool)isMuted {
|
- (void)setIsMuted:(bool)isMuted {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->SetMicMute(isMuted);
|
_tgVoip->setMuteMicrophone(isMuted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNetworkType:(OngoingCallNetworkType)networkType {
|
- (void)setNetworkType:(OngoingCallNetworkType)networkType {
|
||||||
if (_networkType != networkType) {
|
if (_networkType != networkType) {
|
||||||
_networkType = networkType;
|
_networkType = networkType;
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->SetNetworkType(callControllerNetworkTypeForType(networkType));
|
_tgVoip->setNetworkType(callControllerNetworkTypeForType(networkType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 522550a1e975b17e9048d7a2ab2d5b97cfc2f5d4
|
Subproject commit a045c9eea47b371c0c514c72c76172a211c894cb
|
76
submodules/TgVoipWebrtc/BUCK
Normal file
76
submodules/TgVoipWebrtc/BUCK
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
load("//Config:buck_rule_macros.bzl", "static_library", "glob_map", "glob_sub_map", "merge_maps")
|
||||||
|
|
||||||
|
static_library(
|
||||||
|
name = "TgVoipWebrtc",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.m",
|
||||||
|
"Sources/**/*.mm",
|
||||||
|
"Sources/**/*.h",
|
||||||
|
"libtgvoip/*.m",
|
||||||
|
"libtgvoip/*.mm",
|
||||||
|
"libtgvoip/*.cpp",
|
||||||
|
"libtgvoip/audio/*.cpp",
|
||||||
|
"libtgvoip/video/*.cpp",
|
||||||
|
"libtgvoip/os/darwin/*.m",
|
||||||
|
"libtgvoip/os/darwin/*.mm",
|
||||||
|
"libtgvoip/os/darwin/*.cpp",
|
||||||
|
"libtgvoip/os/posix/*.cpp",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.c",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.cc",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.cpp",
|
||||||
|
], exclude = ["libtgvoip/os/darwin/*OSX*"]),
|
||||||
|
has_cpp = True,
|
||||||
|
headers = merge_maps([
|
||||||
|
glob_sub_map("libtgvoip/", [
|
||||||
|
"libtgvoip/*.h",
|
||||||
|
"libtgvoip/*.hpp",
|
||||||
|
"libtgvoip/audio/*.h",
|
||||||
|
"libtgvoip/audio/*.hpp",
|
||||||
|
"libtgvoip/video/*.h",
|
||||||
|
"libtgvoip/video/*.hpp",
|
||||||
|
]),
|
||||||
|
glob_sub_map("libtgvoip/", [
|
||||||
|
"libtgvoip/os/darwin/*.h",
|
||||||
|
], exclude = ["libtgvoip/os/darwin/*OSX*"]),
|
||||||
|
glob_sub_map("libtgvoip/webrtc_dsp/", [
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.h",
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
exported_headers = glob([
|
||||||
|
"PublicHeaders/**/*.h",
|
||||||
|
]),
|
||||||
|
platform_compiler_flags = [
|
||||||
|
('arm.*', [
|
||||||
|
'-DTGVOIP_USE_CUSTOM_CRYPTO',
|
||||||
|
'-DTGVOIP_USE_INSTALLED_OPUS',
|
||||||
|
'-DWEBRTC_APM_DEBUG_DUMP=0',
|
||||||
|
'-DWEBRTC_POSIX',
|
||||||
|
'-DTGVOIP_HAVE_TGLOG',
|
||||||
|
'-DWEBRTC_NS_FLOAT',
|
||||||
|
'-DWEBRTC_IOS',
|
||||||
|
'-DWEBRTC_HAS_NEON',
|
||||||
|
]),
|
||||||
|
('.*', [
|
||||||
|
'-DTGVOIP_USE_CUSTOM_CRYPTO',
|
||||||
|
'-DTGVOIP_USE_INSTALLED_OPUS',
|
||||||
|
'-DWEBRTC_APM_DEBUG_DUMP=0',
|
||||||
|
'-DWEBRTC_POSIX',
|
||||||
|
'-DTGVOIP_HAVE_TGLOG',
|
||||||
|
'-DWEBRTC_NS_FLOAT',
|
||||||
|
'-DWEBRTC_IOS',
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/MtProtoKit:MtProtoKit#shared",
|
||||||
|
"//submodules/Opus:opus",
|
||||||
|
],
|
||||||
|
frameworks = [
|
||||||
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/AudioToolbox.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/VideoToolbox.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/CoreTelephony.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/CoreMedia.framework",
|
||||||
|
"$SDKROOT/System/Library/Frameworks/AVFoundation.framework",
|
||||||
|
],
|
||||||
|
)
|
74
submodules/TgVoipWebrtc/BUILD
Normal file
74
submodules/TgVoipWebrtc/BUILD
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
copts_arm = [
|
||||||
|
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||||
|
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||||
|
"-DWEBRTC_POSIX",
|
||||||
|
"-DTGVOIP_HAVE_TGLOG",
|
||||||
|
"-DWEBRTC_NS_FLOAT",
|
||||||
|
"-DWEBRTC_IOS",
|
||||||
|
"-DWEBRTC_HAS_NEON",
|
||||||
|
]
|
||||||
|
|
||||||
|
copts_x86 = [
|
||||||
|
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
||||||
|
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
||||||
|
"-DWEBRTC_POSIX",
|
||||||
|
"-DTGVOIP_HAVE_TGLOG",
|
||||||
|
"-DWEBRTC_NS_FLOAT",
|
||||||
|
"-DWEBRTC_IOS",
|
||||||
|
]
|
||||||
|
|
||||||
|
objc_library(
|
||||||
|
name = "TgVoipWebrtc",
|
||||||
|
enable_modules = True,
|
||||||
|
module_name = "TgVoipWebrtc",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.m",
|
||||||
|
"Sources/**/*.mm",
|
||||||
|
"Sources/**/*.h",
|
||||||
|
"libtgvoip/*.m",
|
||||||
|
"libtgvoip/*.mm",
|
||||||
|
"libtgvoip/*.cpp",
|
||||||
|
"libtgvoip/audio/*.cpp",
|
||||||
|
"libtgvoip/video/*.cpp",
|
||||||
|
"libtgvoip/os/darwin/*.m",
|
||||||
|
"libtgvoip/os/darwin/*.mm",
|
||||||
|
"libtgvoip/os/darwin/*.cpp",
|
||||||
|
"libtgvoip/os/posix/*.cpp",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.c",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.cc",
|
||||||
|
"libtgvoip/webrtc_dsp/**/*.cpp",
|
||||||
|
], exclude = ["libtgvoip/os/darwin/*OSX*"]),
|
||||||
|
hdrs = glob([
|
||||||
|
"PublicHeaders/**/*.h",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-I{}/PublicHeaders/TgVoip".format(package_name()),
|
||||||
|
"-I{}/libtgvoip".format(package_name()),
|
||||||
|
"-I{}/libtgvoip/webrtc_dsp".format(package_name()),
|
||||||
|
"-DTGVOIP_USE_INSTALLED_OPUS",
|
||||||
|
] + select({
|
||||||
|
"@build_bazel_rules_apple//apple:ios_armv7": copts_arm,
|
||||||
|
"@build_bazel_rules_apple//apple:ios_arm64": copts_arm,
|
||||||
|
"@build_bazel_rules_apple//apple:ios_x86_64": copts_x86,
|
||||||
|
}),
|
||||||
|
includes = [
|
||||||
|
"PublicHeaders",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/MtProtoKit:MtProtoKit",
|
||||||
|
"//submodules/Opus:opus",
|
||||||
|
],
|
||||||
|
sdk_frameworks = [
|
||||||
|
"Foundation",
|
||||||
|
"UIKit",
|
||||||
|
"AudioToolbox",
|
||||||
|
"VideoToolbox",
|
||||||
|
"CoreTelephony",
|
||||||
|
"CoreMedia",
|
||||||
|
"AVFoundation",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef OngoingCallContext_h
|
||||||
|
#define OngoingCallContext_h
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface OngoingCallConnectionDescription : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) int64_t connectionId;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull ip;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull ipv6;
|
||||||
|
@property (nonatomic, readonly) int32_t port;
|
||||||
|
@property (nonatomic, strong, readonly) NSData * _Nonnull peerTag;
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
typedef NS_ENUM(int32_t, OngoingCallState) {
|
||||||
|
OngoingCallStateInitializing,
|
||||||
|
OngoingCallStateConnected,
|
||||||
|
OngoingCallStateFailed,
|
||||||
|
OngoingCallStateReconnecting
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NS_ENUM(int32_t, OngoingCallNetworkType) {
|
||||||
|
OngoingCallNetworkTypeWifi,
|
||||||
|
OngoingCallNetworkTypeCellularGprs,
|
||||||
|
OngoingCallNetworkTypeCellularEdge,
|
||||||
|
OngoingCallNetworkTypeCellular3g,
|
||||||
|
OngoingCallNetworkTypeCellularLte
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NS_ENUM(int32_t, OngoingCallDataSaving) {
|
||||||
|
OngoingCallDataSavingNever,
|
||||||
|
OngoingCallDataSavingCellular,
|
||||||
|
OngoingCallDataSavingAlways
|
||||||
|
};
|
||||||
|
|
||||||
|
@protocol OngoingCallThreadLocalContextQueue <NSObject>
|
||||||
|
|
||||||
|
- (void)dispatch:(void (^ _Nonnull)())f;
|
||||||
|
- (bool)isCurrent;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface VoipProxyServer : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull host;
|
||||||
|
@property (nonatomic, readonly) int32_t port;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nullable username;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nullable password;
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface OngoingCallThreadLocalContext : NSObject
|
||||||
|
|
||||||
|
+ (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction;
|
||||||
|
+ (void)applyServerConfig:(NSString * _Nullable)data;
|
||||||
|
+ (int32_t)maxLayer;
|
||||||
|
+ (NSString * _Nonnull)version;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
||||||
|
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
|
||||||
|
- (void)stop:(void (^_Nonnull)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
||||||
|
|
||||||
|
- (bool)needRate;
|
||||||
|
|
||||||
|
- (NSString * _Nullable)debugInfo;
|
||||||
|
- (NSString * _Nullable)version;
|
||||||
|
- (NSData * _Nonnull)getDerivedState;
|
||||||
|
|
||||||
|
- (void)setIsMuted:(bool)isMuted;
|
||||||
|
- (void)setNetworkType:(OngoingCallNetworkType)networkType;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
@ -1,14 +1,9 @@
|
|||||||
#import "OngoingCallThreadLocalContext.h"
|
#import "OngoingCallThreadLocalContext.h"
|
||||||
|
|
||||||
#import "VoIPController.h"
|
#import "TgVoip.h"
|
||||||
#import "VoIPServerConfig.h"
|
|
||||||
#import "os/darwin/SetupLogging.h"
|
|
||||||
|
|
||||||
#ifdef BUCK
|
|
||||||
#import <MtProtoKit/MtProtoKit.h>
|
#import <MtProtoKit/MtProtoKit.h>
|
||||||
#else
|
#include <memory>
|
||||||
#import <MtProtoKitDynamic/MtProtoKitDynamic.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void TGCallAesIgeEncrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
static void TGCallAesIgeEncrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
||||||
MTAesEncryptRaw(inBytes, outBytes, length, key, iv);
|
MTAesEncryptRaw(inBytes, outBytes, length, key, iv);
|
||||||
@ -131,34 +126,19 @@ static void withContext(int32_t contextId, void (^f)(OngoingCallThreadLocalConte
|
|||||||
NSTimeInterval _callRingTimeout;
|
NSTimeInterval _callRingTimeout;
|
||||||
NSTimeInterval _callConnectTimeout;
|
NSTimeInterval _callConnectTimeout;
|
||||||
NSTimeInterval _callPacketTimeout;
|
NSTimeInterval _callPacketTimeout;
|
||||||
int32_t _dataSavingMode;
|
|
||||||
|
|
||||||
tgvoip::VoIPController *_controller;
|
TgVoip *_tgVoip;
|
||||||
|
|
||||||
OngoingCallState _state;
|
OngoingCallState _state;
|
||||||
int32_t _signalBars;
|
int32_t _signalBars;
|
||||||
NSData *_lastDerivedState;
|
NSData *_lastDerivedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controllerStateChanged:(int)state;
|
- (void)controllerStateChanged:(TgVoipState)state;
|
||||||
- (void)signalBarsChanged:(int32_t)signalBars;
|
- (void)signalBarsChanged:(int32_t)signalBars;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static void controllerStateCallback(tgvoip::VoIPController *controller, int state) {
|
|
||||||
int32_t contextId = (int32_t)((intptr_t)controller->implData);
|
|
||||||
withContext(contextId, ^(OngoingCallThreadLocalContext *context) {
|
|
||||||
[context controllerStateChanged:state];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBars) {
|
|
||||||
int32_t contextId = (int32_t)((intptr_t)controller->implData);
|
|
||||||
withContext(contextId, ^(OngoingCallThreadLocalContext *context) {
|
|
||||||
[context signalBarsChanged:(int32_t)signalBars];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation VoipProxyServer
|
@implementation VoipProxyServer
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
||||||
@ -174,55 +154,62 @@ static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBar
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
static TgVoipNetworkType callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallNetworkTypeWifi:
|
case OngoingCallNetworkTypeWifi:
|
||||||
return tgvoip::NET_TYPE_WIFI;
|
return TgVoipNetworkType::WiFi;
|
||||||
case OngoingCallNetworkTypeCellularGprs:
|
case OngoingCallNetworkTypeCellularGprs:
|
||||||
return tgvoip::NET_TYPE_GPRS;
|
return TgVoipNetworkType::Gprs;
|
||||||
case OngoingCallNetworkTypeCellular3g:
|
case OngoingCallNetworkTypeCellular3g:
|
||||||
return tgvoip::NET_TYPE_3G;
|
return TgVoipNetworkType::ThirdGeneration;
|
||||||
case OngoingCallNetworkTypeCellularLte:
|
case OngoingCallNetworkTypeCellularLte:
|
||||||
return tgvoip::NET_TYPE_LTE;
|
return TgVoipNetworkType::Lte;
|
||||||
default:
|
default:
|
||||||
return tgvoip::NET_TYPE_WIFI;
|
return TgVoipNetworkType::ThirdGeneration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
static TgVoipDataSaving callControllerDataSavingForType(OngoingCallDataSaving type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallDataSavingNever:
|
case OngoingCallDataSavingNever:
|
||||||
return tgvoip::DATA_SAVING_NEVER;
|
return TgVoipDataSaving::Never;
|
||||||
case OngoingCallDataSavingCellular:
|
case OngoingCallDataSavingCellular:
|
||||||
return tgvoip::DATA_SAVING_MOBILE;
|
return TgVoipDataSaving::Mobile;
|
||||||
case OngoingCallDataSavingAlways:
|
case OngoingCallDataSavingAlways:
|
||||||
return tgvoip::DATA_SAVING_ALWAYS;
|
return TgVoipDataSaving::Always;
|
||||||
default:
|
default:
|
||||||
return tgvoip::DATA_SAVING_NEVER;
|
return TgVoipDataSaving::Never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation OngoingCallThreadLocalContext
|
@implementation OngoingCallThreadLocalContext
|
||||||
|
|
||||||
|
static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
||||||
|
|
||||||
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
|
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
|
||||||
TGVoipLoggingFunction = loggingFunction;
|
InternalVoipLoggingFunction = loggingFunction;
|
||||||
|
TgVoip::setLoggingFunction([](std::string const &string) {
|
||||||
|
if (InternalVoipLoggingFunction) {
|
||||||
|
InternalVoipLoggingFunction([[NSString alloc] initWithUTF8String:string.c_str()]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)applyServerConfig:(NSString *)string {
|
+ (void)applyServerConfig:(NSString *)string {
|
||||||
if (string.length != 0) {
|
if (string.length != 0) {
|
||||||
tgvoip::ServerConfig::GetSharedInstance()->Update(std::string(string.UTF8String));
|
TgVoip::setGlobalServerConfig(std::string(string.UTF8String));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (int32_t)maxLayer {
|
+ (int32_t)maxLayer {
|
||||||
return tgvoip::VoIPController::GetConnectionMaxLayer();
|
return 92;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)version {
|
+ (NSString *)version {
|
||||||
return [NSString stringWithUTF8String:tgvoip::VoIPController::GetVersion()];
|
return [NSString stringWithUTF8String:TgVoip::getVersion().c_str()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState {
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_queue = queue;
|
_queue = queue;
|
||||||
@ -233,37 +220,108 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
_callRingTimeout = 90.0;
|
_callRingTimeout = 90.0;
|
||||||
_callConnectTimeout = 30.0;
|
_callConnectTimeout = 30.0;
|
||||||
_callPacketTimeout = 10.0;
|
_callPacketTimeout = 10.0;
|
||||||
_dataSavingMode = callControllerDataSavingForType(dataSaving);
|
|
||||||
_networkType = networkType;
|
_networkType = networkType;
|
||||||
|
|
||||||
_controller = new tgvoip::VoIPController();
|
|
||||||
_controller->implData = (void *)((intptr_t)_contextId);
|
|
||||||
std::vector<uint8_t> derivedStateValue;
|
std::vector<uint8_t> derivedStateValue;
|
||||||
derivedStateValue.resize(derivedState.length);
|
derivedStateValue.resize(derivedState.length);
|
||||||
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
|
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
|
||||||
_controller->SetPersistentState(derivedStateValue);
|
|
||||||
|
|
||||||
|
std::unique_ptr<TgVoipProxy> proxyValue = nullptr;
|
||||||
if (proxy != nil) {
|
if (proxy != nil) {
|
||||||
_controller->SetProxy(tgvoip::PROXY_SOCKS5, proxy.host.UTF8String, (uint16_t)proxy.port, proxy.username.UTF8String ?: "", proxy.password.UTF8String ?: "");
|
TgVoipProxy *proxyObject = new TgVoipProxy();
|
||||||
|
proxyObject->host = proxy.host.UTF8String;
|
||||||
|
proxyObject->port = (uint16_t)proxy.port;
|
||||||
|
proxyObject->login = proxy.username.UTF8String ?: "";
|
||||||
|
proxyObject->password = proxy.password.UTF8String ?: "";
|
||||||
|
proxyValue = std::unique_ptr<TgVoipProxy>(proxyObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callbacks = tgvoip::VoIPController::Callbacks();
|
TgVoipCrypto crypto;
|
||||||
callbacks.connectionStateChanged = &controllerStateCallback;
|
crypto.sha1 = &TGCallSha1;
|
||||||
callbacks.groupCallKeyReceived = NULL;
|
crypto.sha256 = &TGCallSha256;
|
||||||
callbacks.groupCallKeySent = NULL;
|
crypto.rand_bytes = &TGCallRandomBytes;
|
||||||
callbacks.signalBarCountChanged = &signalBarsCallback;
|
crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
|
||||||
callbacks.upgradeToGroupCallRequested = NULL;
|
crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
|
||||||
_controller->SetCallbacks(callbacks);
|
crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;
|
||||||
|
|
||||||
tgvoip::VoIPController::crypto.sha1 = &TGCallSha1;
|
std::vector<TgVoipEndpoint> endpoints;
|
||||||
tgvoip::VoIPController::crypto.sha256 = &TGCallSha256;
|
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
||||||
tgvoip::VoIPController::crypto.rand_bytes = &TGCallRandomBytes;
|
for (OngoingCallConnectionDescription *connection in connections) {
|
||||||
tgvoip::VoIPController::crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
|
unsigned char peerTag[16];
|
||||||
tgvoip::VoIPController::crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
|
[connection.peerTag getBytes:peerTag length:16];
|
||||||
tgvoip::VoIPController::crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;
|
|
||||||
|
TgVoipEndpoint endpoint;
|
||||||
|
endpoint.endpointId = connection.connectionId;
|
||||||
|
endpoint.host = {
|
||||||
|
.ipv4 = std::string(connection.ip.UTF8String),
|
||||||
|
.ipv6 = std::string(connection.ipv6.UTF8String)
|
||||||
|
};
|
||||||
|
endpoint.port = (uint16_t)connection.port;
|
||||||
|
endpoint.type = TgVoipEndpointType::UdpRelay;
|
||||||
|
memcpy(endpoint.peerTag, peerTag, 16);
|
||||||
|
endpoints.push_back(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
TgVoipConfig config = {
|
||||||
|
.initializationTimeout = _callConnectTimeout,
|
||||||
|
.receiveTimeout = _callPacketTimeout,
|
||||||
|
.dataSaving = callControllerDataSavingForType(dataSaving),
|
||||||
|
.enableP2P = allowP2P,
|
||||||
|
.enableAEC = false,
|
||||||
|
.enableNS = true,
|
||||||
|
.enableAGC = true,
|
||||||
|
.enableCallUpgrade = false,
|
||||||
|
.logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String),
|
||||||
|
.maxApiLayer = [OngoingCallThreadLocalContext maxLayer]
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint8_t> encryptionKeyValue;
|
||||||
|
encryptionKeyValue.resize(key.length);
|
||||||
|
memcpy(encryptionKeyValue.data(), key.bytes, key.length);
|
||||||
|
|
||||||
|
TgVoipEncryptionKey encryptionKey = {
|
||||||
|
.value = encryptionKeyValue,
|
||||||
|
.isOutgoing = isOutgoing,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
TgVoipConfig const &config,
|
||||||
|
TgVoipPersistentState const &persistentState,
|
||||||
|
std::vector<TgVoipEndpoint> const &endpoints,
|
||||||
|
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||||
|
TgVoipNetworkType initialNetworkType,
|
||||||
|
TgVoipEncryptionKey const &encryptionKey
|
||||||
|
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||||
|
,
|
||||||
|
TgVoipCrypto const &crypto
|
||||||
|
*/
|
||||||
|
|
||||||
|
_tgVoip = TgVoip::makeInstance(
|
||||||
|
config,
|
||||||
|
{ derivedStateValue },
|
||||||
|
endpoints,
|
||||||
|
proxyValue,
|
||||||
|
callControllerNetworkTypeForType(networkType),
|
||||||
|
encryptionKey,
|
||||||
|
crypto
|
||||||
|
);
|
||||||
|
|
||||||
_state = OngoingCallStateInitializing;
|
_state = OngoingCallStateInitializing;
|
||||||
_signalBars = -1;
|
_signalBars = -1;
|
||||||
|
|
||||||
|
__weak OngoingCallThreadLocalContext *weakSelf = self;
|
||||||
|
_tgVoip->setOnStateUpdated([weakSelf](TgVoipState state) {
|
||||||
|
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
[strongSelf controllerStateChanged:state];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_tgVoip->setOnSignalBarsUpdated([weakSelf](int signalBars) {
|
||||||
|
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
||||||
|
if (strongSelf) {
|
||||||
|
[strongSelf signalBarsChanged:signalBars];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -271,79 +329,30 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
assert([_queue isCurrent]);
|
assert([_queue isCurrent]);
|
||||||
removeContext(_contextId);
|
removeContext(_contextId);
|
||||||
if (_controller != NULL) {
|
if (_tgVoip != NULL) {
|
||||||
[self stop:nil];
|
[self stop:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
|
|
||||||
std::vector<tgvoip::Endpoint> endpoints;
|
|
||||||
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
|
||||||
for (OngoingCallConnectionDescription *connection in connections) {
|
|
||||||
struct in_addr addrIpV4;
|
|
||||||
if (!inet_aton(connection.ip.UTF8String, &addrIpV4)) {
|
|
||||||
NSLog(@"CallSession: invalid ipv4 address");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct in6_addr addrIpV6;
|
|
||||||
if (!inet_pton(AF_INET6, connection.ipv6.UTF8String, &addrIpV6)) {
|
|
||||||
NSLog(@"CallSession: invalid ipv6 address");
|
|
||||||
}
|
|
||||||
|
|
||||||
tgvoip::IPv4Address address(std::string(connection.ip.UTF8String));
|
|
||||||
tgvoip::IPv6Address addressv6(std::string(connection.ipv6.UTF8String));
|
|
||||||
unsigned char peerTag[16];
|
|
||||||
[connection.peerTag getBytes:peerTag length:16];
|
|
||||||
endpoints.push_back(tgvoip::Endpoint(connection.connectionId, (uint16_t)connection.port, address, addressv6, tgvoip::Endpoint::Type::UDP_RELAY, peerTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
tgvoip::VoIPController::Config config(_callConnectTimeout, _callPacketTimeout, _dataSavingMode, false, true, true);
|
|
||||||
config.logFilePath = logPath.length > 0 ? std::string(logPath.UTF8String) : "";
|
|
||||||
config.statsDumpFilePath = "";
|
|
||||||
|
|
||||||
if (_controller != nil) {
|
|
||||||
_controller->SetConfig(config);
|
|
||||||
|
|
||||||
_controller->SetNetworkType(callControllerNetworkTypeForType(_networkType));
|
|
||||||
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
|
||||||
_controller->SetRemoteEndpoints(endpoints, allowP2P, maxLayer);
|
|
||||||
_controller->Start();
|
|
||||||
|
|
||||||
_controller->Connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->Stop();
|
TgVoipFinalState finalState = _tgVoip->stop();
|
||||||
|
|
||||||
auto debugString = _controller->GetDebugLog();
|
NSString *debugLog = [NSString stringWithUTF8String:finalState.debugLog.c_str()];
|
||||||
NSString *debugLog = [NSString stringWithUTF8String:debugString.c_str()];
|
_lastDerivedState = [[NSData alloc] initWithBytes:finalState.persistentState.value.data() length:finalState.persistentState.value.size()];
|
||||||
|
|
||||||
tgvoip::VoIPController::TrafficStats stats;
|
delete _tgVoip;
|
||||||
_controller->GetStats(&stats);
|
_tgVoip = NULL;
|
||||||
std::vector<uint8_t> derivedStateValue = _controller->GetPersistentState();
|
|
||||||
_lastDerivedState = [[NSData alloc] initWithBytes:derivedStateValue.data() length:derivedStateValue.size()];
|
|
||||||
delete _controller;
|
|
||||||
_controller = NULL;
|
|
||||||
|
|
||||||
if (completion) {
|
if (completion) {
|
||||||
completion(debugLog, stats.bytesSentWifi, stats.bytesRecvdWifi, stats.bytesSentMobile, stats.bytesRecvdMobile);
|
completion(debugLog, finalState.trafficStats.bytesSentWifi, finalState.trafficStats.bytesReceivedWifi, finalState.trafficStats.bytesSentMobile, finalState.trafficStats.bytesReceivedMobile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)needRate {
|
|
||||||
if (_controller != nil) {
|
|
||||||
return _controller->NeedRate();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)debugInfo {
|
- (NSString *)debugInfo {
|
||||||
if (_controller != nil) {
|
if (_tgVoip != nil) {
|
||||||
auto rawDebugString = _controller->GetDebugString();
|
auto rawDebugString = _tgVoip->getDebugInfo();
|
||||||
return [NSString stringWithUTF8String:rawDebugString.c_str()];
|
return [NSString stringWithUTF8String:rawDebugString.c_str()];
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
@ -351,17 +360,17 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)version {
|
- (NSString *)version {
|
||||||
if (_controller != nil) {
|
if (_tgVoip != nil) {
|
||||||
return [NSString stringWithUTF8String:_controller->GetVersion()];
|
return [NSString stringWithUTF8String:_tgVoip->getVersion().c_str()];
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData * _Nonnull)getDerivedState {
|
- (NSData * _Nonnull)getDerivedState {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
std::vector<uint8_t> derivedStateValue = _controller->GetPersistentState();
|
auto persistentState = _tgVoip->getPersistentState();
|
||||||
return [[NSData alloc] initWithBytes:derivedStateValue.data() length:derivedStateValue.size()];
|
return [[NSData alloc] initWithBytes:persistentState.value.data() length:persistentState.value.size()];
|
||||||
} else if (_lastDerivedState != nil) {
|
} else if (_lastDerivedState != nil) {
|
||||||
return _lastDerivedState;
|
return _lastDerivedState;
|
||||||
} else {
|
} else {
|
||||||
@ -369,16 +378,16 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controllerStateChanged:(int)state {
|
- (void)controllerStateChanged:(TgVoipState)state {
|
||||||
OngoingCallState callState = OngoingCallStateInitializing;
|
OngoingCallState callState = OngoingCallStateInitializing;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case tgvoip::STATE_ESTABLISHED:
|
case TgVoipState::Estabilished:
|
||||||
callState = OngoingCallStateConnected;
|
callState = OngoingCallStateConnected;
|
||||||
break;
|
break;
|
||||||
case tgvoip::STATE_FAILED:
|
case TgVoipState::Failed:
|
||||||
callState = OngoingCallStateFailed;
|
callState = OngoingCallStateFailed;
|
||||||
break;
|
break;
|
||||||
case tgvoip::STATE_RECONNECTING:
|
case TgVoipState::Reconnecting:
|
||||||
callState = OngoingCallStateReconnecting;
|
callState = OngoingCallStateReconnecting;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -405,16 +414,16 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)setIsMuted:(bool)isMuted {
|
- (void)setIsMuted:(bool)isMuted {
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->SetMicMute(isMuted);
|
_tgVoip->setMuteMicrophone(isMuted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setNetworkType:(OngoingCallNetworkType)networkType {
|
- (void)setNetworkType:(OngoingCallNetworkType)networkType {
|
||||||
if (_networkType != networkType) {
|
if (_networkType != networkType) {
|
||||||
_networkType = networkType;
|
_networkType = networkType;
|
||||||
if (_controller != nil) {
|
if (_tgVoip) {
|
||||||
_controller->SetNetworkType(callControllerNetworkTypeForType(networkType));
|
_tgVoip->setNetworkType(callControllerNetworkTypeForType(networkType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user