diff --git a/ios/RTCPjSip/PjSipAccount.m b/ios/RTCPjSip/PjSipAccount.m index f66ade68..b68e8d2d 100755 --- a/ios/RTCPjSip/PjSipAccount.m +++ b/ios/RTCPjSip/PjSipAccount.m @@ -116,6 +116,36 @@ - (id)initWithConfig:(NSDictionary *)config { } } } + // TURN settings + NSDictionary *turnConfiguration = config[@"turn"]; + if (turnConfiguration) { + NSString *turnServer = turnConfiguration[@"server"]; + NSString *transportType = turnConfiguration[@"tp_type"]; + NSString *realm = turnConfiguration[@"realm"]; + NSString *username = turnConfiguration[@"username"]; + NSString *passwordDataType = turnConfiguration[@"password_data_type"]; + NSString *passwordData = turnConfiguration[@"data"]; + + pjsua_turn_config turnConfig; + turnConfig.enable_turn = PJ_TRUE; + NSAssert(turnServer, @"TURN server is required"); + turnConfig.turn_server = pj_str((char *)turnServer.UTF8String); + + if (transportType != nil && [transportType isEqualToString:@"TP_TCP"]) { + turnConfig.turn_conn_type = PJ_TURN_TP_TCP; + } + NSAssert(realm, @"realm is required"); + turnConfig.turn_auth_cred.data.static_cred.realm = pj_str((char *)realm.UTF8String); + NSAssert(username, @"username is required"); + turnConfig.turn_auth_cred.data.static_cred.username = pj_str((char *)username.UTF8String); + NSAssert(passwordData, @"passwordData is required"); + turnConfig.turn_auth_cred.data.static_cred.data = pj_str((char *)passwordData.UTF8String); + + bool isHashed = passwordDataType != nil && [passwordDataType isEqualToString:@"HASHED"]; + turnConfig.turn_auth_cred.data.static_cred.data_type = isHashed ? PJ_STUN_PASSWD_HASHED : PJ_STUN_PASSWD_PLAIN; + cfg.turn_cfg = turnConfig; + cfg.turn_cfg_use = PJSUA_TURN_CONFIG_USE_CUSTOM; + } pjsua_acc_id account_id; diff --git a/ios/RTCPjSip/PjSipEndpoint.h b/ios/RTCPjSip/PjSipEndpoint.h index 210594bb..eec36c43 100755 --- a/ios/RTCPjSip/PjSipEndpoint.h +++ b/ios/RTCPjSip/PjSipEndpoint.h @@ -8,7 +8,9 @@ @property NSMutableDictionary* accounts; @property NSMutableDictionary* calls; -@property(nonatomic, strong) RCTBridge *bridge; +@property (nonatomic, strong) RCTBridge *bridge; +@property (nonatomic, strong) NSArray *stunServerList; +@property (nonatomic, strong) NSDictionary *turnServerConfig; @property pjsua_transport_id tcpTransportId; @property pjsua_transport_id udpTransportId; @@ -22,6 +24,34 @@ -(void) updateStunServers: (int) accountId stunServerList:(NSArray *)stunServerList; +/** + * @brief TURN configuration + * @discussion This method accepts a key-value object with TURN server configuration. + * + * Usage: + * server - Specify TURN domain name or host name in "DOMAIN:PORT" or "HOST:PORT" format. + * value type: string + * + * tp_type - TURN transport type. + * value type: string + * value: "TP_UDP" or "TP_TCP". + * + * realm - If not-empty, it indicates that this is a long term credential. + * value type: string + * + * username - The username of the credential. + * value type: string + * + * password_data_type - Data type to indicate the type of password in the \a data field. + * value type: string + * value: "PLAIN" or "HASHED". + * + * data - The data, which depends depends on the value of \a data_type + * field. When \a data_type is zero, this field will contain the + * plaintext password. + */ +-(void) updateTurnSever: (int) accountId configuration: (NSDictionary*) turnConfiguration; + -(PjSipAccount *)createAccount:(NSDictionary*) config; -(void) deleteAccount:(int) accountId; -(PjSipAccount *)findAccount:(int)accountId; diff --git a/ios/RTCPjSip/PjSipEndpoint.m b/ios/RTCPjSip/PjSipEndpoint.m index 3470b693..a79d0275 100755 --- a/ios/RTCPjSip/PjSipEndpoint.m +++ b/ios/RTCPjSip/PjSipEndpoint.m @@ -161,10 +161,25 @@ - (NSDictionary *)start: (NSDictionary *)config { [callsResult addObject:[call toJsonDictionary:self.isSpeaker]]; } - if ([accountsResult count] > 0 && config[@"service"] && config[@"service"][@"stun"]) { - for (NSDictionary *account in accountsResult) { - int accountId = account[@"_data"][@"id"]; - [[PjSipEndpoint instance] updateStunServers:accountId stunServerList:config[@"service"][@"stun"]]; + NSArray *stunServerList = config[@"service"][@"stun"]; + if (stunServerList) { + self.stunServerList = stunServerList; + if ([accountsResult count] > 0) { + for (NSDictionary *account in accountsResult) { + int accountId = (int)account[@"_data"][@"id"]; + [[PjSipEndpoint instance] updateStunServers:accountId stunServerList:stunServerList]; + + } + } + } + NSDictionary *turnServerConfiguration = config[@"service"][@"turn"]; + if (turnServerConfiguration) { + self.turnServerConfig = turnServerConfiguration; + if ([accountsResult count] > 0) { + for (NSDictionary *account in accountsResult) { + int accountId = (int)account[@"_data"][@"id"]; + [[PjSipEndpoint instance] updateTurnSever: accountId configuration: turnServerConfiguration]; + } } } @@ -190,10 +205,50 @@ - (void)updateStunServers:(int)accountId stunServerList:(NSArray *)stunServerLis pjsua_acc_modify(accountId, &cfg_update); } +-(void) updateTurnSever: (int) accountId configuration: (NSDictionary*) turnConfiguration { + pjsua_acc_config cfg_update; + pj_pool_t *pool = pjsua_pool_create("tmp-pjsua", 1000, 1000); + pjsua_acc_config_default(&cfg_update); + pjsua_acc_get_config(accountId, pool, &cfg_update); + + pjsua_acc_modify(accountId, &cfg_update); + NSString *turnServer = turnConfiguration[@"server"]; + NSString *transportType = turnConfiguration[@"tp_type"]; + NSString *realm = turnConfiguration[@"realm"]; + NSString *username = turnConfiguration[@"username"]; + NSString *passwordDataType = turnConfiguration[@"password_data_type"]; + NSString *passwordData = turnConfiguration[@"data"]; + + pjsua_turn_config turnConfig; + turnConfig.enable_turn = PJ_TRUE; + NSAssert(turnServer, @"TURN server is required"); + turnConfig.turn_server = pj_str((char *)turnServer.UTF8String); + + if (transportType != nil && [transportType isEqualToString:@"TP_TCP"]) { + turnConfig.turn_conn_type = PJ_TURN_TP_TCP; + } + NSAssert(realm, @"realm is required"); + turnConfig.turn_auth_cred.data.static_cred.realm = pj_str((char *)realm.UTF8String); + NSAssert(username, @"username is required"); + turnConfig.turn_auth_cred.data.static_cred.username = pj_str((char *)username.UTF8String); + NSAssert(passwordData, @"passwordData is required"); + turnConfig.turn_auth_cred.data.static_cred.data = pj_str((char *)passwordData.UTF8String); + bool isHashed = passwordDataType != nil && [passwordDataType isEqualToString:@"HASHED"]; + turnConfig.turn_auth_cred.data.static_cred.data_type = isHashed ? PJ_STUN_PASSWD_HASHED : PJ_STUN_PASSWD_PLAIN; + cfg_update.turn_cfg = turnConfig; + pjsua_acc_modify(accountId, &cfg_update); + pj_pool_release(pool); +} + - (PjSipAccount *)createAccount:(NSDictionary *)config { PjSipAccount *account = [PjSipAccount itemConfig:config]; self.accounts[@(account.id)] = account; - + if (self.stunServerList) { + [[PjSipEndpoint instance] updateStunServers:account.id stunServerList:self.stunServerList]; + } + if (self.turnServerConfig) { + [[PjSipEndpoint instance] updateTurnSever:account.id configuration:self.turnServerConfig]; + } return account; }