Swiftgram/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm
2020-05-05 21:03:54 +04:00

327 lines
11 KiB
Plaintext

#import <TgVoip/OngoingCallThreadLocalContext.h>
#import "TgVoip.h"
using namespace TGVOIP_NAMESPACE;
@implementation OngoingCallConnectionDescriptionWebrtc
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag {
self = [super init];
if (self != nil) {
_connectionId = connectionId;
_ip = ip;
_ipv6 = ipv6;
_port = port;
_peerTag = peerTag;
}
return self;
}
@end
@interface OngoingCallThreadLocalContextWebrtc () {
id<OngoingCallThreadLocalContextQueueWebrtc> _queue;
int32_t _contextId;
OngoingCallNetworkTypeWebrtc _networkType;
NSTimeInterval _callReceiveTimeout;
NSTimeInterval _callRingTimeout;
NSTimeInterval _callConnectTimeout;
NSTimeInterval _callPacketTimeout;
TgVoip *_tgVoip;
OngoingCallStateWebrtc _state;
int32_t _signalBars;
NSData *_lastDerivedState;
}
- (void)controllerStateChanged:(TgVoipState)state;
- (void)signalBarsChanged:(int32_t)signalBars;
@end
@implementation VoipProxyServerWebrtc
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
self = [super init];
if (self != nil) {
_host = host;
_port = port;
_username = username;
_password = password;
}
return self;
}
@end
static TgVoipNetworkType callControllerNetworkTypeForType(OngoingCallNetworkTypeWebrtc type) {
switch (type) {
case OngoingCallNetworkTypeWifi:
return TgVoipNetworkType::WiFi;
case OngoingCallNetworkTypeCellularGprs:
return TgVoipNetworkType::Gprs;
case OngoingCallNetworkTypeCellular3g:
return TgVoipNetworkType::ThirdGeneration;
case OngoingCallNetworkTypeCellularLte:
return TgVoipNetworkType::Lte;
default:
return TgVoipNetworkType::ThirdGeneration;
}
}
static TgVoipDataSaving callControllerDataSavingForType(OngoingCallDataSavingWebrtc type) {
switch (type) {
case OngoingCallDataSavingNever:
return TgVoipDataSaving::Never;
case OngoingCallDataSavingCellular:
return TgVoipDataSaving::Mobile;
case OngoingCallDataSavingAlways:
return TgVoipDataSaving::Always;
default:
return TgVoipDataSaving::Never;
}
}
@implementation OngoingCallThreadLocalContextWebrtc
static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
InternalVoipLoggingFunction = loggingFunction;
TgVoip::setLoggingFunction([](std::string const &string) {
if (InternalVoipLoggingFunction) {
InternalVoipLoggingFunction([[NSString alloc] initWithUTF8String:string.c_str()]);
}
});
}
+ (void)applyServerConfig:(NSString *)string {
if (string.length != 0) {
TgVoip::setGlobalServerConfig(std::string(string.UTF8String));
}
}
+ (int32_t)maxLayer {
return 92;
}
+ (NSString *)version {
return @"2.7.7";
}
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
self = [super init];
if (self != nil) {
_queue = queue;
assert([queue isCurrent]);
_callReceiveTimeout = 20.0;
_callRingTimeout = 90.0;
_callConnectTimeout = 30.0;
_callPacketTimeout = 10.0;
_networkType = networkType;
std::vector<uint8_t> derivedStateValue;
derivedStateValue.resize(derivedState.length);
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
std::unique_ptr<TgVoipProxy> proxyValue = nullptr;
if (proxy != nil) {
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);
}
/*TgVoipCrypto crypto;
crypto.sha1 = &TGCallSha1;
crypto.sha256 = &TGCallSha256;
crypto.rand_bytes = &TGCallRandomBytes;
crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;*/
std::vector<TgVoipEndpoint> endpoints;
NSArray<OngoingCallConnectionDescriptionWebrtc *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
for (OngoingCallConnectionDescriptionWebrtc *connection in connections) {
unsigned char peerTag[16];
[connection.peerTag getBytes:peerTag length:16];
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 = [OngoingCallThreadLocalContextWebrtc maxLayer]
};
std::vector<uint8_t> encryptionKeyValue;
encryptionKeyValue.resize(key.length);
memcpy(encryptionKeyValue.data(), key.bytes, key.length);
TgVoipEncryptionKey encryptionKey = {
.value = encryptionKeyValue,
.isOutgoing = isOutgoing,
};
_tgVoip = TgVoip::makeInstance(
config,
{ derivedStateValue },
endpoints,
proxyValue,
callControllerNetworkTypeForType(networkType),
encryptionKey
);
_state = OngoingCallStateInitializing;
_signalBars = -1;
__weak OngoingCallThreadLocalContextWebrtc *weakSelf = self;
_tgVoip->setOnStateUpdated([weakSelf](TgVoipState state) {
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf controllerStateChanged:state];
}
});
_tgVoip->setOnSignalBarsUpdated([weakSelf](int signalBars) {
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf signalBarsChanged:signalBars];
}
});
}
return self;
}
- (void)dealloc {
assert([_queue isCurrent]);
if (_tgVoip != NULL) {
[self stop:nil];
}
}
- (bool)needRate {
return false;
}
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
if (_tgVoip) {
TgVoipFinalState finalState = _tgVoip->stop();
NSString *debugLog = [NSString stringWithUTF8String:finalState.debugLog.c_str()];
_lastDerivedState = [[NSData alloc] initWithBytes:finalState.persistentState.value.data() length:finalState.persistentState.value.size()];
delete _tgVoip;
_tgVoip = NULL;
if (completion) {
completion(debugLog, finalState.trafficStats.bytesSentWifi, finalState.trafficStats.bytesReceivedWifi, finalState.trafficStats.bytesSentMobile, finalState.trafficStats.bytesReceivedMobile);
}
}
}
- (NSString *)debugInfo {
if (_tgVoip != nil) {
NSString *version = [self version];
return [NSString stringWithFormat:@"WebRTC, Version: %@", version];
//auto rawDebugString = _tgVoip->getDebugInfo();
//return [NSString stringWithUTF8String:rawDebugString.c_str()];
} else {
return nil;
}
}
- (NSString *)version {
if (_tgVoip != nil) {
return @"2.7.7";//[NSString stringWithUTF8String:_tgVoip->getVersion().c_str()];
} else {
return nil;
}
}
- (NSData * _Nonnull)getDerivedState {
if (_tgVoip) {
auto persistentState = _tgVoip->getPersistentState();
return [[NSData alloc] initWithBytes:persistentState.value.data() length:persistentState.value.size()];
} else if (_lastDerivedState != nil) {
return _lastDerivedState;
} else {
return [NSData data];
}
}
- (void)controllerStateChanged:(TgVoipState)state {
OngoingCallStateWebrtc callState = OngoingCallStateInitializing;
switch (state) {
case TgVoipState::Estabilished:
callState = OngoingCallStateConnected;
break;
case TgVoipState::Failed:
callState = OngoingCallStateFailed;
break;
case TgVoipState::Reconnecting:
callState = OngoingCallStateReconnecting;
break;
default:
break;
}
if (callState != _state) {
_state = callState;
if (_stateChanged) {
_stateChanged(callState);
}
}
}
- (void)signalBarsChanged:(int32_t)signalBars {
if (signalBars != _signalBars) {
_signalBars = signalBars;
if (_signalBarsChanged) {
_signalBarsChanged(signalBars);
}
}
}
- (void)setIsMuted:(bool)isMuted {
if (_tgVoip) {
_tgVoip->setMuteMicrophone(isMuted);
}
}
- (void)setNetworkType:(OngoingCallNetworkTypeWebrtc)networkType {
if (_networkType != networkType) {
_networkType = networkType;
if (_tgVoip) {
_tgVoip->setNetworkType(callControllerNetworkTypeForType(networkType));
}
}
}
@end