From 0437cc9199eb0bfa3c9b973a275bd228c10974b2 Mon Sep 17 00:00:00 2001 From: cruizba Date: Fri, 11 Feb 2022 20:03:26 +0100 Subject: [PATCH] Add customIceServers to openvidu-node-client. Send customIceServers to openvidu-browser in 'joinRoom' response --- .../client/internal/ProtocolElements.java | 1 + .../io/openvidu/java/client/Connection.java | 13 ++++++ .../java/client/ConnectionProperties.java | 2 +- .../java/client/IceServerProperties.java | 17 ++++++++ openvidu-node-client/src/Connection.ts | 14 ++++++- .../src/ConnectionProperties.ts | 27 ++++++++++++ .../src/IceServerProperties.ts | 42 +++++++++++++++++++ openvidu-node-client/src/Session.ts | 3 +- openvidu-node-client/src/index.ts | 3 +- .../server/core/SessionEventsHandler.java | 6 +++ .../java/io/openvidu/server/core/Token.java | 11 +++++ 11 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 openvidu-node-client/src/IceServerProperties.ts diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java index 85a327d5..9574b48c 100644 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java +++ b/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java @@ -165,6 +165,7 @@ public class ProtocolElements { public static final String PARTICIPANTJOINED_ROLE_PARAM = "role"; public static final String PARTICIPANTJOINED_COTURNIP_PARAM = "coturnIp"; public static final String PARTICIPANTJOINED_COTURNPORT_PARAM = "coturnPort"; + public static final String PARTICIPANTJOINED_CUSTOM_ICE_SERVERS = "customIceServers"; public static final String PARTICIPANTJOINED_TURNUSERNAME_PARAM = "turnUsername"; public static final String PARTICIPANTJOINED_TURNCREDENTIAL_PARAM = "turnCredential"; diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java index 3e7ba5dd..a833f3b9 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Connection.java @@ -192,6 +192,19 @@ public class Connection { return this.connectionProperties.getNetworkCache(); } + /** + * Returns a list of custom ICE Servers configured for this connection. + *

+ * See {@link io.openvidu.java.client.ConnectionProperties.Builder#addCustomIceServer(IceServerProperties)} for more + * information. + *

+ * Only for + * {@link io.openvidu.java.client.ConnectionType#WEBRTC} + */ + public List getCustomIceServers() { + return this.connectionProperties.getCustomIceServers(); + } + /** * Returns the token string associated to the Connection. This is the value that * must be sent to the client-side to be consumed in OpenVidu Browser method diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/ConnectionProperties.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/ConnectionProperties.java index a14e1607..a9125dec 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/ConnectionProperties.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/ConnectionProperties.java @@ -243,7 +243,7 @@ public class ConnectionProperties { * The level of precedence for ICE Server configuration on every OpenVidu connection is: *
    *
  1. Configured ICE Server using Openvidu.setAdvancedCofiguration() at openvidu-browser.
  2. - *
  3. Configured ICE server at + *
  4. Configured ICE server at * {@link io.openvidu.java.client.ConnectionProperties#customIceServers ConnectionProperties.customIceServers}
  5. *
  6. Configured ICE Server at global configuration parameter: OPENVIDU_WEBRTC_ICE_SERVERS
  7. *
  8. Default deployed Coturn within OpenVidu deployment
  9. diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java index a478a1fa..c9f72876 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/IceServerProperties.java @@ -1,3 +1,20 @@ +/* + * (C) Copyright 2017-2020 OpenVidu (https://openvidu.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package io.openvidu.java.client; import com.google.gson.JsonObject; diff --git a/openvidu-node-client/src/Connection.ts b/openvidu-node-client/src/Connection.ts index 35d8ba81..a54c36c0 100644 --- a/openvidu-node-client/src/Connection.ts +++ b/openvidu-node-client/src/Connection.ts @@ -18,6 +18,7 @@ import { Publisher } from './Publisher'; import { ConnectionProperties } from './ConnectionProperties'; import { OpenViduRole } from './OpenViduRole'; +import { IceServerProperties } from './IceServerProperties'; /** * See [[Session.connections]] @@ -138,6 +139,7 @@ export class Connection { this.connectionProperties.adaptativeBitrate = json.adaptativeBitrate; this.connectionProperties.onlyPlayWithSubscribers = json.onlyPlayWithSubscribers; this.connectionProperties.networkCache = json.networkCache; + this.connectionProperties.customIceServers = json.customIceServers ?? [] } else { this.connectionProperties = { type: json.type, @@ -148,7 +150,8 @@ export class Connection { rtspUri: json.rtspUri, adaptativeBitrate: json.adaptativeBitrate, onlyPlayWithSubscribers: json.onlyPlayWithSubscribers, - networkCache: json.networkCache + networkCache: json.networkCache, + customIceServers: json.customIceServers ?? [] } } this.role = json.role; @@ -224,6 +227,7 @@ export class Connection { this.connectionProperties.adaptativeBitrate === other.connectionProperties.adaptativeBitrate && this.connectionProperties.onlyPlayWithSubscribers === other.connectionProperties.onlyPlayWithSubscribers && this.connectionProperties.networkCache === other.connectionProperties.networkCache && + this.connectionProperties.customIceServers.length === other.connectionProperties.customIceServers.length && this.token === other.token && this.location === other.location && this.ip === other.ip && @@ -238,6 +242,14 @@ export class Connection { equals = (this.connectionProperties.kurentoOptions === other.connectionProperties.kurentoOptions); } } + if (equals) { + if (this.connectionProperties.customIceServers != null) { + const simpleIceComparator = (a: IceServerProperties, b: IceServerProperties) => (a.url > b.url) ? 1 : -1 + const sortedIceServers = this.connectionProperties.customIceServers.sort(simpleIceComparator); + const sortedOtherIceServers = other.connectionProperties.customIceServers.sort(simpleIceComparator); + equals = JSON.stringify(sortedIceServers) === JSON.stringify(sortedOtherIceServers); + } + } if (equals) { equals = JSON.stringify(this.subscribers.sort()) === JSON.stringify(other.subscribers.sort()); if (equals) { diff --git a/openvidu-node-client/src/ConnectionProperties.ts b/openvidu-node-client/src/ConnectionProperties.ts index ca88e962..77321c19 100644 --- a/openvidu-node-client/src/ConnectionProperties.ts +++ b/openvidu-node-client/src/ConnectionProperties.ts @@ -15,6 +15,7 @@ * */ +import { IceServerProperties } from './IceServerProperties'; import { ConnectionType } from './ConnectionType'; import { OpenViduRole } from './OpenViduRole'; @@ -127,4 +128,30 @@ export interface ConnectionProperties { */ networkCache?: number; + /** + * On certain type of networks, clients using default OpenVidu STUN/TURN server can not be reached it because + * firewall rules and network topologies at the client side. This method allows you to configure your + * own ICE Server for specific connections if you need it. This is usually not necessary, only it is usefull for + * OpenVidu users behind firewalls which allows traffic from/to specific ports which may need a custom + * ICE Server configuration + * + * Add an ICE Server if in your use case you need this connection to use your own ICE Server deployment. + * When the user uses this connection, it will use the specified ICE Servers defined here. + * + * The level of precedence for ICE Server configuration on every OpenVidu connection is: + * + * 1. Configured ICE Server using Openvidu.setAdvancedCofiguration() at openvidu-browser. + * 2. Configured ICE server at [[ConnectionProperties.customIceServers]]. + * 3. Configured ICE Server at global configuration parameter: `OPENVIDU_WEBRTC_ICE_SERVERS`. + * 4. Default deployed Coturn within OpenVidu deployment. + * + * + * If no value is found at level 1, level 2 will be used, and so on until level 4. + * + * This method is equivalent to level 2 of precedence. + * + * **Only for [[ConnectionType.WEBRTC]]** + * + */ + customIceServers?: IceServerProperties[]; } \ No newline at end of file diff --git a/openvidu-node-client/src/IceServerProperties.ts b/openvidu-node-client/src/IceServerProperties.ts new file mode 100644 index 00000000..3484ea04 --- /dev/null +++ b/openvidu-node-client/src/IceServerProperties.ts @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2017-2020 OpenVidu (https://openvidu.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export interface IceServerProperties { + + /** + * Set the url for the ICE Server you want to use. + * It should follow a valid format: + * + * - [https://datatracker.ietf.org/doc/html/rfc7065#section-3.1](https://datatracker.ietf.org/doc/html/rfc7065#section-3.1) + * - [https://datatracker.ietf.org/doc/html/rfc7064#section-3.1](https://datatracker.ietf.org/doc/html/rfc7064#section-3.1) + * + */ + url: string; + + /** + * Set a username for the ICE Server you want to use. + * This parameter should be defined only for TURN, not for STUN ICE Servers. + */ + username?: string; + + /** + * Set a credential for the ICE Server you want to use. + * This parameter should be defined only for TURN, not for STUN ICE Servers. + */ + credential?: string; + +} \ No newline at end of file diff --git a/openvidu-node-client/src/Session.ts b/openvidu-node-client/src/Session.ts index 9ca089a2..d006d179 100644 --- a/openvidu-node-client/src/Session.ts +++ b/openvidu-node-client/src/Session.ts @@ -150,7 +150,8 @@ export class Session { rtspUri: (!!connectionProperties && !!connectionProperties.rtspUri) ? connectionProperties.rtspUri : null, adaptativeBitrate: !!connectionProperties ? connectionProperties.adaptativeBitrate : null, onlyPlayWithSubscribers: !!connectionProperties ? connectionProperties.onlyPlayWithSubscribers : null, - networkCache: (!!connectionProperties && (connectionProperties.networkCache != null)) ? connectionProperties.networkCache : null + networkCache: (!!connectionProperties && (connectionProperties.networkCache != null)) ? connectionProperties.networkCache : null, + customIceServers: (!!connectionProperties && (!!connectionProperties.customIceServers != null)) ? connectionProperties.customIceServers : null }); axios.post( this.ov.host + OpenVidu.API_SESSIONS + '/' + this.sessionId + '/connection', diff --git a/openvidu-node-client/src/index.ts b/openvidu-node-client/src/index.ts index 669b4e90..80b7989c 100644 --- a/openvidu-node-client/src/index.ts +++ b/openvidu-node-client/src/index.ts @@ -12,4 +12,5 @@ export * from './Recording'; export * from './RecordingProperties'; export * from './Connection'; export * from './Publisher'; -export * from './VideoCodec'; \ No newline at end of file +export * from './VideoCodec'; +export * from './IceServerProperties'; \ No newline at end of file diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java index 27f675c0..bb9c592e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import io.openvidu.java.client.IceServerProperties; import org.kurento.client.GenericMediaEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -186,6 +187,11 @@ public class SessionEventsHandler { } result.addProperty(ProtocolElements.PARTICIPANTJOINED_COTURNIP_PARAM, openviduConfig.getCoturnIp()); result.addProperty(ProtocolElements.PARTICIPANTJOINED_COTURNPORT_PARAM, openviduConfig.getCoturnPort()); + List customIceServers = participant.getToken().getCustomIceServers(); + if (customIceServers!= null && !customIceServers.isEmpty()) { + result.add(ProtocolElements.PARTICIPANTJOINED_CUSTOM_ICE_SERVERS, + participant.getToken().getCustomIceServersAsJson()); + } if (participant.getToken().getTurnCredentials() != null) { result.addProperty(ProtocolElements.PARTICIPANTJOINED_TURNUSERNAME_PARAM, participant.getToken().getTurnCredentials().getUsername()); diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Token.java b/openvidu-server/src/main/java/io/openvidu/server/core/Token.java index 6633a761..a9dbe3bc 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Token.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Token.java @@ -17,6 +17,7 @@ package io.openvidu.server.core; +import com.google.gson.JsonArray; import io.openvidu.java.client.*; import org.apache.commons.lang3.RandomStringUtils; @@ -143,6 +144,16 @@ public class Token { return json; } + public JsonArray getCustomIceServersAsJson() { + JsonArray customIceServersJsonList = new JsonArray(); + if (this.connectionProperties.getCustomIceServers() != null) { + this.connectionProperties.getCustomIceServers().forEach((customIceServer) -> { + customIceServersJsonList.add(customIceServer.toJson()); + }); + } + return customIceServersJsonList; + } + public JsonObject toJsonAsParticipant() { JsonObject json = new JsonObject(); json.addProperty("id", this.getConnectionId());