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;
}