POST Connection API

pull/553/head
pabloFuente 2020-10-20 22:09:06 +02:00
parent 06a602cf62
commit f989b0c2ee
31 changed files with 1350 additions and 956 deletions

View File

@ -39,7 +39,8 @@ public class Connection {
private String location; private String location;
private String platform; private String platform;
private String clientData; private String clientData;
private Token token; private ConnectionOptions connectionOptions;
private String token;
protected Map<String, Publisher> publishers = new ConcurrentHashMap<>(); protected Map<String, Publisher> publishers = new ConcurrentHashMap<>();
protected List<String> subscribers = new ArrayList<>(); protected List<String> subscribers = new ArrayList<>();
@ -49,7 +50,7 @@ public class Connection {
} }
/** /**
* Returns the identifier of the connection. You can call methods * Returns the identifier of the Connection. You can call methods
* {@link io.openvidu.java.client.Session#forceDisconnect(String)} or * {@link io.openvidu.java.client.Session#forceDisconnect(String)} or
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)} * {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)}
* passing this property as parameter * passing this property as parameter
@ -59,7 +60,7 @@ public class Connection {
} }
/** /**
* Returns the status of the connection. Can be: * Returns the status of the Connection. Can be:
* <ul> * <ul>
* <li><code>pending</code>: if the Connection is waiting for any user to use * <li><code>pending</code>: if the Connection is waiting for any user to use
* its internal token to connect to the session, calling method <a href= * its internal token to connect to the session, calling method <a href=
@ -74,7 +75,7 @@ public class Connection {
} }
/** /**
* Timestamp when this connection was created, in UTC milliseconds (ms since Jan * Timestamp when this Connection was created, in UTC milliseconds (ms since Jan
* 1, 1970, 00:00:00 UTC) * 1, 1970, 00:00:00 UTC)
*/ */
public Long createdAt() { public Long createdAt() {
@ -82,7 +83,7 @@ public class Connection {
} }
/** /**
* Timestamp when this connection was taken by a user (passing from status * Timestamp when this Connection was taken by a user (passing from status
* "pending" to "active"), in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 * "pending" to "active"), in UTC milliseconds (ms since Jan 1, 1970, 00:00:00
* UTC) * UTC)
*/ */
@ -91,19 +92,19 @@ public class Connection {
} }
/** /**
* Returns the role of the connection * Returns the type of Connection.
*/ */
public OpenViduRole getRole() { public ConnectionType getType() {
return this.token.getRole(); return this.connectionOptions.getType();
} }
/** /**
* Returns the data associated to the connection on the server-side. This value * Returns the data associated to the Connection on the server-side. This value
* is set with {@link io.openvidu.java.client.TokenOptions.Builder#data(String)} * is set with {@link io.openvidu.java.client.TokenOptions.Builder#data(String)}
* when calling {@link io.openvidu.java.client.Session#generateToken()} * when calling {@link io.openvidu.java.client.Session#generateToken()}
*/ */
public String getServerData() { public String getServerData() {
return this.token.getData(); return this.connectionOptions.getData();
} }
/** /**
@ -113,14 +114,86 @@ public class Connection {
* target="_blank">INDIVIDUAL recording</a>. * target="_blank">INDIVIDUAL recording</a>.
*/ */
public boolean record() { public boolean record() {
return this.token.record(); return this.connectionOptions.record();
} }
/** /**
* Returns the token string associated to the connection * Returns the role of the Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#WEBRTC}</strong>
*/
public OpenViduRole getRole() {
return this.connectionOptions.getRole();
}
/**
* Returns the RTSP URI of the Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public String getRtspUri() {
return this.connectionOptions.getRtspUri();
}
/**
* Whether the Connection uses adaptative bitrate (and therefore adaptative
* quality) or not. For local network connections that do not require media
* transcoding this can be disabled to save CPU power. If you are not sure if
* transcoding might be necessary, setting this property to false <strong>may
* result in media connections not being established</strong>.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public boolean adaptativeBitrate() {
return this.connectionOptions.adaptativeBitrate();
}
/**
* Whether the IP camera stream of this Connection will only be enabled when
* some user is subscribed to it, or not. This allows you to reduce power
* consumption and network bandwidth in your server while nobody is asking to
* receive the camera's video. On the counterpart, first user subscribing to the
* IP camera stream will take a little longer to receive its video.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public boolean onlyPlayWithSubscribers() {
return this.connectionOptions.onlyPlayWithSubscribers();
}
/**
* Returns the size of the buffer of the endpoint receiving the IP camera's
* stream, in milliseconds. The smaller it is, the less delay the signal will
* have, but more problematic will be in unstable networks. Use short buffers
* only if there is a quality connection between the IP camera and OpenVidu
* Server.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public int getNetworkCache() {
return this.connectionOptions.getNetworkCache();
}
/**
* Returns the token string associated to the Connection
*/ */
public String getToken() { public String getToken() {
return this.token.getToken(); return this.token;
} }
/** /**
@ -180,17 +253,23 @@ public class Connection {
protected JsonObject toJson() { protected JsonObject toJson() {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("id", this.getConnectionId()); json.addProperty("connectionId", this.getConnectionId());
json.addProperty("status", this.getStatus()); json.addProperty("status", this.getStatus());
json.addProperty("createdAt", this.createdAt()); json.addProperty("createdAt", this.createdAt());
json.addProperty("activeAt", this.activeAt()); json.addProperty("activeAt", this.activeAt());
json.addProperty("location", this.getLocation()); json.addProperty("location", this.getLocation());
json.addProperty("platform", this.getPlatform()); json.addProperty("platform", this.getPlatform());
json.addProperty("token", this.getToken());
json.addProperty("role", this.getRole().name());
json.addProperty("serverData", this.getServerData());
json.addProperty("record", this.record());
json.addProperty("clientData", this.getClientData()); json.addProperty("clientData", this.getClientData());
json.addProperty("token", this.getToken());
JsonObject jsonConnectionOptions = this.connectionOptions.toJson("");
jsonConnectionOptions.remove("session");
json.addProperty("serverData", jsonConnectionOptions.get("data").getAsString());
jsonConnectionOptions.remove("data");
jsonConnectionOptions.entrySet().forEach(entry -> {
json.add(entry.getKey(), entry.getValue());
});
JsonArray pubs = new JsonArray(); JsonArray pubs = new JsonArray();
this.getPublishers().forEach(p -> { this.getPublishers().forEach(p -> {
pubs.add(p.toJson()); pubs.add(p.toJson());
@ -204,14 +283,33 @@ public class Connection {
return json; return json;
} }
/** protected void overrideConnectionOptions(ConnectionOptions newConnectionOptions) {
* For now only properties data, role and record can be updated ConnectionOptions.Builder builder = new ConnectionOptions.Builder();
*/ // For now only properties role and record can be updated
protected void overrideConnectionOptions(ConnectionOptions connectionOptions) { if (newConnectionOptions.getRole() != null) {
TokenOptions.Builder modifiableTokenOptions = new TokenOptions.Builder().role(connectionOptions.getRole()) builder.role(newConnectionOptions.getRole());
.record(connectionOptions.record()); } else {
modifiableTokenOptions.data(this.token.getData()); builder.role(this.connectionOptions.getRole());
this.token.overrideTokenOptions(modifiableTokenOptions.build()); }
if (newConnectionOptions.record() != null) {
builder.record(newConnectionOptions.record());
} else {
builder.record(this.connectionOptions.record());
}
// Keep old configuration in the rest of properties
builder.type(this.connectionOptions.getType()).data(this.connectionOptions.getData())
.kurentoOptions(this.connectionOptions.getKurentoOptions())
.rtspUri(this.connectionOptions.getRtspUri());
if (this.connectionOptions.adaptativeBitrate() != null) {
builder.adaptativeBitrate(this.connectionOptions.adaptativeBitrate());
}
if (this.connectionOptions.onlyPlayWithSubscribers() != null) {
builder.onlyPlayWithSubscribers(this.connectionOptions.onlyPlayWithSubscribers());
}
if (this.connectionOptions.getNetworkCache() != null) {
builder.networkCache(this.connectionOptions.getNetworkCache());
}
this.connectionOptions = builder.build();
} }
protected void setSubscribers(List<String> subscribers) { protected void setSubscribers(List<String> subscribers) {
@ -220,6 +318,10 @@ public class Connection {
protected Connection resetWithJson(JsonObject json) { protected Connection resetWithJson(JsonObject json) {
this.connectionId = json.get("connectionId").getAsString();
this.status = json.get("status").getAsString();
this.token = !json.get("token").isJsonNull() ? json.get("token").getAsString() : null;
if (!json.get("publishers").isJsonNull()) { if (!json.get("publishers").isJsonNull()) {
JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray(); JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray();
@ -284,16 +386,34 @@ public class Connection {
this.clientData = json.get("clientData").getAsString(); this.clientData = json.get("clientData").getAsString();
} }
// These properties won't ever be null // COMMON
this.connectionId = json.get("connectionId").getAsString(); ConnectionType type = ConnectionType.valueOf(json.get("type").getAsString());
this.status = json.get("status").getAsString(); String data = (json.has("serverData") && !json.get("serverData").isJsonNull())
String token = json.has("token") ? json.get("token").getAsString() : null; ? json.get("serverData").getAsString()
OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString()); : null;
String data = json.get("serverData").getAsString(); Boolean record = (json.has("record") && !json.get("record").isJsonNull()) ? json.get("record").getAsBoolean()
Boolean record = json.get("record").getAsBoolean(); : null;
TokenOptions tokenOptions = new TokenOptions(role, data, record, null); // WEBRTC
this.token = new Token(token, this.connectionId, tokenOptions); OpenViduRole role = (json.has("role") && !json.get("role").isJsonNull())
? OpenViduRole.valueOf(json.get("role").getAsString())
: null;
// IPCAM
String rtspUri = (json.has("rtspUri") && !json.get("rtspUri").isJsonNull()) ? json.get("rtspUri").getAsString()
: null;
Boolean adaptativeBitrate = (json.has("adaptativeBitrate") && !json.get("adaptativeBitrate").isJsonNull())
? json.get("adaptativeBitrate").getAsBoolean()
: null;
Boolean onlyPlayWithSubscribers = (json.has("onlyPlayWithSubscribers")
&& !json.get("onlyPlayWithSubscribers").isJsonNull())
? json.get("onlyPlayWithSubscribers").getAsBoolean()
: null;
Integer networkCache = (json.has("networkCache") && !json.get("networkCache").isJsonNull())
? json.get("networkCache").getAsInt()
: null;
this.connectionOptions = new ConnectionOptions(type, data, record, role, null, rtspUri, adaptativeBitrate,
onlyPlayWithSubscribers, networkCache);
return this; return this;
} }

View File

@ -1,15 +1,26 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
/**
* See
* {@link io.openvidu.java.client.Session#createConnection(ConnectionOptions)}
*/
public class ConnectionOptions { public class ConnectionOptions {
private OpenViduRole role; private ConnectionType type;
// COMMON
private String data; private String data;
private Boolean record; private Boolean record;
// WEBRTC
private OpenViduRole role;
private KurentoOptions kurentoOptions; private KurentoOptions kurentoOptions;
// IPCAM
private String rtspUri;
private Boolean adaptativeBitrate;
private Boolean onlyPlayWithSubscribers;
private Integer networkCache;
/** /**
* *
@ -18,23 +29,58 @@ public class ConnectionOptions {
*/ */
public static class Builder { public static class Builder {
private OpenViduRole role = OpenViduRole.PUBLISHER; private ConnectionType type;
// COMMON
private String data; private String data;
private Boolean record = true; private Boolean record;
// WEBRTC
private OpenViduRole role;
private KurentoOptions kurentoOptions; private KurentoOptions kurentoOptions;
// IPCAM
private String rtspUri;
private Boolean adaptativeBitrate;
private Boolean onlyPlayWithSubscribers;
private Integer networkCache;
/** /**
* Builder for {@link io.openvidu.java.client.ConnectionOptions}. * Builder for {@link io.openvidu.java.client.ConnectionOptions}.
*/ */
public ConnectionOptions build() { public ConnectionOptions build() {
return new ConnectionOptions(this.role, this.data, this.record, this.kurentoOptions); return new ConnectionOptions(this.type, this.data, this.record, this.role, this.kurentoOptions,
this.rtspUri, this.adaptativeBitrate, this.onlyPlayWithSubscribers, this.networkCache);
} }
/** /**
* Call this method to set the role assigned to this Connection. * Call this method to set the type of Connection. The
* {@link io.openvidu.java.client.ConnectionType} dictates what properties will
* have effect:
* <ul>
* <li>{@link io.openvidu.java.client.ConnectionType#WEBRTC}:
* {@link io.openvidu.java.client.ConnectionOptions.Builder#data(String) data},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#record(boolean)
* record},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#role(OpenViduRole)
* role},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#kurentoOptions(KurentoOptions)
* kurentoOptions}</li>
* <li>{@link io.openvidu.java.client.ConnectionType#IPCAM}:
* {@link io.openvidu.java.client.ConnectionOptions.Builder#data(String) data},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#record(boolean)
* record},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#rtspUri(String)
* rtspUri},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#adaptativeBitrate(boolean)
* adaptativeBitrate},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#onlyPlayWithSubscribers(boolean)
* onlyPlayWithSubscribers},
* {@link io.openvidu.java.client.ConnectionOptions.Builder#networkCache(int)
* networkCache}</li>
* </ul>
* If not set by default will be @link
* io.openvidu.java.client.ConnectionType#WEBRTC}.
*/ */
public Builder role(OpenViduRole role) { public Builder type(ConnectionType type) {
this.role = role; this.type = type;
return this; return this;
} }
@ -76,29 +122,122 @@ public class ConnectionOptions {
return this; return this;
} }
/**
* Call this method to set the role assigned to this Connection. If not set by
* default will be {@link io.openvidu.java.client.OpenViduRole#PUBLISHER
* PUBLISHER}.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#WEBRTC}</strong>
*/
public Builder role(OpenViduRole role) {
this.role = role;
return this;
}
/** /**
* Call this method to set a {@link io.openvidu.java.client.KurentoOptions} * Call this method to set a {@link io.openvidu.java.client.KurentoOptions}
* object for this Connection. * object for this Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#WEBRTC}</strong>
*/ */
public Builder kurentoOptions(KurentoOptions kurentoOptions) { public Builder kurentoOptions(KurentoOptions kurentoOptions) {
this.kurentoOptions = kurentoOptions; this.kurentoOptions = kurentoOptions;
return this; return this;
} }
} /**
* Call this method to set the RTSP URI of an IP camera. For example:
ConnectionOptions(OpenViduRole role, String data, Boolean record, KurentoOptions kurentoOptions) { * <code>rtsp://your.camera.ip:7777/path</code>
this.role = role; *
this.data = data; * <br>
this.record = record; * <br>
this.kurentoOptions = kurentoOptions; * <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Builder rtspUri(String rtspUri) {
this.rtspUri = rtspUri;
return this;
} }
/** /**
* Returns the role assigned to this Connection. * Call this method to set whether to use adaptative bitrate (and therefore
* adaptative quality) or not. For local network connections that do not require
* media transcoding this can be disabled to save CPU power. If you are not sure
* if transcoding might be necessary, setting this property to false <strong>may
* result in media connections not being established</strong>. Default to
* <code>true</code>.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/ */
public OpenViduRole getRole() { public Builder adaptativeBitrate(boolean adaptativeBitrate) {
return this.role; this.adaptativeBitrate = adaptativeBitrate;
return this;
}
/**
* Call this method to set whether to enable the IP camera stream only when some
* user is subscribed to it, or not. This allows you to reduce power consumption
* and network bandwidth in your server while nobody is asking to receive the
* camera's video. On the counterpart, first user subscribing to the IP camera
* stream will take a little longer to receive its video. Default to
* <code>true</code>.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Builder onlyPlayWithSubscribers(boolean onlyPlayWithSubscribers) {
this.onlyPlayWithSubscribers = onlyPlayWithSubscribers;
return this;
}
/**
* Call this method to set the size of the buffer of the endpoint receiving the
* IP camera's stream, in milliseconds. The smaller it is, the less delay the
* signal will have, but more problematic will be in unstable networks. Use
* short buffers only if there is a quality connection between the IP camera and
* OpenVidu Server. Default to <code>2000</code>.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Builder networkCache(int networkCache) {
this.networkCache = networkCache;
return this;
}
}
ConnectionOptions(ConnectionType type, String data, Boolean record, OpenViduRole role,
KurentoOptions kurentoOptions, String rtspUri, Boolean adaptativeBitrate, Boolean onlyPlayWithSubscribers,
Integer networkCache) {
this.type = type;
this.data = data;
this.record = record;
this.role = role;
this.kurentoOptions = kurentoOptions;
this.rtspUri = rtspUri;
this.adaptativeBitrate = adaptativeBitrate;
this.onlyPlayWithSubscribers = onlyPlayWithSubscribers;
this.networkCache = networkCache;
}
/**
* Returns the type of Connection.
*/
public ConnectionType getType() {
return this.type;
} }
/** /**
@ -118,13 +257,97 @@ public class ConnectionOptions {
return this.record; return this.record;
} }
protected JsonObject toJsonObject(String sessionId) { /**
* Returns the role assigned to this Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#WEBRTC}</strong>
*/
public OpenViduRole getRole() {
return this.role;
}
/**
* Returns the KurentoOptions assigned to this Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#WEBRTC}</strong>
*/
public KurentoOptions getKurentoOptions() {
return this.kurentoOptions;
}
/**
* Returns the RTSP URI of this Connection.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public String getRtspUri() {
return this.rtspUri;
}
/**
* Whether this Connection uses adaptative bitrate (and therefore adaptative
* quality) or not. For local network connections that do not require media
* transcoding this can be disabled to save CPU power. If you are not sure if
* transcoding might be necessary, setting this property to false <strong>may
* result in media connections not being established</strong>.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Boolean adaptativeBitrate() {
return this.adaptativeBitrate;
}
/**
* Whether to enable the IP camera stream only when some user is subscribed to
* it. This allows you to reduce power consumption and network bandwidth in your
* server while nobody is asking to receive the camera's video. On the
* counterpart, first user subscribing to the IP camera stream will take a
* little longer to receive its video.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Boolean onlyPlayWithSubscribers() {
return this.onlyPlayWithSubscribers;
}
/**
* Size of the buffer of the endpoint receiving the IP camera's stream, in
* milliseconds. The smaller it is, the less delay the signal will have, but
* more problematic will be in unstable networks. Use short buffers only if
* there is a quality connection between the IP camera and OpenVidu Server.
*
* <br>
* <br>
* <strong>Only for
* {@link io.openvidu.java.client.ConnectionType#IPCAM}</strong>
*/
public Integer getNetworkCache() {
return this.networkCache;
}
public JsonObject toJson(String sessionId) {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("session", sessionId); json.addProperty("session", sessionId);
if (getRole() != null) { // COMMON
json.addProperty("role", getRole().name()); if (getType() != null) {
json.addProperty("type", getType().name());
} else { } else {
json.add("role", JsonNull.INSTANCE); json.add("type", JsonNull.INSTANCE);
} }
if (getData() != null) { if (getData() != null) {
json.addProperty("data", getData()); json.addProperty("data", getData());
@ -136,28 +359,37 @@ public class ConnectionOptions {
} else { } else {
json.add("record", JsonNull.INSTANCE); json.add("record", JsonNull.INSTANCE);
} }
// WEBRTC
if (getRole() != null) {
json.addProperty("role", getRole().name());
} else {
json.add("role", JsonNull.INSTANCE);
}
if (this.kurentoOptions != null) { if (this.kurentoOptions != null) {
JsonObject kurentoOptions = new JsonObject(); json.add("kurentoOptions", kurentoOptions.toJson());
if (this.kurentoOptions.getVideoMaxRecvBandwidth() != null) { } else {
kurentoOptions.addProperty("videoMaxRecvBandwidth", this.kurentoOptions.getVideoMaxRecvBandwidth()); json.add("kurentoOptions", JsonNull.INSTANCE);
} }
if (this.kurentoOptions.getVideoMinRecvBandwidth() != null) { // IPCAM
kurentoOptions.addProperty("videoMinRecvBandwidth", this.kurentoOptions.getVideoMinRecvBandwidth()); if (getRtspUri() != null) {
json.addProperty("rtspUri", getRtspUri());
} else {
json.add("rtspUri", JsonNull.INSTANCE);
} }
if (this.kurentoOptions.getVideoMaxSendBandwidth() != null) { if (adaptativeBitrate() != null) {
kurentoOptions.addProperty("videoMaxSendBandwidth", this.kurentoOptions.getVideoMaxSendBandwidth()); json.addProperty("adaptativeBitrate", adaptativeBitrate());
} else {
json.add("adaptativeBitrate", JsonNull.INSTANCE);
} }
if (this.kurentoOptions.getVideoMinSendBandwidth() != null) { if (onlyPlayWithSubscribers() != null) {
kurentoOptions.addProperty("videoMinSendBandwidth", this.kurentoOptions.getVideoMinSendBandwidth()); json.addProperty("onlyPlayWithSubscribers", onlyPlayWithSubscribers());
} else {
json.add("onlyPlayWithSubscribers", JsonNull.INSTANCE);
} }
if (this.kurentoOptions.getAllowedFilters().length > 0) { if (getNetworkCache() != null) {
JsonArray allowedFilters = new JsonArray(); json.addProperty("networkCache", getNetworkCache());
for (String filter : this.kurentoOptions.getAllowedFilters()) { } else {
allowedFilters.add(filter); json.add("networkCache", JsonNull.INSTANCE);
}
kurentoOptions.add("allowedFilters", allowedFilters);
}
json.add("kurentoOptions", kurentoOptions);
} }
return json; return json;
} }

View File

@ -17,6 +17,11 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import java.util.Arrays;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/** /**
* See {@link io.openvidu.java.client.TokenOptions#getKurentoOptions()} * See {@link io.openvidu.java.client.TokenOptions#getKurentoOptions()}
*/ */
@ -105,10 +110,10 @@ public class KurentoOptions {
} }
/** /**
* Defines the maximum number of Kbps that the client owning the token will be * Defines the maximum number of Kbps that the Connection will be able to
* able to receive from Kurento Media Server. 0 means unconstrained. Giving a * receive from Kurento Media Server per media stream. 0 means unconstrained.
* value to this property will override the global configuration set in <a * Giving a value to this property will override the global configuration set in
* href="https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/" * <a href="https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/"
* target="_blank">OpenVidu Server configuration</a> (parameter * target="_blank">OpenVidu Server configuration</a> (parameter
* <code>OPENVIDU_STREAMS_VIDEO_MAX_RECV_BANDWIDTH</code>) for every incoming * <code>OPENVIDU_STREAMS_VIDEO_MAX_RECV_BANDWIDTH</code>) for every incoming
* stream of the user owning the token. <br> * stream of the user owning the token. <br>
@ -122,10 +127,10 @@ public class KurentoOptions {
} }
/** /**
* Defines the minimum number of Kbps that the client owning the token will try * Defines the minimum number of Kbps that the Connection will try to receive
* to receive from Kurento Media Server. 0 means unconstrained. Giving a value * from Kurento Media Server per media stream. 0 means unconstrained. Giving a
* to this property will override the global configuration set in <a href= * value to this property will override the global configuration set in
* "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/" * <a href= "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/"
* target="_blank">OpenVidu Server configuration</a> (parameter * target="_blank">OpenVidu Server configuration</a> (parameter
* <code>OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH</code>) for every incoming * <code>OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH</code>) for every incoming
* stream of the user owning the token. * stream of the user owning the token.
@ -135,10 +140,10 @@ public class KurentoOptions {
} }
/** /**
* Defines the maximum number of Kbps that the client owning the token will be * Defines the maximum number of Kbps that the Connection will be able to send
* able to send to Kurento Media Server. 0 means unconstrained. Giving a value * to Kurento Media Server per media stream. 0 means unconstrained. Giving a
* to this property will override the global configuration set in <a href= * value to this property will override the global configuration set in
* "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/" * <a href= "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/"
* target="_blank">OpenVidu Server configuration</a> (parameter * target="_blank">OpenVidu Server configuration</a> (parameter
* <code>OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH</code>) for every outgoing * <code>OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH</code>) for every outgoing
* stream of the user owning the token. <br> * stream of the user owning the token. <br>
@ -151,10 +156,10 @@ public class KurentoOptions {
} }
/** /**
* Defines the minimum number of Kbps that the client owning the token will try * Defines the minimum number of Kbps that the Connection will try to send to
* to send to Kurento Media Server. 0 means unconstrained. Giving a value to * Kurento Media Server per media stream. 0 means unconstrained. Giving a value
* this property will override the global configuration set in <a href= * to this property will override the global configuration set in
* "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/" * <a href= "https://docs.openvidu.io/en/stable/reference-docs/openvidu-config/"
* target="_blank">OpenVidu Server configuration</a> (parameter * target="_blank">OpenVidu Server configuration</a> (parameter
* <code>OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH</code>) for every outgoing * <code>OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH</code>) for every outgoing
* stream of the user owning the token. * stream of the user owning the token.
@ -164,13 +169,50 @@ public class KurentoOptions {
} }
/** /**
* Defines the names of the filters the user owning the token will be able to * Defines the names of the filters the Connection will be able to apply to its
* apply. See * published streams. See
* <a href="https://docs.openvidu.io/en/stable/advanced-features/filters/" target= "_blank">Voice and * <a href="https://docs.openvidu.io/en/stable/advanced-features/filters/"
* video filters</a> * target= "_blank">Voice and video filters</a>.
*/ */
public String[] getAllowedFilters() { public String[] getAllowedFilters() {
return allowedFilters; return allowedFilters;
} }
/**
* See if the Connection can apply certain filter. See
* <a href="https://docs.openvidu.io/en/stable/advanced-features/filters/"
* target= "_blank">Voice and video filters</a>.
*/
public boolean isFilterAllowed(String filterType) {
if (filterType == null) {
return false;
}
return Arrays.stream(allowedFilters).anyMatch(filterType::equals);
}
public JsonObject toJson() {
JsonObject json = new JsonObject();
if (this.getVideoMaxRecvBandwidth() != null) {
json.addProperty("videoMaxRecvBandwidth", this.getVideoMaxRecvBandwidth());
}
if (this.getVideoMinRecvBandwidth() != null) {
json.addProperty("videoMinRecvBandwidth", this.getVideoMinRecvBandwidth());
}
if (this.getVideoMaxSendBandwidth() != null) {
json.addProperty("videoMaxSendBandwidth", this.getVideoMaxSendBandwidth());
}
if (this.getVideoMinSendBandwidth() != null) {
json.addProperty("videoMinSendBandwidth", this.getVideoMinSendBandwidth());
}
if (this.getAllowedFilters().length > 0) {
JsonArray filtersJson = new JsonArray();
String[] filters = this.getAllowedFilters();
for (String filter : filters) {
filtersJson.add(filter);
}
json.add("allowedFilters", filtersJson);
}
return json;
}
} }

View File

@ -497,6 +497,10 @@ public class OpenVidu {
* since the last time method {@link io.openvidu.java.client.OpenVidu#fetch()} * since the last time method {@link io.openvidu.java.client.OpenVidu#fetch()}
* was called</strong>. Exceptions to this rule are: * was called</strong>. Exceptions to this rule are:
* <ul> * <ul>
* <li>Calling
* {@link io.openvidu.java.client.OpenVidu#createSession(SessionProperties)
* OpenVidu.createSession} automatically adds the new Session object to the
* local collection.</li>
* <li>Calling {@link io.openvidu.java.client.Session#fetch()} updates that * <li>Calling {@link io.openvidu.java.client.Session#fetch()} updates that
* specific Session status</li> * specific Session status</li>
* <li>Calling {@link io.openvidu.java.client.Session#close()} automatically * <li>Calling {@link io.openvidu.java.client.Session#close()} automatically

View File

@ -89,8 +89,9 @@ public class Session {
} }
/** /**
* @deprecated Use {@link Session#createToken() Session.createToken()} instead * @deprecated Use {@link Session#createConnection() Session.createConnection()}
* to get a {@link io.openvidu.java.client.Token} object. * instead to get a {@link io.openvidu.java.client.Connection}
* object.
* *
* @return The generated token String * @return The generated token String
* *
@ -99,14 +100,14 @@ public class Session {
*/ */
@Deprecated @Deprecated
public String generateToken() throws OpenViduJavaClientException, OpenViduHttpException { public String generateToken() throws OpenViduJavaClientException, OpenViduHttpException {
return createToken().getToken(); return generateToken(new TokenOptions.Builder().data("").role(OpenViduRole.PUBLISHER).record(true).build());
} }
/** /**
* @deprecated Use * @deprecated Use
* {@link Session#createToken(io.openvidu.java.client.TokenOptions) * {@link Session#createConnection(io.openvidu.java.client.ConnectionOptions)
* Session.createToken(TokenOptions)} instead to get a * Session.createConnection(ConnectionOptions)} instead to get a
* {@link io.openvidu.java.client.Token} object. * {@link io.openvidu.java.client.Connection} object.
* *
* @return The generated token String * @return The generated token String
* *
@ -115,70 +116,6 @@ public class Session {
*/ */
@Deprecated @Deprecated
public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException { public String generateToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
return createToken(tokenOptions).getToken();
}
/**
* Gets a new token object associated to Session object with default values for
* {@link io.openvidu.java.client.TokenOptions}. The token string value to send
* to the client side can be retrieved with
* {@link io.openvidu.java.client.Token#getToken() Token.getToken()}. <br>
* <br>
* You can use method {@link io.openvidu.java.client.Token#getConnectionId()
* Token.getConnectionId()} to get the connection identifier that will be given
* to the user consuming the token. With <code>connectionId</code> you can call
* the following methods without having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* Session.forceDisconnect()} to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.</li>
* <li>Call
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)
* Session.updateConnection()} to update the
* {@link io.openvidu.java.client.Connection Connection} options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the connection options on the fly.</li>
* </ul>
*
* @return The generated {@link io.openvidu.java.client.Token Token} object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Token createToken() throws OpenViduJavaClientException, OpenViduHttpException {
return createToken(new TokenOptions.Builder().data("").role(OpenViduRole.PUBLISHER).record(true).build());
}
/**
* Gets a new token object associated to Session object configured with
* <code>tokenOptions</code>. The token string value to send to the client side
* can be retrieved with {@link io.openvidu.java.client.Token#getToken()
* Token.getToken()}. <br>
* <br>
* You can use method {@link io.openvidu.java.client.Token#getConnectionId()
* Token.getConnectionId()} to get the connection identifier that will be given
* to the user consuming the token. With <code>connectionId</code> you can call
* the following methods without having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* Session.forceDisconnect()} to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.</li>
* <li>Call
* {@link io.openvidu.java.client.Session#updateConnection(String, ConnectionOptions)
* Session.updateConnection()} to update the
* {@link io.openvidu.java.client.Connection Connection} options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the user connection options on the fly.</li>
* </ul>
*
* @return The generated {@link io.openvidu.java.client.Token Token} object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Token createToken(TokenOptions tokenOptions) throws OpenViduJavaClientException, OpenViduHttpException {
if (!this.hasSessionId()) { if (!this.hasSessionId()) {
this.getSessionId(); this.getSessionId();
} }
@ -205,8 +142,8 @@ public class Session {
try { try {
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) { if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
Token token = new Token(httpResponseToJson(response)); String token = httpResponseToJson(response).get("id").getAsString();
log.info("Returning a TOKEN: {}", token.getToken()); log.info("Returning a TOKEN: {}", token);
return token; return token;
} else { } else {
throw new OpenViduHttpException(statusCode); throw new OpenViduHttpException(statusCode);
@ -216,6 +153,75 @@ public class Session {
} }
} }
/**
* Same as
* {@link io.openvidu.java.client.Session#createConnection(ConnectionOptions)
* but with default ConnectionOptions values.
*
* @return The generated {@link io.openvidu.java.client.Connection Connection}
* object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Connection createConnection() throws OpenViduJavaClientException, OpenViduHttpException {
return createConnection(
new ConnectionOptions.Builder().data("").role(OpenViduRole.PUBLISHER).record(true).build());
}
/**
* Creates a new Connection object associated to Session object and configured
* with <code>connectionOptions</code>. Each user connecting to the Session
* requires a Connection. The token string value to send to the client side can
* be retrieved with {@link io.openvidu.java.client.Connection#getToken()
* Connection.getToken()}.
*
* @return The generated {@link io.openvidu.java.client.Connection Connection}
* object.
*
* @throws OpenViduJavaClientException
* @throws OpenViduHttpException
*/
public Connection createConnection(ConnectionOptions connectionOptions)
throws OpenViduJavaClientException, OpenViduHttpException {
if (!this.hasSessionId()) {
this.getSessionId();
}
HttpPost request = new HttpPost(
this.openVidu.hostname + OpenVidu.API_SESSIONS + "/" + this.sessionId + "/connection");
StringEntity params;
try {
params = new StringEntity(connectionOptions.toJson(sessionId).toString());
} catch (UnsupportedEncodingException e1) {
throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause());
}
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
request.setEntity(params);
HttpResponse response;
try {
response = this.openVidu.httpClient.execute(request);
} catch (IOException e2) {
throw new OpenViduJavaClientException(e2.getMessage(), e2.getCause());
}
try {
int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == org.apache.http.HttpStatus.SC_OK)) {
Connection connection = new Connection(httpResponseToJson(response));
this.connections.put(connection.getConnectionId(), connection);
return connection;
} else {
throw new OpenViduHttpException(statusCode);
}
} finally {
EntityUtils.consumeQuietly(response.getEntity());
}
}
/** /**
* Gracefully closes the Session: unpublishes all streams and evicts every * Gracefully closes the Session: unpublishes all streams and evicts every
* participant. * participant.
@ -298,24 +304,31 @@ public class Session {
} }
/** /**
* Forces the user represented by <code>connection</code> to leave the session. * Removes the Connection from the Session. This can translate into a forced
* OpenVidu Browser will trigger the proper events on the client-side * eviction of a user from the Session if the Connection had status
* (<code>streamDestroyed</code>, <code>connectionDestroyed</code>, * <code>active</code>, or into a token invalidation if no user had taken the
* Connection yet (status <code>pending</code>). <br>
* <br>
*
* In the first case, OpenVidu Browser will trigger the proper events on the
* client-side (<code>streamDestroyed</code>, <code>connectionDestroyed</code>,
* <code>sessionDisconnected</code>) with reason set to * <code>sessionDisconnected</code>) with reason set to
* <code>"forceDisconnectByServer"</code>. <br> * <code>"forceDisconnectByServer"</code>. <br>
* <br> * <br>
* *
* You can get <code>connection</code> parameter with * In the second case, the token of the Connection will be invalidated and no
* {@link io.openvidu.java.client.Session#fetch()} and then * user will be able to connect to the session with it. <br>
* {@link io.openvidu.java.client.Session#getActiveConnections()}.<br>
* <br> * <br>
* *
* This method automatically updates the properties of the local affected * This method automatically updates the properties of the local affected
* objects. This means that there is no need to call * objects. This means that there is no need to call
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to see the * {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} to see the
* changes consequence of the execution of this method applied in the local * changes consequence of the execution of this method applied in the local
* objects. * objects.
* *
* @param connection The Connection to remove
*
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
*/ */
@ -324,35 +337,12 @@ public class Session {
} }
/** /**
* Forces the user with Connection <code>connectionId</code> to leave the * Same as {@link io.openvidu.java.client.Session#forceDisconnect(Connection)
* session, or invalidates the {@link Token} associated with that * forceDisconnect(ConnectionOptions)} but providing the
* <code>connectionId</code> if no user has used it yet. <br> * {@link io.openvidu.java.client.Connection#getConnectionId() connectionId}
* <br> * instead of the Connection object.
* *
* In the first case you can get <code>connectionId</code> parameter from * @param connectionId The identifier of the Connection object to remove
* {@link io.openvidu.java.client.Connection#getConnectionId()
* Connection.getConnectionId()}. Connection objects can be listed with
* {@link io.openvidu.java.client.Session#getActiveConnections()
* Session.getActiveConnections()} (remember to use first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to fetch the
* current active connections from OpenVidu Server). As a result, OpenVidu
* Browser will trigger the proper events on the client-side
* (<code>streamDestroyed</code>, <code>connectionDestroyed</code>,
* <code>sessionDisconnected</code>) with reason set to
* <code>"forceDisconnectByServer"</code>. <br>
* <br>
*
* In the second case you can get <code>connectionId</code> parameter from a
* {@link Token} with {@link Token#getConnectionId()}. As a result, the token
* will be invalidated and no user will be able to connect to the session with
* it. <br>
* <br>
*
* This method automatically updates the properties of the local affected
* objects. This means that there is no need to call
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to see the
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -400,9 +390,9 @@ public class Session {
} }
/** /**
* Forces some user to unpublish a Stream. OpenVidu Browser will trigger the * Forces some Connection to unpublish a Stream. OpenVidu Browser will trigger
* proper events on the client-side (<code>streamDestroyed</code>) with reason * the proper events in the client-side (<code>streamDestroyed</code>) with
* set to <code>"forceUnpublishByServer"</code>. <br> * reason set to <code>"forceUnpublishByServer"</code>. <br>
* <br> * <br>
* *
* You can get <code>publisher</code> parameter with * You can get <code>publisher</code> parameter with
@ -415,10 +405,13 @@ public class Session {
* *
* This method automatically updates the properties of the local affected * This method automatically updates the properties of the local affected
* objects. This means that there is no need to call * objects. This means that there is no need to call
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to see the * {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} to see the
* changes consequence of the execution of this method applied in the local * changes consequence of the execution of this method applied in the local
* objects. * objects.
* *
* @param publisher The Publisher object to unpublish
*
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
*/ */
@ -427,26 +420,12 @@ public class Session {
} }
/** /**
* Forces some user to unpublish a Stream. OpenVidu Browser will trigger the * Same as {@link io.openvidu.java.client.Session#forceUnpublish(Publisher)
* proper events on the client-side (<code>streamDestroyed</code>) with reason * forceUnpublish(Publisher)} but providing the
* set to <code>"forceUnpublishByServer"</code>. <br> * {@link io.openvidu.java.client.Publisher#getStreamId() streamId} instead of
* <br> * the Publisher object.
* *
* You can get <code>streamId</code> parameter with * @param streamId The identifier of the Publisher object to remove
* {@link io.openvidu.java.client.Session#getActiveConnections()} and then for
* each Connection you can call
* {@link io.openvidu.java.client.Connection#getPublishers()}. Finally
* {@link io.openvidu.java.client.Publisher#getStreamId()}) will give you the
* <code>streamId</code>. Remember to call
* {@link io.openvidu.java.client.Session#fetch()} before to fetch the current
* actual properties of the Session from OpenVidu Server.<br>
* <br>
*
* This method automatically updates the properties of the local affected
* objects. This means that there is no need to call
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} to see the
* changes consequence of the execution of this method applied in the local
* objects.
* *
* @throws OpenViduJavaClientException * @throws OpenViduJavaClientException
* @throws OpenViduHttpException * @throws OpenViduHttpException
@ -520,7 +499,7 @@ public class Session {
StringEntity params; StringEntity params;
try { try {
params = new StringEntity(connectionOptions.toJsonObject(this.sessionId).toString()); params = new StringEntity(connectionOptions.toJson(this.sessionId).toString());
} catch (UnsupportedEncodingException e1) { } catch (UnsupportedEncodingException e1) {
throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause()); throw new OpenViduJavaClientException(e1.getMessage(), e1.getCause());
} }
@ -570,6 +549,11 @@ public class Session {
* actual value you must call first * actual value you must call first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or * {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}. * {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}.
*
* @param id The Connection to get
*
* @return The {@link io.openvidu.java.client.Connection Connection} object, or
* <code>null</code> if no Connection is found for param <code>id</code>
*/ */
public Connection getConnection(String id) { public Connection getConnection(String id) {
return this.connections.get(id); return this.connections.get(id);
@ -581,6 +565,29 @@ public class Session {
* current actual value you must call first * current actual value you must call first
* {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or * {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}. * {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}.
*
* <strong>The list of Connections will remain unchanged since the last time
* method {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} was
* called</strong>. Exceptions to this rule are:
* <ul>
* <li>Calling
* {@link io.openvidu.java.client.Session#createConnection(ConnectionOptions)
* createConnection(ConnectionOptions)} automatically adds the new Connection
* object to the local collection.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)}
* automatically updates each affected local Connection object.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)}
* automatically updates each affected local Connection object.</li>
* <li>Calling
* {@link io.openvidu.java.client.Session#updateConnection(String, ConnectionOptions)}
* automatically updates the attributes of the affected local Connection
* object.</li>
* </ul>
* <br>
* To get the list of connections with their current actual value, you must call
* first {@link io.openvidu.java.client.Session#fetch() Session.fetch()} or
* {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()}.
*/ */
public List<Connection> getConnections() { public List<Connection> getConnections() {
return this.connections.values().stream().collect(Collectors.toList()); return this.connections.values().stream().collect(Collectors.toList());
@ -596,6 +603,10 @@ public class Session {
* or {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} was * or {@link io.openvidu.java.client.OpenVidu#fetch() OpenVidu.fetch()} was
* called</strong>. Exceptions to this rule are: * called</strong>. Exceptions to this rule are:
* <ul> * <ul>
* <li>Calling
* {@link io.openvidu.java.client.Session#createConnection(ConnectionOptions)
* createConnection(ConnectionOptions)} automatically adds the new Connection
* object to the local collection.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)} * <li>Calling {@link io.openvidu.java.client.Session#forceUnpublish(String)}
* automatically updates each affected local Connection object.</li> * automatically updates each affected local Connection object.</li>
* <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)} * <li>Calling {@link io.openvidu.java.client.Session#forceDisconnect(String)}
@ -609,7 +620,7 @@ public class Session {
* To get the list of active connections with their current actual value, you * To get the list of active connections with their current actual value, you
* must call first {@link io.openvidu.java.client.Session#fetch() * must call first {@link io.openvidu.java.client.Session#fetch()
* Session.fetch()} or {@link io.openvidu.java.client.OpenVidu#fetch() * Session.fetch()} or {@link io.openvidu.java.client.OpenVidu#fetch()
* OpenVidu.fetch()}. * OpenVidu.fetch()} OpenVidu.fetch()}.
*/ */
public List<Connection> getActiveConnections() { public List<Connection> getActiveConnections() {
return this.connections.values().stream().filter(con -> "active".equals(con.getStatus())) return this.connections.values().stream().filter(con -> "active".equals(con.getStatus()))

View File

@ -1,127 +0,0 @@
package io.openvidu.java.client;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
public class Token {
private String token;
private String connectionId;
private TokenOptions tokenOptions;
protected Token(String token, String connectionId, TokenOptions tokenOptions) {
this.token = token;
this.connectionId = connectionId;
this.tokenOptions = tokenOptions;
}
protected Token(JsonObject json) {
this.token = json.get("token").getAsString();
this.connectionId = json.get("connectionId").getAsString();
OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString());
String data = json.get("data").getAsString();
Boolean record = json.get("record").getAsBoolean();
KurentoOptions kurentoOptions = null;
if (json.has("kurentoOptions")) {
JsonObject kurentoOptionsJson = json.get("kurentoOptions").getAsJsonObject();
Integer videoMaxRecvBandwidth = null;
Integer videoMinRecvBandwidth = null;
Integer videoMaxSendBandwidth = null;
Integer videoMinSendBandwidth = null;
String[] allowedFilters = null;
if (kurentoOptionsJson.has("videoMaxRecvBandwidth")) {
videoMaxRecvBandwidth = kurentoOptionsJson.get("videoMaxRecvBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMinRecvBandwidth")) {
videoMinRecvBandwidth = kurentoOptionsJson.get("videoMinRecvBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMaxSendBandwidth")) {
videoMaxSendBandwidth = kurentoOptionsJson.get("videoMaxSendBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("videoMinSendBandwidth")) {
videoMinSendBandwidth = kurentoOptionsJson.get("videoMinSendBandwidth").getAsInt();
}
if (kurentoOptionsJson.has("allowedFilters")) {
JsonArray filters = kurentoOptionsJson.get("allowedFilters").getAsJsonArray();
allowedFilters = new String[filters.size()];
for (int i = 0; i < filters.size(); i++) {
allowedFilters[i] = filters.get(i).getAsString();
}
}
kurentoOptions = new KurentoOptions(videoMaxRecvBandwidth, videoMinRecvBandwidth, videoMaxSendBandwidth,
videoMinSendBandwidth, allowedFilters);
}
this.tokenOptions = new TokenOptions(role, data, record, kurentoOptions);
}
/**
* Returns the token string value that must be sent to clients. They need to use
* it to connect to the session.
*/
public String getToken() {
return this.token;
}
/**
* Returns the connection identifier that will be associated to the user
* consuming this token. This means that the future
* {@link io.openvidu.java.client.Connection Connection} object created with
* this token will have as <code>connectionId</code> this string. In other
* words, method {@link io.openvidu.java.client.Connection#getConnectionId()
* Connection.getConnectionId()} will return this same value.
*
* With <code>connectionId</code> you can call the following methods without
* having to fetch and search for the actual
* {@link io.openvidu.java.client.Connection Connection} object:
* <ul>
* <li>Call {@link io.openvidu.java.client.Session#forceDisconnect(String)
* Session.forceDisconnect()} to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.</li>
* <li>Call
* {@link io.openvidu.java.client.Session#updateConnection(String, TokenOptions)
* Session.updateConnection()} to update the
* {@link io.openvidu.java.client.Connection Connection} options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the connection options on the fly.</li>
* </ul>
*
*/
public String getConnectionId() {
return this.connectionId;
}
/**
* Returns the role assigned to this token.
*/
public OpenViduRole getRole() {
return this.tokenOptions.getRole();
}
/**
* Returns the secure (server-side) metadata assigned to this token.
*/
public String getData() {
return this.tokenOptions.getData();
}
/**
* Whether the streams published by the participant owning this token will be
* recorded or not. This only affects <a href=
* "https://docs.openvidu.io/en/stable/advanced-features/recording#selecting-streams-to-be-recorded"
* target="_blank">INDIVIDUAL recording</a>.
*/
public Boolean record() {
return this.tokenOptions.record();
}
protected void overrideTokenOptions(TokenOptions tokenOptions) {
this.tokenOptions = tokenOptions;
}
}

View File

@ -17,12 +17,12 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
/** /**
* See {@link io.openvidu.java.client.Session#generateToken(TokenOptions)} * @deprecated Use {@link io.openvidu.java.client.ConnectionOptions
* ConnectionOptions} instead
*/ */
public class TokenOptions { public class TokenOptions {
@ -32,9 +32,8 @@ public class TokenOptions {
private KurentoOptions kurentoOptions; private KurentoOptions kurentoOptions;
/** /**
* * @deprecated Use {@link io.openvidu.java.client.ConnectionOptions.Builder
* Builder for {@link io.openvidu.java.client.TokenOptions} * ConnectionOptions.Builder} instead
*
*/ */
public static class Builder { public static class Builder {
@ -157,27 +156,7 @@ public class TokenOptions {
json.add("record", JsonNull.INSTANCE); json.add("record", JsonNull.INSTANCE);
} }
if (this.kurentoOptions != null) { if (this.kurentoOptions != null) {
JsonObject kurentoOptions = new JsonObject(); json.add("kurentoOptions", kurentoOptions.toJson());
if (this.kurentoOptions.getVideoMaxRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMaxRecvBandwidth", this.kurentoOptions.getVideoMaxRecvBandwidth());
}
if (this.kurentoOptions.getVideoMinRecvBandwidth() != null) {
kurentoOptions.addProperty("videoMinRecvBandwidth", this.kurentoOptions.getVideoMinRecvBandwidth());
}
if (this.kurentoOptions.getVideoMaxSendBandwidth() != null) {
kurentoOptions.addProperty("videoMaxSendBandwidth", this.kurentoOptions.getVideoMaxSendBandwidth());
}
if (this.kurentoOptions.getVideoMinSendBandwidth() != null) {
kurentoOptions.addProperty("videoMinSendBandwidth", this.kurentoOptions.getVideoMinSendBandwidth());
}
if (this.kurentoOptions.getAllowedFilters().length > 0) {
JsonArray allowedFilters = new JsonArray();
for (String filter : this.kurentoOptions.getAllowedFilters()) {
allowedFilters.add(filter);
}
kurentoOptions.add("allowedFilters", allowedFilters);
}
json.add("kurentoOptions", kurentoOptions);
} }
return json; return json;
} }

View File

@ -15,9 +15,9 @@
* *
*/ */
import { OpenViduRole } from './OpenViduRole';
import { Publisher } from './Publisher'; import { Publisher } from './Publisher';
import { ConnectionOptions } from './ConnectionOptions'; import { ConnectionOptions } from './ConnectionOptions';
import { OpenViduRole } from 'OpenViduRole';
/** /**
* See [[Session.connections]] * See [[Session.connections]]
@ -25,13 +25,13 @@ import { ConnectionOptions } from './ConnectionOptions';
export class Connection { export class Connection {
/** /**
* Identifier of the connection. You can call methods [[Session.forceDisconnect]] * Identifier of the Connection. You can call methods [[Session.forceDisconnect]]
* or [[Session.updateConnection]] passing this property as parameter * or [[Session.updateConnection]] passing this property as parameter
*/ */
connectionId: string; connectionId: string;
/** /**
* Returns the status of the connection. Can be: * Returns the status of the Connection. Can be:
* - `pending`: if the Connection is waiting for any user to use * - `pending`: if the Connection is waiting for any user to use
* its internal token to connect to the session, calling method * its internal token to connect to the session, calling method
* [Session.connect](https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/session.html#connect) * [Session.connect](https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/session.html#connect)
@ -43,39 +43,19 @@ export class Connection {
status: string; status: string;
/** /**
* Timestamp when this connection was created, in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC) * Timestamp when the Connection was created, in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC)
*/ */
createdAt: number; createdAt: number;
/** /**
* Timestamp when this connection was taken by a user (passing from status "pending" to "active") * Timestamp when the Connection was taken by a user (passing from status "pending" to "active")
* in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC) * in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC)
*/ */
activeAt: number; activeAt: number;
/**
* Role of the connection
*/
role: OpenViduRole;
/**
* Data associated to the connection on the server-side. This value is set with property [[TokenOptions.data]] when calling [[Session.generateToken]]
*/
serverData: string;
/**
* Whether to record the streams published by the participant owning this token or not. This only affects [INDIVIDUAL recording](/en/stable/advanced-features/recording#selecting-streams-to-be-recorded)
*/
record: boolean;
/**
* Token associated to the connection
*/
token: string;
/** /**
* <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" target="_blank" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin-right: 5px; border-radius: 3px; font-size: 13px; line-height:21px; font-family: Montserrat, sans-serif">PRO</a> * <a href="https://docs.openvidu.io/en/stable/openvidu-pro/" target="_blank" style="display: inline-block; background-color: rgb(0, 136, 170); color: white; font-weight: bold; padding: 0px 5px; margin-right: 5px; border-radius: 3px; font-size: 13px; line-height:21px; font-family: Montserrat, sans-serif">PRO</a>
* Geo location of the connection, with the following format: `"CITY, COUNTRY"` (`"unknown"` if it wasn't possible to locate it) * Geo location of the Connection, with the following format: `"CITY, COUNTRY"` (`"unknown"` if it wasn't possible to locate it)
*/ */
location: string; location: string;
@ -85,11 +65,21 @@ export class Connection {
platform: string; platform: string;
/** /**
* Data associated to the connection on the client-side. This value is set with second parameter of method * Data associated to the Connection on the client-side. This value is set with second parameter of method
* [Session.connect](/en/stable/api/openvidu-browser/classes/session.html#connect) in OpenVidu Browser * [Session.connect](/en/stable/api/openvidu-browser/classes/session.html#connect) in OpenVidu Browser
*/ */
clientData: string; clientData: string;
/**
* The [[ConnectionOptions]] assigned to the Connection
*/
connectionOptions: ConnectionOptions;
/**
* Token associated to the Connection
*/
token: string;
/** /**
* Array of Publisher objects this particular Connection is publishing to the Session (each Publisher object has one Stream, uniquely * Array of Publisher objects this particular Connection is publishing to the Session (each Publisher object has one Stream, uniquely
* identified by its `streamId`). You can call [[Session.forceUnpublish]] passing any of this values as parameter * identified by its `streamId`). You can call [[Session.forceUnpublish]] passing any of this values as parameter
@ -102,6 +92,15 @@ export class Connection {
*/ */
subscribers: string[] = []; subscribers: string[] = [];
/**
* @hidden deprecated. Inside ConnectionOptions
*/
role?: OpenViduRole;
/**
* @hidden deprecated. Inside ConnectionOptions
*/
serverData?: string;
/** /**
* @hidden * @hidden
*/ */
@ -114,15 +113,41 @@ export class Connection {
*/ */
resetWithJson(json): Connection { resetWithJson(json): Connection {
// These properties won't ever be null
this.connectionId = json.connectionId; this.connectionId = json.connectionId;
this.status = json.status; this.status = json.status;
this.createdAt = json.createdAt;
this.activeAt = json.activeAt;
this.location = json.location;
this.platform = json.platform;
this.clientData = json.clientData;
this.token = json.token; this.token = json.token;
if (this.connectionOptions != null) {
this.connectionOptions.type = json.type;
this.connectionOptions.data = json.data;
this.connectionOptions.record = json.record;
this.connectionOptions.role = json.role;
this.connectionOptions.kurentoOptions = json.kurentoOptions;
this.connectionOptions.rtspUri = json.rtspUri;
this.connectionOptions.adaptativeBitrate = json.adaptativeBitrate;
this.connectionOptions.onlyPlayWithSubscribers = json.onlyPlayWithSubscribers;
this.connectionOptions.networkCache = json.networkCache;
} else {
this.connectionOptions = {
type: json.type,
data: json.data,
record: json.record,
role: json.role,
kurentoOptions: json.kurentoOptions,
rtspUri: json.rtspUri,
adaptativeBitrate: json.adaptativeBitrate,
onlyPlayWithSubscribers: json.onlyPlayWithSubscribers,
networkCache: json.networkCache
}
}
this.role = json.role; this.role = json.role;
this.serverData = json.serverData; this.serverData = json.data;
this.record = json.record;
// These properties may be null // publishers may be null
if (json.publishers != null) { if (json.publishers != null) {
// 1. Array to store fetched Publishers and later remove closed ones // 1. Array to store fetched Publishers and later remove closed ones
@ -151,6 +176,7 @@ export class Connection {
} }
// subscribers may be null
if (json.subscribers != null) { if (json.subscribers != null) {
// 1. Array to store fetched Subscribers and later remove closed ones // 1. Array to store fetched Subscribers and later remove closed ones
@ -171,12 +197,6 @@ export class Connection {
} }
} }
this.createdAt = json.createdAt;
this.activeAt = json.activeAt;
this.location = json.location;
this.platform = json.platform;
this.clientData = json.clientData;
return this; return this;
} }
@ -189,9 +209,15 @@ export class Connection {
this.status === other.status && this.status === other.status &&
this.createdAt === other.createdAt && this.createdAt === other.createdAt &&
this.activeAt === other.activeAt && this.activeAt === other.activeAt &&
this.role === other.role && this.connectionOptions.type === other.connectionOptions.type &&
this.serverData === other.serverData && this.connectionOptions.data === other.connectionOptions.data &&
this.record === other.record && this.connectionOptions.record === other.connectionOptions.record &&
this.connectionOptions.role === other.connectionOptions.role &&
this.connectionOptions.kurentoOptions === other.connectionOptions.kurentoOptions &&
this.connectionOptions.rtspUri === other.connectionOptions.rtspUri &&
this.connectionOptions.adaptativeBitrate === other.connectionOptions.adaptativeBitrate &&
this.connectionOptions.onlyPlayWithSubscribers === other.connectionOptions.onlyPlayWithSubscribers &&
this.connectionOptions.networkCache === other.connectionOptions.networkCache &&
this.token === other.token && this.token === other.token &&
this.location === other.location && this.location === other.location &&
this.platform === other.platform && this.platform === other.platform &&
@ -218,12 +244,13 @@ export class Connection {
/** /**
* @hidden * @hidden
*/ */
overrideConnectionOptions(connectionOptions: ConnectionOptions): void { overrideConnectionOptions(newConnectionOptions: ConnectionOptions): void {
if (connectionOptions.role != null) { // For now only properties record and role
this.role = connectionOptions.role; if (newConnectionOptions.record != null) {
this.connectionOptions.record = newConnectionOptions.record;
} }
if (connectionOptions.record != null) { if (newConnectionOptions.role != null) {
this.record = connectionOptions.record this.connectionOptions.role = newConnectionOptions.role;
} }
} }

View File

@ -15,16 +15,20 @@
* *
*/ */
import { ConnectionType } from 'ConnectionType';
import { OpenViduRole } from './OpenViduRole'; import { OpenViduRole } from './OpenViduRole';
export interface ConnectionOptions { export interface ConnectionOptions {
/** /**
* The role assigned to this Connection * Type of Connection. The [[ConnectionType]] dictates what properties will have effect:
* *
* @default PUBLISHER * - **[[ConnectionType.WEBRTC]]**: [[data]], [[record]], [[role]], [[kurentoOptions]]
* - **[[ConnectionType.IPCAM]]**: [[data]], [[record]], [[rtspUri]], [[adaptativeBitrate]], [[onlyPlayWithSubscribers]], [[networkCache]]
*
* @default WEBRTC
*/ */
role?: OpenViduRole; type?: ConnectionType;
/** /**
* Secure (server-side) data associated to this Connection. Every client will receive this data in property `Connection.data`. Object `Connection` can be retrieved by subscribing to event `connectionCreated` of Session object. * Secure (server-side) data associated to this Connection. Every client will receive this data in property `Connection.data`. Object `Connection` can be retrieved by subscribing to event `connectionCreated` of Session object.
@ -41,6 +45,15 @@ export interface ConnectionOptions {
*/ */
record?: boolean; record?: boolean;
/**
* The role assigned to this Connection
*
* **Only for [[ConnectionType.WEBRTC]]**
*
* @default PUBLISHER
*/
role?: OpenViduRole;
/** /**
* **WARNING**: experimental option. This interface may change in the near future * **WARNING**: experimental option. This interface may change in the near future
* *
@ -61,6 +74,8 @@ export interface ConnectionOptions {
* the global configuration set in [OpenVidu Server configuration](/en/stable/reference-docs/openvidu-config/) * the global configuration set in [OpenVidu Server configuration](/en/stable/reference-docs/openvidu-config/)
* (parameter `OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH`) for every outgoing stream of the Connection. * (parameter `OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH`) for every outgoing stream of the Connection.
* - `allowedFilters`: names of the filters the Connection will be able to apply. See [Voice and video filters](/en/stable/advanced-features/filters/) * - `allowedFilters`: names of the filters the Connection will be able to apply. See [Voice and video filters](/en/stable/advanced-features/filters/)
*
* **Only for [[ConnectionType.WEBRTC]]**
*/ */
kurentoOptions?: { kurentoOptions?: {
videoMaxRecvBandwidth?: number, videoMaxRecvBandwidth?: number,
@ -69,4 +84,45 @@ export interface ConnectionOptions {
videoMinSendBandwidth?: number, videoMinSendBandwidth?: number,
allowedFilters?: string[] allowedFilters?: string[]
}; };
/**
* RTSP URI of an IP camera. For example: `rtsp://your.camera.ip:7777/path`
*
* **Only for [[ConnectionType.IPCAM]]**
*/
rtspUri?: string;
/**
* Whether to use adaptative bitrate (and therefore adaptative quality) or not. For local network connections
* that do not require media transcoding this can be disabled to save CPU power. If you are not sure if transcoding
* might be necessary, setting this property to false **may result in media connections not being established**.
*
* **Only for [[ConnectionType.IPCAM]]**
*
* @default true
*/
adaptativeBitrate?: boolean;
/**
* Whether to enable the IP camera stream only when some user is subscribed to it, or not. This allows you to reduce
* power consumption and network bandwidth in your server while nobody is asking to receive the camera's video.
* On the counterpart, first user subscribing to the IP camera stream will take a little longer to receive its video.
*
* **Only for [[ConnectionType.IPCAM]]**
*
* @default true
*/
onlyPlayWithSubscribers?: boolean;
/**
* Size of the buffer of the endpoint receiving the IP camera's stream, in milliseconds. The smaller it is, the less
* delay the signal will have, but more problematic will be in unstable networks. Use short buffers only if there is
* a quality connection between the IP camera and OpenVidu Server.
*
* **Only for [[ConnectionType.IPCAM]]**
*
* @default 2000
*/
networkCache?: number;
} }

View File

@ -0,0 +1,34 @@
/*
* (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.
*
*/
/**
* See [[Session.createConnection]]
*/
export enum ConnectionType {
/**
* WebRTC connection. This is the normal type of Connection for a regular user
* connecting to a session from an application.
*/
WEBRTC = 'WEBRTC',
/**
* IP camera connection. This is the type of Connection used by IP cameras to
* connect to a session.
*/
IPCAM = 'IPCAM'
}

View File

@ -76,6 +76,7 @@ export class OpenVidu {
* Array of active sessions. **This value will remain unchanged since the last time method [[OpenVidu.fetch]] * Array of active sessions. **This value will remain unchanged since the last time method [[OpenVidu.fetch]]
* was called**. Exceptions to this rule are: * was called**. Exceptions to this rule are:
* *
* - Calling [[OpenVidu.createSession]] automatically adds the new Session object to the local collection.
* - Calling [[Session.fetch]] updates that specific Session status * - Calling [[Session.fetch]] updates that specific Session status
* - Calling [[Session.close]] automatically removes the Session from the list of active Sessions * - Calling [[Session.close]] automatically removes the Session from the list of active Sessions
* - Calling [[Session.forceDisconnect]] automatically updates the inner affected connections for that specific Session * - Calling [[Session.forceDisconnect]] automatically updates the inner affected connections for that specific Session

View File

@ -25,10 +25,8 @@ import { Recording } from './Recording';
import { RecordingLayout } from './RecordingLayout'; import { RecordingLayout } from './RecordingLayout';
import { RecordingMode } from './RecordingMode'; import { RecordingMode } from './RecordingMode';
import { SessionProperties } from './SessionProperties'; import { SessionProperties } from './SessionProperties';
import { Token } from './Token';
import { TokenOptions } from './TokenOptions'; import { TokenOptions } from './TokenOptions';
export class Session { export class Session {
/** /**
@ -51,6 +49,7 @@ export class Session {
* **will remain unchanged since the last time method [[Session.fetch]] or [[OpenVidu.fetch]] was called**. * **will remain unchanged since the last time method [[Session.fetch]] or [[OpenVidu.fetch]] was called**.
* Exceptions to this rule are: * Exceptions to this rule are:
* *
* - Calling [[Session.createConnection]] automatically adds the new Connection object to the local collection.
* - Calling [[Session.forceUnpublish]] automatically updates each affected local Connection object. * - Calling [[Session.forceUnpublish]] automatically updates each affected local Connection object.
* - Calling [[Session.forceDisconnect]] automatically updates each affected local Connection object. * - Calling [[Session.forceDisconnect]] automatically updates each affected local Connection object.
* - Calling [[Session.updateConnection]] automatically updates the attributes of the affected local Connection object. * - Calling [[Session.updateConnection]] automatically updates the attributes of the affected local Connection object.
@ -105,37 +104,12 @@ export class Session {
} }
/** /**
* @deprecated Use [[Session.createToken]] instead to get a [[Token]] object. * @deprecated Use [[Session.createConnection]] instead to get a [[Connection]] object.
* *
* @returns A Promise that is resolved to the generated _token_ string if success and rejected with an Error object if not * @returns A Promise that is resolved to the generated _token_ string if success and rejected with an Error object if not
*/ */
public generateToken(tokenOptions?: TokenOptions): Promise<string> { public generateToken(tokenOptions?: TokenOptions): Promise<string> {
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
this.createToken(tokenOptions).then(token => resolve(token.token)).catch(error => reject(error));
});
}
/**
* Gets a new token object associated to Session object configured with
* `tokenOptions`. The token string value to send to the client side
* is available at [[Token.token]] property.
*
* Property [[Token.connectionId]] provides the connection identifier that will be given
* to the user consuming the token. With `connectionId` you can call
* the following methods without having to fetch and search for the actual
* [[Connection]] object:
*
* - Call [[Session.forceDisconnect]] to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.
* - Call [[Session.updateConnection]] to update the [[Connection]] options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the user connection options on the fly.
*
* @returns A Promise that is resolved to the generated [[Token]] object if success and rejected with an Error object if not
*/
public createToken(tokenOptions?: TokenOptions): Promise<Token> {
return new Promise<Token>((resolve, reject) => {
const data = JSON.stringify({ const data = JSON.stringify({
session: this.sessionId, session: this.sessionId,
role: (!!tokenOptions && !!tokenOptions.role) ? tokenOptions.role : null, role: (!!tokenOptions && !!tokenOptions.role) ? tokenOptions.role : null,
@ -156,7 +130,51 @@ export class Session {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
// SUCCESS response from openvidu-server. Resolve token // SUCCESS response from openvidu-server. Resolve token
resolve(new Token(res.data)); resolve(res.data.token);
} else {
// ERROR response from openvidu-server. Resolve HTTP status
reject(new Error(res.status.toString()));
}
}).catch(error => {
this.handleError(error, reject);
});
});
}
/**
* Creates a new Connection object associated to Session object and configured with
* `connectionOptions`. Each user connecting to the Session requires a Connection.
* The token string value to send to the client side is available at [[Connection.token]].
*
* @returns A Promise that is resolved to the generated [[Connection]] object if success and rejected with an Error object if not
*/
public createConnection(connectionOptions?: ConnectionOptions): Promise<Connection> {
return new Promise<Connection>((resolve, reject) => {
const data = JSON.stringify({
role: (!!connectionOptions && !!connectionOptions.role) ? connectionOptions.role : null,
data: (!!connectionOptions && !!connectionOptions.data) ? connectionOptions.data : null,
record: !!connectionOptions ? connectionOptions.record : null,
kurentoOptions: (!!connectionOptions && !!connectionOptions.kurentoOptions) ? connectionOptions.kurentoOptions : null
});
axios.post(
this.ov.host + OpenVidu.API_SESSIONS + '/' + this.sessionId + '/connection',
data,
{
headers: {
'Authorization': this.ov.basicAuth,
'Content-Type': 'application/json'
}
}
)
.then(res => {
if (res.status === 200) {
// SUCCESS response from openvidu-server. Store and resolve Connection
const connection = new Connection(res.data);
this.connections.push(connection);
if (connection.status === 'active') {
this.activeConnections.push(connection);
}
resolve(new Connection(res.data));
} else { } else {
// ERROR response from openvidu-server. Resolve HTTP status // ERROR response from openvidu-server. Resolve HTTP status
reject(new Error(res.status.toString())); reject(new Error(res.status.toString()));
@ -240,12 +258,18 @@ export class Session {
} }
/** /**
* Removes a Connection from the Session. * Removes the Connection from the Session. This can translate into a forced eviction of a user from the Session if the
* Connection had status `active` or into a token invalidation if no user had taken the Connection yet (status `pending`).
*
* In the first case, OpenVidu Browser will trigger the proper events in the client-side (`streamDestroyed`, `connectionDestroyed`,
* `sessionDisconnected`) with reason set to `"forceDisconnectByServer"`.
*
* In the second case, the token of the Connection will be invalidated and no user will be able to connect to the session with it.
* *
* This method automatically updates the properties of the local affected objects. This means that there is no need to call * This method automatically updates the properties of the local affected objects. This means that there is no need to call
* [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects. * [[Session.fetch]] or [[OpenVidu.fetch]]] to see the changes consequence of the execution of this method applied in the local objects.
* *
* @param connection The Connection object to disconnect from the session, or its `connectionId` property * @param connection The Connection object to remove from the session, or its `connectionId` property
* *
* @returns A Promise that is resolved if the Connection was successfully removed from the Session and rejected with an Error object if not * @returns A Promise that is resolved if the Connection was successfully removed from the Session and rejected with an Error object if not
*/ */
@ -308,7 +332,7 @@ export class Session {
} }
/** /**
* Forces some user to unpublish a Stream (identified by its `streamId` or the corresponding [[Publisher]] object owning it). * Forces some Connection to unpublish a Stream (identified by its `streamId` or the corresponding [[Publisher]] object owning it).
* OpenVidu Browser will trigger the proper events on the client-side (`streamDestroyed`) with reason set to `"forceUnpublishByServer"`. * OpenVidu Browser will trigger the proper events on the client-side (`streamDestroyed`) with reason set to `"forceUnpublishByServer"`.
* *
* You can get `publisher` parameter from [[Connection.publishers]] array ([[Publisher.streamId]] for getting each `streamId` property). * You can get `publisher` parameter from [[Connection.publishers]] array ([[Publisher.streamId]] for getting each `streamId` property).
@ -317,6 +341,8 @@ export class Session {
* This method automatically updates the properties of the local affected objects. This means that there is no need to call * This method automatically updates the properties of the local affected objects. This means that there is no need to call
* [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects. * [[Session.fetch]] or [[OpenVidu.fetch]] to see the changes consequence of the execution of this method applied in the local objects.
* *
* @param publisher The Publisher object to unpublish, or its `streamId` property
*
* @returns A Promise that is resolved if the stream was successfully unpublished and rejected with an Error object if not * @returns A Promise that is resolved if the stream was successfully unpublished and rejected with an Error object if not
*/ */
public forceUnpublish(publisher: string | Publisher): Promise<any> { public forceUnpublish(publisher: string | Publisher): Promise<any> {

View File

@ -1,81 +0,0 @@
/*
* (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.
*
*/
import { TokenOptions } from './TokenOptions';
export class Token {
/**
* The token string value that must be sent to clients. They need to use it to connect to the session.
*/
token: string;
/**
* The connection identifier that will be associated to the user
* consuming this token. This means that the future [[Connection]] object created with
* this token will have as [[Connection.connectionId]] this same value.
*
* With `connectionId` you can call the following methods without
* having to fetch and search for the actual [[Connection]] object:
*
* - Call [[Session.forceDisconnect]] to invalidate the token if no client has used it
* yet or force the connected client to leave the session if it has.
* - Call [[Session.updateConnection]] to update the [[Connection]] options. And this is
* valid for unused tokens, but also for already used tokens, so you can
* dynamically change the connection options on the fly.
*/
connectionId: string;
/**
* The [[TokenOptions]] assigned to this token.
*/
tokenOptions: TokenOptions;
/**
* @hidden
*/
constructor(json) {
this.token = json.token;
this.connectionId = json.connectionId;
let possibleKurentoOptions;
if (!!json.kurentoOptions) {
possibleKurentoOptions = {};
if (json.kurentoOptions.videoMaxRecvBandwidth != null) {
possibleKurentoOptions['videoMaxRecvBandwidth'] = json.kurentoOptions.videoMaxRecvBandwidth;
}
if (json.kurentoOptions.videoMinRecvBandwidth != null) {
possibleKurentoOptions['videoMinRecvBandwidth'] = json.kurentoOptions.videoMinRecvBandwidth;
}
if (json.kurentoOptions.videoMaxSendBandwidth != null) {
possibleKurentoOptions['videoMaxSendBandwidth'] = json.kurentoOptions.videoMaxSendBandwidth;
}
if (json.kurentoOptions.videoMinSendBandwidth != null) {
possibleKurentoOptions['videoMinSendBandwidth'] = json.kurentoOptions.videoMinSendBandwidth;
}
if (json.kurentoOptions.allowedFilters != null) {
possibleKurentoOptions['allowedFilters'] = json.kurentoOptions.allowedFilters;
}
}
this.tokenOptions = {
role: json.role,
data: json.data,
record: json.record,
kurentoOptions: possibleKurentoOptions
};
}
}

View File

@ -18,7 +18,7 @@
import { OpenViduRole } from './OpenViduRole'; import { OpenViduRole } from './OpenViduRole';
/** /**
* See [[Session.generateToken]] * @deprecated Use [[ConnectionOptions]] instead
*/ */
export interface TokenOptions { export interface TokenOptions {

View File

@ -4,7 +4,7 @@ export * from './Session';
export * from './SessionProperties'; export * from './SessionProperties';
export * from './TokenOptions'; export * from './TokenOptions';
export * from './ConnectionOptions'; export * from './ConnectionOptions';
export * from './Token'; export * from './ConnectionType';
export * from './MediaMode'; export * from './MediaMode';
export * from './RecordingLayout'; export * from './RecordingLayout';
export * from './RecordingMode'; export * from './RecordingMode';

View File

@ -22,7 +22,6 @@ import java.util.concurrent.locks.ReentrantLock;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.openvidu.java.client.ConnectionType;
import io.openvidu.server.kurento.endpoint.EndpointType; import io.openvidu.server.kurento.endpoint.EndpointType;
import io.openvidu.server.utils.GeoLocation; import io.openvidu.server.utils.GeoLocation;
@ -44,7 +43,6 @@ public class Participant {
active active
} }
protected ConnectionType type; // WEBRTC, IPCAM
protected String finalUserId; // ID to match this connection with a final user (HttpSession id) protected String finalUserId; // ID to match this connection with a final user (HttpSession id)
protected String participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id) protected String participantPrivatetId; // ID to identify the user on server (org.kurento.jsonrpc.Session.id)
protected String participantPublicId; // ID to identify the user on clients protected String participantPublicId; // ID to identify the user on clients
@ -52,7 +50,6 @@ public class Participant {
protected ParticipantStatus status; // Status of the connection protected ParticipantStatus status; // Status of the connection
protected Long activeAt; // Timestamp when this connection entered status "active" protected Long activeAt; // Timestamp when this connection entered status "active"
protected String clientMetadata = ""; // Metadata provided on client side protected String clientMetadata = ""; // Metadata provided on client side
protected String serverMetadata = ""; // Metadata provided on server side
protected Token token; // Token associated to this participant protected Token token; // Token associated to this participant
protected GeoLocation location; // Location of the participant protected GeoLocation location; // Location of the participant
protected String platform; // Platform used by the participant to connect to the session protected String platform; // Platform used by the participant to connect to the session
@ -78,10 +75,9 @@ public class Participant {
*/ */
public Lock singleRecordingLock = new ReentrantLock(); public Lock singleRecordingLock = new ReentrantLock();
public Participant(ConnectionType type, String finalUserId, String participantPrivatetId, public Participant(String finalUserId, String participantPrivatetId, String participantPublicId, String sessionId,
String participantPublicId, String sessionId, Token token, String clientMetadata, GeoLocation location, Token token, String clientMetadata, GeoLocation location, String platform, EndpointType endpointType,
String platform, EndpointType endpointType, Long activeAt) { Long activeAt) {
this.type = type;
this.finalUserId = finalUserId; this.finalUserId = finalUserId;
this.participantPrivatetId = participantPrivatetId; this.participantPrivatetId = participantPrivatetId;
this.participantPublicId = participantPublicId; this.participantPublicId = participantPublicId;
@ -96,18 +92,11 @@ public class Participant {
if (clientMetadata != null) { if (clientMetadata != null) {
this.clientMetadata = clientMetadata; this.clientMetadata = clientMetadata;
} }
if (!token.getServerMetadata().isEmpty()) {
this.serverMetadata = token.getServerMetadata();
}
this.location = location; this.location = location;
this.platform = platform; this.platform = platform;
this.endpointType = endpointType; this.endpointType = endpointType;
} }
public ConnectionType getType() {
return type;
}
public String getFinalUserId() { public String getFinalUserId() {
return finalUserId; return finalUserId;
} }
@ -145,11 +134,7 @@ public class Participant {
} }
public String getServerMetadata() { public String getServerMetadata() {
return serverMetadata; return this.token.getServerMetadata();
}
public void setServerMetadata(String serverMetadata) {
this.serverMetadata = serverMetadata;
} }
public Token getToken() { public Token getToken() {
@ -234,16 +219,16 @@ public class Participant {
public String getFullMetadata() { public String getFullMetadata() {
String fullMetadata; String fullMetadata;
if ((!this.clientMetadata.isEmpty()) && (!this.serverMetadata.isEmpty())) { if ((!this.clientMetadata.isEmpty()) && (!this.token.getServerMetadata().isEmpty())) {
fullMetadata = this.clientMetadata + METADATA_SEPARATOR + this.serverMetadata; fullMetadata = this.clientMetadata + METADATA_SEPARATOR + this.token.getServerMetadata();
} else { } else {
fullMetadata = this.clientMetadata + this.serverMetadata; fullMetadata = this.clientMetadata + this.token.getServerMetadata();
} }
return fullMetadata; return fullMetadata;
} }
public void deleteIpcamProperties() { public void deleteIpcamProperties() {
this.clientMetadata = ""; this.clientMetadata = null;
this.token.setToken(null); this.token.setToken(null);
} }
@ -305,9 +290,9 @@ public class Participant {
public JsonObject toJson() { public JsonObject toJson() {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
// COMMON
json.addProperty("id", this.participantPublicId); json.addProperty("id", this.participantPublicId);
json.addProperty("object", "connection"); json.addProperty("object", "connection");
json.addProperty("type", this.type.name());
json.addProperty("status", this.status.name()); json.addProperty("status", this.status.name());
json.addProperty("connectionId", this.participantPublicId); // TODO: deprecated. Better use only "id" json.addProperty("connectionId", this.participantPublicId); // TODO: deprecated. Better use only "id"
json.addProperty("sessionId", this.sessionId); json.addProperty("sessionId", this.sessionId);
@ -317,10 +302,14 @@ public class Participant {
json.addProperty("platform", this.platform); json.addProperty("platform", this.platform);
if (this.token.getToken() != null) { if (this.token.getToken() != null) {
json.addProperty("token", this.token.getToken()); json.addProperty("token", this.token.getToken());
} else {
json.add("token", null);
} }
json.addProperty("role", this.token.getRole().name()); // Add all ConnectionOptions
json.addProperty("serverData", this.serverMetadata); JsonObject connectionOptionsJson = this.token.getConnectionOptionsWithFinalJsonFormat();
json.addProperty("record", this.token.record()); connectionOptionsJson.entrySet().forEach(entry -> {
json.add(entry.getKey(), entry.getValue());
});
json.addProperty("clientData", this.clientMetadata); json.addProperty("clientData", this.clientMetadata);
return json; return json;
} }

View File

@ -45,14 +45,15 @@ import com.google.gson.JsonSyntaxException;
import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.OpenViduException.Code;
import io.openvidu.client.internal.ProtocolElements; import io.openvidu.client.internal.ProtocolElements;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.ConnectionType; import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.OpenViduRole;
import io.openvidu.java.client.Recording; import io.openvidu.java.client.Recording;
import io.openvidu.java.client.SessionProperties; import io.openvidu.java.client.SessionProperties;
import io.openvidu.server.cdr.CDREventRecording; import io.openvidu.server.cdr.CDREventRecording;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.coturn.CoturnCredentialsService; import io.openvidu.server.coturn.CoturnCredentialsService;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
import io.openvidu.server.kurento.endpoint.EndpointType; import io.openvidu.server.kurento.endpoint.EndpointType;
import io.openvidu.server.recording.service.RecordingManager; import io.openvidu.server.recording.service.RecordingManager;
import io.openvidu.server.utils.FormatChecker; import io.openvidu.server.utils.FormatChecker;
@ -160,8 +161,8 @@ public abstract class SessionManager {
public abstract void removeFilterEventListener(Session session, Participant subscriber, String streamId, public abstract void removeFilterEventListener(Session session, Participant subscriber, String streamId,
String eventType); String eventType);
public abstract Participant publishIpcam(Session session, MediaOptions mediaOptions, String serverMetadata) public abstract Participant publishIpcam(Session session, MediaOptions mediaOptions,
throws Exception; ConnectionOptions connectionOptions) throws Exception;
public abstract void reconnectStream(Participant participant, String streamId, String sdpOffer, public abstract void reconnectStream(Participant participant, String streamId, String sdpOffer,
Integer transactionId); Integer transactionId);
@ -301,22 +302,22 @@ public abstract class SessionManager {
} }
public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record, public Token newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
KurentoTokenOptions kurentoTokenOptions) throws Exception { KurentoOptions kurentoOptions) throws Exception {
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) { if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
log.error("Data invalid format"); log.error("Data invalid format");
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format"); throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
} }
Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), role, serverMetadata, record, Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), serverMetadata,
kurentoTokenOptions); record, role, kurentoOptions);
session.storeToken(tokenObj); session.storeToken(tokenObj);
session.showTokens("Token created"); session.showTokens("Token created");
return tokenObj; return tokenObj;
} }
public Token newTokenForInsecureUser(Session session, String token, String serverMetadata) throws Exception { public Token newTokenForInsecureUser(Session session, String token, ConnectionOptions connectionOptions)
Token tokenObj = new Token(token, session.getSessionId(), OpenViduRole.PUBLISHER, throws Exception {
serverMetadata != null ? serverMetadata : "", true, Token tokenObj = new Token(token, session.getSessionId(), connectionOptions,
this.openviduConfig.isTurnadminAvailable() ? this.coturnCredentialsService.createUser() : null, null); this.openviduConfig.isTurnadminAvailable() ? this.coturnCredentialsService.createUser() : null);
session.storeToken(tokenObj); session.storeToken(tokenObj);
session.showTokens("Token created for insecure user"); session.showTokens("Token created for insecure user");
return tokenObj; return tokenObj;
@ -364,9 +365,8 @@ public abstract class SessionManager {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(ConnectionType.WEBRTC, finalUserId, participantPrivatetId, Participant p = new Participant(finalUserId, participantPrivatetId, token.getConnectionId(), sessionId,
token.getConnectionId(), sessionId, token, clientMetadata, location, platform, token, clientMetadata, location, platform, EndpointType.WEBRTC_ENDPOINT, null);
EndpointType.WEBRTC_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId).put(p.getParticipantPublicId(), p); this.sessionidParticipantpublicidParticipant.get(sessionId).put(p.getParticipantPublicId(), p);
@ -386,9 +386,8 @@ public abstract class SessionManager {
public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token, public Participant newRecorderParticipant(String sessionId, String participantPrivatetId, Token token,
String clientMetadata) { String clientMetadata) {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(ConnectionType.WEBRTC, null, participantPrivatetId, Participant p = new Participant(null, participantPrivatetId, ProtocolElements.RECORDER_PARTICIPANT_PUBLICID,
ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, sessionId, token, clientMetadata, null, null, sessionId, token, clientMetadata, null, null, EndpointType.WEBRTC_ENDPOINT, null);
EndpointType.WEBRTC_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId) this.sessionidParticipantpublicidParticipant.get(sessionId)
.put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p); .put(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID, p);
return p; return p;
@ -400,8 +399,8 @@ public abstract class SessionManager {
public Participant newIpcamParticipant(String sessionId, String ipcamId, Token token, GeoLocation location, public Participant newIpcamParticipant(String sessionId, String ipcamId, Token token, GeoLocation location,
String platform) { String platform) {
if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) { if (this.sessionidParticipantpublicidParticipant.get(sessionId) != null) {
Participant p = new Participant(ConnectionType.IPCAM, ipcamId, ipcamId, ipcamId, sessionId, token, null, Participant p = new Participant(ipcamId, ipcamId, ipcamId, sessionId, token, null, location, platform,
location, platform, EndpointType.PLAYER_ENDPOINT, null); EndpointType.PLAYER_ENDPOINT, null);
this.sessionidParticipantpublicidParticipant.get(sessionId).put(ipcamId, p); this.sessionidParticipantpublicidParticipant.get(sessionId).put(ipcamId, p);
return p; return p;
} else { } else {

View File

@ -21,95 +21,113 @@ import org.apache.commons.lang3.RandomStringUtils;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.ConnectionType; import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.OpenViduRole;
import io.openvidu.server.core.Participant.ParticipantStatus; import io.openvidu.server.core.Participant.ParticipantStatus;
import io.openvidu.server.coturn.TurnCredentials; import io.openvidu.server.coturn.TurnCredentials;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
public class Token { public class Token {
private String token; private String token;
private String sessionId; private String sessionId;
private Long createdAt; private Long createdAt;
private OpenViduRole role; private ConnectionOptions connectionOptions;
private String serverMetadata = "";
private boolean record;
private TurnCredentials turnCredentials; private TurnCredentials turnCredentials;
private KurentoTokenOptions kurentoTokenOptions;
private final String connectionId = IdentifierPrefixes.PARTICIPANT_PUBLIC_ID private final String connectionId = IdentifierPrefixes.PARTICIPANT_PUBLIC_ID
+ RandomStringUtils.randomAlphabetic(1).toUpperCase() + RandomStringUtils.randomAlphanumeric(9); + RandomStringUtils.randomAlphabetic(1).toUpperCase() + RandomStringUtils.randomAlphanumeric(9);
public Token(String token, String sessionId, OpenViduRole role, String serverMetadata, boolean record, public Token(String token, String sessionId, ConnectionOptions connectionOptions, TurnCredentials turnCredentials) {
TurnCredentials turnCredentials, KurentoTokenOptions kurentoTokenOptions) {
this.token = token; this.token = token;
this.sessionId = sessionId; this.sessionId = sessionId;
this.createdAt = System.currentTimeMillis(); this.createdAt = System.currentTimeMillis();
this.role = role; this.connectionOptions = connectionOptions;
this.serverMetadata = serverMetadata;
this.record = record;
this.turnCredentials = turnCredentials; this.turnCredentials = turnCredentials;
this.kurentoTokenOptions = kurentoTokenOptions; }
public ConnectionType getType() {
return this.connectionOptions.getType();
} }
public String getToken() { public String getToken() {
return token; return token;
} }
public void setToken(String token) { public void setToken(String newToken) {
this.token = token; this.token = newToken;
} }
public Long getCreatedAt() { public Long getCreatedAt() {
return this.createdAt; return this.createdAt;
} }
public OpenViduRole getRole() {
return role;
}
public String getServerMetadata() { public String getServerMetadata() {
return serverMetadata; return this.connectionOptions.getData();
} }
public boolean record() { public boolean record() {
return record; return this.connectionOptions.record();
}
public void setRecord(boolean newRecord) {
this.updateConnectionOptions(connectionOptions.getType(), connectionOptions.getData(), newRecord,
connectionOptions.getRole(), connectionOptions.getKurentoOptions(), connectionOptions.getRtspUri(),
connectionOptions.adaptativeBitrate(), connectionOptions.onlyPlayWithSubscribers(),
connectionOptions.getNetworkCache());
}
public OpenViduRole getRole() {
return this.connectionOptions.getRole();
}
public void setRole(OpenViduRole newRole) {
this.updateConnectionOptions(connectionOptions.getType(), connectionOptions.getData(),
connectionOptions.record(), newRole, connectionOptions.getKurentoOptions(),
connectionOptions.getRtspUri(), connectionOptions.adaptativeBitrate(),
connectionOptions.onlyPlayWithSubscribers(), connectionOptions.getNetworkCache());
}
public KurentoOptions getKurentoOptions() {
return this.connectionOptions.getKurentoOptions();
}
public String getRtspUri() {
return this.connectionOptions.getRtspUri();
}
public Boolean adaptativeBitrate() {
return this.connectionOptions.adaptativeBitrate();
}
public Boolean onlyPlayWithSubscribers() {
return this.connectionOptions.onlyPlayWithSubscribers();
}
public Integer getNetworkCache() {
return this.connectionOptions.getNetworkCache();
} }
public TurnCredentials getTurnCredentials() { public TurnCredentials getTurnCredentials() {
return turnCredentials; return turnCredentials;
} }
public KurentoTokenOptions getKurentoTokenOptions() {
return kurentoTokenOptions;
}
public String getConnectionId() { public String getConnectionId() {
return connectionId; return connectionId;
} }
public void setRole(OpenViduRole role) {
this.role = role;
}
public void setRecord(boolean record) {
this.record = record;
}
public JsonObject toJson() { public JsonObject toJson() {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("id", this.getToken()); json.addProperty("id", this.getToken());
json.addProperty("object", "token");
json.addProperty("token", this.getToken()); json.addProperty("token", this.getToken());
json.addProperty("createdAt", this.getCreatedAt());
json.addProperty("connectionId", this.getConnectionId()); json.addProperty("connectionId", this.getConnectionId());
json.addProperty("createdAt", this.createdAt);
json.addProperty("session", this.sessionId); json.addProperty("session", this.sessionId);
json.addProperty("role", this.getRole().toString());
json.addProperty("data", this.getServerMetadata()); json.addProperty("data", this.getServerMetadata());
json.addProperty("record", this.record()); json.addProperty("role", this.getRole().toString());
if (this.getKurentoTokenOptions() != null) { if (this.getKurentoOptions() != null) {
json.add("kurentoOptions", this.getKurentoTokenOptions().toJson()); json.add("kurentoOptions", this.getKurentoOptions().toJson());
} }
return json; return json;
} }
@ -118,28 +136,73 @@ public class Token {
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("id", this.getConnectionId()); json.addProperty("id", this.getConnectionId());
json.addProperty("object", "connection"); json.addProperty("object", "connection");
json.addProperty("type", ConnectionType.WEBRTC.name());
json.addProperty("status", ParticipantStatus.pending.name()); json.addProperty("status", ParticipantStatus.pending.name());
json.addProperty("connectionId", this.getConnectionId()); // DEPRECATED: better use id json.addProperty("connectionId", this.getConnectionId()); // DEPRECATED: better use id
json.addProperty("sessionId", this.sessionId); json.addProperty("sessionId", this.sessionId);
json.addProperty("createdAt", this.createdAt); json.addProperty("createdAt", this.createdAt);
// Add all ConnectionOptions
JsonObject connectionOptionsJson = this.getConnectionOptionsWithFinalJsonFormat();
connectionOptionsJson.entrySet().forEach(entry -> {
json.add(entry.getKey(), entry.getValue());
});
json.addProperty("token", this.getToken());
json.add("activeAt", null); json.add("activeAt", null);
json.add("location", null); json.add("location", null);
json.add("platform", null); json.add("platform", null);
json.addProperty("token", this.getToken());
json.addProperty("role", this.getRole().toString());
json.addProperty("serverData", this.getServerMetadata());
json.addProperty("record", this.record());
json.add("clientData", null); json.add("clientData", null);
json.add("publishers", null); json.add("publishers", null);
json.add("subscribers", null); json.add("subscribers", null);
return json; return json;
} }
protected JsonObject getConnectionOptionsWithFinalJsonFormat() {
JsonObject json = this.connectionOptions.toJson(this.sessionId);
json.remove("session");
json.addProperty("serverData", json.get("data").getAsString());
json.remove("data");
return json;
}
private void updateConnectionOptions(ConnectionType type, String data, Boolean record, OpenViduRole role,
KurentoOptions kurentoOptions, String rtspUri, Boolean adaptativeBitrate, Boolean onlyPlayWithSubscribers,
Integer networkCache) {
ConnectionOptions.Builder builder = new ConnectionOptions.Builder();
if (type != null) {
builder.type(type);
}
if (data != null) {
builder.data(data);
}
if (record != null) {
builder.record(record);
}
if (role != null) {
builder.role(role);
}
if (kurentoOptions != null) {
builder.kurentoOptions(kurentoOptions);
}
if (rtspUri != null) {
builder.rtspUri(rtspUri);
}
if (adaptativeBitrate != null) {
builder.adaptativeBitrate(adaptativeBitrate);
}
if (onlyPlayWithSubscribers != null) {
builder.onlyPlayWithSubscribers(onlyPlayWithSubscribers);
}
if (networkCache != null) {
builder.networkCache(networkCache);
}
this.connectionOptions = builder.build();
}
@Override @Override
public String toString() { public String toString() {
if (this.role != null) if (this.connectionOptions.getRole() != null)
return this.role.name(); return this.connectionOptions.getRole().name();
else else
return this.token; return this.token;
} }

View File

@ -20,13 +20,15 @@ package io.openvidu.server.core;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.OpenViduRole;
import io.openvidu.server.OpenViduServer; import io.openvidu.server.OpenViduServer;
import io.openvidu.server.config.OpenviduBuildInfo; import io.openvidu.server.config.OpenviduBuildInfo;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.coturn.CoturnCredentialsService; import io.openvidu.server.coturn.CoturnCredentialsService;
import io.openvidu.server.coturn.TurnCredentials; import io.openvidu.server.coturn.TurnCredentials;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
public class TokenGenerator { public class TokenGenerator {
@ -39,8 +41,8 @@ public class TokenGenerator {
@Autowired @Autowired
protected OpenviduBuildInfo openviduBuildConfig; protected OpenviduBuildInfo openviduBuildConfig;
public Token generateToken(String sessionId, OpenViduRole role, String serverMetadata, boolean record, public Token generateToken(String sessionId, String serverMetadata, boolean record, OpenViduRole role,
KurentoTokenOptions kurentoTokenOptions) throws Exception { KurentoOptions kurentoOptions) throws Exception {
String token = OpenViduServer.wsUrl; String token = OpenViduServer.wsUrl;
token += "?sessionId=" + sessionId; token += "?sessionId=" + sessionId;
token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase() token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
@ -56,6 +58,8 @@ public class TokenGenerator {
token += "&turnCredential=" + turnCredentials.getCredential(); token += "&turnCredential=" + turnCredentials.getCredential();
} }
} }
return new Token(token, sessionId, role, serverMetadata, record, turnCredentials, kurentoTokenOptions); ConnectionOptions connectionOptions = new ConnectionOptions.Builder().type(ConnectionType.WEBRTC)
.data(serverMetadata).record(record).role(role).kurentoOptions(kurentoOptions).build();
return new Token(token, sessionId, connectionOptions, turnCredentials);
} }
} }

View File

@ -77,7 +77,7 @@ public class KurentoParticipant extends Participant {
public KurentoParticipant(Participant participant, KurentoSession kurentoSession, public KurentoParticipant(Participant participant, KurentoSession kurentoSession,
KurentoParticipantEndpointConfig endpointConfig, OpenviduConfig openviduConfig, KurentoParticipantEndpointConfig endpointConfig, OpenviduConfig openviduConfig,
RecordingManager recordingManager) { RecordingManager recordingManager) {
super(participant.getType(), participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(), super(participant.getFinalUserId(), participant.getParticipantPrivateId(), participant.getParticipantPublicId(),
kurentoSession.getSessionId(), participant.getToken(), participant.getClientMetadata(), kurentoSession.getSessionId(), participant.getToken(), participant.getClientMetadata(),
participant.getLocation(), participant.getPlatform(), participant.getEndpointType(), participant.getLocation(), participant.getPlatform(), participant.getEndpointType(),
participant.getActiveAt()); participant.getActiveAt());

View File

@ -48,6 +48,8 @@ import com.google.gson.JsonObject;
import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.OpenViduException.Code;
import io.openvidu.client.internal.ProtocolElements; import io.openvidu.client.internal.ProtocolElements;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.MediaMode; import io.openvidu.java.client.MediaMode;
import io.openvidu.java.client.Recording; import io.openvidu.java.client.Recording;
import io.openvidu.java.client.RecordingLayout; import io.openvidu.java.client.RecordingLayout;
@ -387,7 +389,7 @@ public class KurentoSessionManager extends SessionManager {
* kurentoParticipant.getPublisher().apply(elem); } * kurentoParticipant.getPublisher().apply(elem); }
*/ */
KurentoTokenOptions kurentoTokenOptions = participant.getToken().getKurentoTokenOptions(); KurentoOptions kurentoTokenOptions = participant.getToken().getKurentoOptions();
if (kurentoOptions.getFilter() != null && kurentoTokenOptions != null) { if (kurentoOptions.getFilter() != null && kurentoTokenOptions != null) {
if (kurentoTokenOptions.isFilterAllowed(kurentoOptions.getFilter().getType())) { if (kurentoTokenOptions.isFilterAllowed(kurentoOptions.getFilter().getType())) {
this.applyFilterInPublisher(kParticipant, kurentoOptions.getFilter()); this.applyFilterInPublisher(kParticipant, kurentoOptions.getFilter());
@ -990,7 +992,7 @@ public class KurentoSessionManager extends SessionManager {
@Override @Override
/* Protected by Session.closingLock.readLock */ /* Protected by Session.closingLock.readLock */
public Participant publishIpcam(Session session, MediaOptions mediaOptions, String serverMetadata) public Participant publishIpcam(Session session, MediaOptions mediaOptions, ConnectionOptions connectionOptions)
throws Exception { throws Exception {
final String sessionId = session.getSessionId(); final String sessionId = session.getSessionId();
final KurentoMediaOptions kMediaOptions = (KurentoMediaOptions) mediaOptions; final KurentoMediaOptions kMediaOptions = (KurentoMediaOptions) mediaOptions;
@ -1032,7 +1034,8 @@ public class KurentoSessionManager extends SessionManager {
this.newInsecureParticipant(rtspConnectionId); this.newInsecureParticipant(rtspConnectionId);
String token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase() String token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
+ RandomStringUtils.randomAlphanumeric(15); + RandomStringUtils.randomAlphanumeric(15);
this.newTokenForInsecureUser(session, token, serverMetadata);
this.newTokenForInsecureUser(session, token, connectionOptions);
final Token tokenObj = session.consumeToken(token); final Token tokenObj = session.consumeToken(token);
Participant ipcamParticipant = this.newIpcamParticipant(sessionId, rtspConnectionId, tokenObj, location, Participant ipcamParticipant = this.newIpcamParticipant(sessionId, rtspConnectionId, tokenObj, location,
@ -1111,7 +1114,8 @@ public class KurentoSessionManager extends SessionManager {
} }
@Override @Override
public void onVideoData(Participant participant, Integer transactionId, Integer height, Integer width, Boolean videoActive, Boolean audioActive) { public void onVideoData(Participant participant, Integer transactionId, Integer height, Integer width,
Boolean videoActive, Boolean audioActive) {
sessionEventsHandler.onVideoData(participant, transactionId, height, width, videoActive, audioActive); sessionEventsHandler.onVideoData(participant, transactionId, height, width, videoActive, audioActive);
} }

View File

@ -1,107 +0,0 @@
/*
* (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.server.kurento.core;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class KurentoTokenOptions {
private Integer videoMaxRecvBandwidth;
private Integer videoMinRecvBandwidth;
private Integer videoMaxSendBandwidth;
private Integer videoMinSendBandwidth;
private Map<String, Boolean> allowedFilters = new ConcurrentHashMap<>();
public KurentoTokenOptions(JsonObject options) {
if (options.has("videoMaxRecvBandwidth")) {
this.videoMaxRecvBandwidth = options.get("videoMaxRecvBandwidth").getAsInt();
}
if (options.has("videoMinRecvBandwidth")) {
this.videoMinRecvBandwidth = options.get("videoMinRecvBandwidth").getAsInt();
}
if (options.has("videoMaxSendBandwidth")) {
this.videoMaxSendBandwidth = options.get("videoMaxSendBandwidth").getAsInt();
}
if (options.has("videoMinSendBandwidth")) {
this.videoMinSendBandwidth = options.get("videoMinSendBandwidth").getAsInt();
}
if (options.has("allowedFilters")) {
JsonArray filters = options.get("allowedFilters").getAsJsonArray();
Iterator<JsonElement> it = filters.iterator();
while (it.hasNext()) {
this.allowedFilters.put(it.next().getAsString(), true);
}
}
}
public Integer getVideoMaxRecvBandwidth() {
return videoMaxRecvBandwidth;
}
public Integer getVideoMinRecvBandwidth() {
return videoMinRecvBandwidth;
}
public Integer getVideoMaxSendBandwidth() {
return videoMaxSendBandwidth;
}
public Integer getVideoMinSendBandwidth() {
return videoMinSendBandwidth;
}
public String[] getAllowedFilters() {
return allowedFilters.keySet().stream().toArray(String[]::new);
}
public boolean isFilterAllowed(String filterType) {
return this.allowedFilters.containsKey(filterType);
}
public JsonObject toJson() {
JsonObject json = new JsonObject();
if (this.getVideoMaxRecvBandwidth() != null) {
json.addProperty("videoMaxRecvBandwidth", this.getVideoMaxRecvBandwidth());
}
if (this.getVideoMinRecvBandwidth() != null) {
json.addProperty("videoMinRecvBandwidth", this.getVideoMinRecvBandwidth());
}
if (this.getVideoMaxSendBandwidth() != null) {
json.addProperty("videoMaxSendBandwidth", this.getVideoMaxSendBandwidth());
}
if (this.getVideoMinSendBandwidth() != null) {
json.addProperty("videoMinSendBandwidth", this.getVideoMinSendBandwidth());
}
if (this.getAllowedFilters().length > 0) {
JsonArray filtersJson = new JsonArray();
String[] filters = this.getAllowedFilters();
for (String filter : filters) {
filtersJson.add(filter);
}
json.add("allowedFilters", filtersJson);
}
return json;
}
}

View File

@ -53,11 +53,11 @@ import com.google.gson.JsonObject;
import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.OpenViduException.Code;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.Participant; import io.openvidu.server.core.Participant;
import io.openvidu.server.kurento.core.KurentoMediaOptions; import io.openvidu.server.kurento.core.KurentoMediaOptions;
import io.openvidu.server.kurento.core.KurentoParticipant; import io.openvidu.server.kurento.core.KurentoParticipant;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
/** /**
* {@link Endpoint} wrapper. Can be based on WebRtcEndpoint (that supports * {@link Endpoint} wrapper. Can be based on WebRtcEndpoint (that supports
@ -128,7 +128,7 @@ public abstract class MediaEndpoint {
this.openviduConfig = openviduConfig; this.openviduConfig = openviduConfig;
KurentoTokenOptions kurentoTokenOptions = this.owner.getToken().getKurentoTokenOptions(); KurentoOptions kurentoTokenOptions = this.owner.getToken().getKurentoOptions();
if (kurentoTokenOptions != null) { if (kurentoTokenOptions != null) {
this.maxRecvKbps = kurentoTokenOptions.getVideoMaxRecvBandwidth() != null this.maxRecvKbps = kurentoTokenOptions.getVideoMaxRecvBandwidth() != null
? kurentoTokenOptions.getVideoMaxRecvBandwidth() ? kurentoTokenOptions.getVideoMaxRecvBandwidth()

View File

@ -64,7 +64,9 @@ public class RecorderEndpointWrapper {
this.name = StringUtils.removeEnd(nameAux, SingleStreamRecordingService.INDIVIDUAL_RECORDING_EXTENSION); this.name = StringUtils.removeEnd(nameAux, SingleStreamRecordingService.INDIVIDUAL_RECORDING_EXTENSION);
this.connectionId = json.get("connectionId").getAsString(); this.connectionId = json.get("connectionId").getAsString();
this.streamId = json.get("streamId").getAsString(); this.streamId = json.get("streamId").getAsString();
this.clientData = json.get("clientData").getAsString(); this.clientData = (json.has("clientData") && !json.get("clientData").isJsonNull())
? json.get("clientData").getAsString()
: null;
this.serverData = json.get("serverData").getAsString(); this.serverData = json.get("serverData").getAsString();
this.startTime = json.get("startTime").getAsLong(); this.startTime = json.get("startTime").getAsLong();
this.endTime = json.get("endTime").getAsLong(); this.endTime = json.get("endTime").getAsLong();

View File

@ -20,7 +20,6 @@ package io.openvidu.server.rest;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -45,12 +44,15 @@ import org.springframework.web.bind.annotation.RestController;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException;
import io.openvidu.client.internal.ProtocolElements; import io.openvidu.client.internal.ProtocolElements;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.ConnectionType; import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.MediaMode; import io.openvidu.java.client.MediaMode;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.OpenViduRole;
import io.openvidu.java.client.Recording.OutputMode; import io.openvidu.java.client.Recording.OutputMode;
@ -66,7 +68,6 @@ import io.openvidu.server.core.Session;
import io.openvidu.server.core.SessionManager; import io.openvidu.server.core.SessionManager;
import io.openvidu.server.core.Token; import io.openvidu.server.core.Token;
import io.openvidu.server.kurento.core.KurentoMediaOptions; import io.openvidu.server.kurento.core.KurentoMediaOptions;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
import io.openvidu.server.recording.Recording; import io.openvidu.server.recording.Recording;
import io.openvidu.server.recording.service.RecordingManager; import io.openvidu.server.recording.service.RecordingManager;
import io.openvidu.server.utils.RecordingUtils; import io.openvidu.server.utils.RecordingUtils;
@ -273,45 +274,29 @@ public class SessionRestController {
public ResponseEntity<?> initializeConnection(@PathVariable("sessionId") String sessionId, public ResponseEntity<?> initializeConnection(@PathVariable("sessionId") String sessionId,
@RequestBody Map<?, ?> params) { @RequestBody Map<?, ?> params) {
log.info("REST API: POST {}/sessions/{}/connection {}", RequestMappings.API, sessionId, params.toString()); log.info("REST API: POST {} {}", RequestMappings.API + "/sessions/" + sessionId + "/connection",
params.toString());
Session session = this.sessionManager.getSessionWithNotActive(sessionId); Session session = this.sessionManager.getSessionWithNotActive(sessionId);
if (session == null) { if (session == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} }
String typeString; ConnectionOptions connectionOptions;
String data;
Boolean record;
try { try {
typeString = (String) params.get("type"); connectionOptions = getConnectionOptionsFromParams(params);
data = (String) params.get("data"); } catch (Exception e) {
record = (Boolean) params.get("record"); return this.generateErrorResponse(e.getMessage(), "/sessions/" + sessionId + "/connection",
} catch (ClassCastException e) { HttpStatus.BAD_REQUEST);
return this.generateErrorResponse("Type error in parameter \"type\"",
"/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
} }
switch (connectionOptions.getType()) {
ConnectionType type;
try {
if (typeString != null) {
type = ConnectionType.valueOf(typeString);
} else {
type = ConnectionType.WEBRTC;
}
} catch (IllegalArgumentException e) {
return this.generateErrorResponse("Parameter type " + params.get("typeString") + " is not defined",
RequestMappings.API + "/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST);
}
switch (type) {
case WEBRTC: case WEBRTC:
return this.newWebrtcConnection(session, data, record, params); return this.newWebrtcConnection(session, connectionOptions);
case IPCAM: case IPCAM:
return this.newIpcamConnection(session, data, record, params); return this.newIpcamConnection(session, connectionOptions);
default: default:
return this.generateErrorResponse("Wrong type " + typeString, return this.generateErrorResponse("Wrong type parameter", "/sessions/" + sessionId + "/connection",
RequestMappings.API + "/sessions/" + sessionId + "/connection", HttpStatus.BAD_REQUEST); HttpStatus.BAD_REQUEST);
} }
} }
@ -654,12 +639,8 @@ public class SessionRestController {
log.info("REST API: POST {}/tokens {}", RequestMappings.API, params.toString()); log.info("REST API: POST {}/tokens {}", RequestMappings.API, params.toString());
String sessionId; String sessionId;
String metadata;
Boolean record;
try { try {
sessionId = (String) params.get("session"); sessionId = (String) params.get("session");
metadata = (String) params.get("data");
record = (Boolean) params.get("record");
} catch (ClassCastException e) { } catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", "/tokens", HttpStatus.BAD_REQUEST); return this.generateErrorResponse("Type error in some parameter", "/tokens", HttpStatus.BAD_REQUEST);
} }
@ -675,10 +656,15 @@ public class SessionRestController {
if (session == null) { if (session == null) {
return this.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND); return this.generateErrorResponse("Session " + sessionId + " not found", "/tokens", HttpStatus.NOT_FOUND);
} }
Map<String, Object> map = new HashMap<>();
params.entrySet().forEach(entry -> map.put((String) entry.getKey(), entry.getValue())); ConnectionOptions connectionOptions;
map.put("type", "WEBRTC"); try {
ResponseEntity<?> entity = this.newWebrtcConnection(session, metadata, record, params); connectionOptions = getConnectionOptionsFromParams(params);
} catch (Exception e) {
return this.generateErrorResponse(e.getMessage(), "/sessions/" + sessionId + "/connection",
HttpStatus.BAD_REQUEST);
}
ResponseEntity<?> entity = this.newWebrtcConnection(session, connectionOptions);
JsonObject jsonResponse = JsonParser.parseString(entity.getBody().toString()).getAsJsonObject(); JsonObject jsonResponse = JsonParser.parseString(entity.getBody().toString()).getAsJsonObject();
if (jsonResponse.has("error")) { if (jsonResponse.has("error")) {
@ -793,57 +779,15 @@ public class SessionRestController {
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }
protected ResponseEntity<?> newWebrtcConnection(Session session, String serverData, Boolean record, protected ResponseEntity<?> newWebrtcConnection(Session session, ConnectionOptions connectionOptions) {
Map<?, ?> params) {
final String REQUEST_PATH = RequestMappings.API + "/sessions/" + session.getSessionId() + "/connection"; final String REQUEST_PATH = "/sessions/" + session.getSessionId() + "/connection";
String roleString = null;
try {
roleString = (String) params.get("role");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", REQUEST_PATH, HttpStatus.BAD_REQUEST);
}
OpenViduRole role = null;
try {
if (roleString != null) {
role = OpenViduRole.valueOf(roleString);
} else {
role = OpenViduRole.PUBLISHER;
}
} catch (IllegalArgumentException e) {
return this.generateErrorResponse("Parameter role " + params.get("role") + " is not defined", REQUEST_PATH,
HttpStatus.BAD_REQUEST);
}
JsonObject kurentoOptions = null;
if (params.get("kurentoOptions") != null) {
try {
kurentoOptions = JsonParser.parseString(params.get("kurentoOptions").toString()).getAsJsonObject();
} catch (Exception e) {
return this.generateErrorResponse("Error in parameter 'kurentoOptions'. It is not a valid JSON object",
REQUEST_PATH, HttpStatus.BAD_REQUEST);
}
}
KurentoTokenOptions kurentoTokenOptions = null;
if (kurentoOptions != null) {
try {
kurentoTokenOptions = new KurentoTokenOptions(kurentoOptions);
} catch (Exception e) {
return this.generateErrorResponse("Type error in some parameter of 'kurentoOptions'", REQUEST_PATH,
HttpStatus.BAD_REQUEST);
}
}
serverData = (serverData != null) ? serverData : "";
record = (record != null) ? record : true;
// While closing a session tokens can't be generated // While closing a session tokens can't be generated
if (session.closingLock.readLock().tryLock()) { if (session.closingLock.readLock().tryLock()) {
try { try {
Token token = sessionManager.newToken(session, role, serverData, record, kurentoTokenOptions); Token token = sessionManager.newToken(session, connectionOptions.getRole(), connectionOptions.getData(),
connectionOptions.record(), connectionOptions.getKurentoOptions());
return new ResponseEntity<>(token.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(), return new ResponseEntity<>(token.toJsonAsParticipant().toString(), RestUtils.getResponseHeaders(),
HttpStatus.OK); HttpStatus.OK);
} catch (Exception e) { } catch (Exception e) {
@ -861,34 +805,9 @@ public class SessionRestController {
} }
} }
protected ResponseEntity<?> newIpcamConnection(Session session, String serverData, Boolean record, protected ResponseEntity<?> newIpcamConnection(Session session, ConnectionOptions connectionOptions) {
Map<?, ?> params) {
final String REQUEST_PATH = RequestMappings.API + "/sessions/" + session.getSessionId() + "/connection"; final String REQUEST_PATH = "/sessions/" + session.getSessionId() + "/connection";
String rtspUri;
Boolean adaptativeBitrate;
Boolean onlyPlayWithSubscribers;
Integer networkCache;
try {
rtspUri = (String) params.get("rtspUri");
adaptativeBitrate = (Boolean) params.get("adaptativeBitrate");
onlyPlayWithSubscribers = (Boolean) params.get("onlyPlayWithSubscribers");
networkCache = (Integer) params.get("networkCache");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", REQUEST_PATH, HttpStatus.BAD_REQUEST);
}
if (rtspUri == null) {
return this.generateErrorResponse("\"rtspUri\" parameter is mandatory", REQUEST_PATH,
HttpStatus.BAD_REQUEST);
}
adaptativeBitrate = adaptativeBitrate != null ? adaptativeBitrate : true;
onlyPlayWithSubscribers = onlyPlayWithSubscribers != null ? onlyPlayWithSubscribers : true;
networkCache = networkCache != null ? networkCache : 2000;
serverData = serverData != null ? serverData : "";
record = (record != null) ? record : true;
boolean hasAudio = true; boolean hasAudio = true;
boolean hasVideo = true; boolean hasVideo = true;
@ -898,8 +817,9 @@ public class SessionRestController {
Integer frameRate = null; Integer frameRate = null;
String videoDimensions = null; String videoDimensions = null;
KurentoMediaOptions mediaOptions = new KurentoMediaOptions(true, null, hasAudio, hasVideo, audioActive, KurentoMediaOptions mediaOptions = new KurentoMediaOptions(true, null, hasAudio, hasVideo, audioActive,
videoActive, typeOfVideo, frameRate, videoDimensions, null, false, rtspUri, adaptativeBitrate, videoActive, typeOfVideo, frameRate, videoDimensions, null, false, connectionOptions.getRtspUri(),
onlyPlayWithSubscribers, networkCache); connectionOptions.adaptativeBitrate(), connectionOptions.onlyPlayWithSubscribers(),
connectionOptions.getNetworkCache());
// While closing a session IP cameras can't be published // While closing a session IP cameras can't be published
if (session.closingLock.readLock().tryLock()) { if (session.closingLock.readLock().tryLock()) {
@ -907,7 +827,8 @@ public class SessionRestController {
if (session.isClosed()) { if (session.isClosed()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND); return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} }
Participant ipcamParticipant = this.sessionManager.publishIpcam(session, mediaOptions, serverData); Participant ipcamParticipant = this.sessionManager.publishIpcam(session, mediaOptions,
connectionOptions);
return new ResponseEntity<>(ipcamParticipant.toJson().toString(), RestUtils.getResponseHeaders(), return new ResponseEntity<>(ipcamParticipant.toJson().toString(), RestUtils.getResponseHeaders(),
HttpStatus.OK); HttpStatus.OK);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
@ -936,6 +857,125 @@ public class SessionRestController {
return token; return token;
} }
protected ConnectionOptions getConnectionOptionsFromParams(Map<?, ?> params) throws Exception {
ConnectionOptions.Builder builder = new ConnectionOptions.Builder();
String typeString;
String data;
Boolean record;
try {
typeString = (String) params.get("type");
data = (String) params.get("data");
record = (Boolean) params.get("record");
} catch (ClassCastException e) {
throw new Exception("Type error in some parameter: " + e.getMessage());
}
ConnectionType type;
try {
if (typeString != null) {
type = ConnectionType.valueOf(typeString);
} else {
type = ConnectionType.WEBRTC;
}
} catch (IllegalArgumentException e) {
throw new Exception("Parameter 'type' " + typeString + " is not defined");
}
data = data != null ? data : "";
record = record != null ? record : true;
// Build COMMON options
builder.type(type).data(data).record(record);
OpenViduRole role = null;
KurentoOptions kurentoOptions = null;
if (ConnectionType.WEBRTC.equals(type)) {
String roleString;
try {
roleString = (String) params.get("role");
} catch (ClassCastException e) {
throw new Exception("Type error in parameter 'role': " + e.getMessage());
}
try {
if (roleString != null) {
role = OpenViduRole.valueOf(roleString);
} else {
role = OpenViduRole.PUBLISHER;
}
} catch (IllegalArgumentException e) {
throw new Exception("Parameter role " + params.get("role") + " is not defined");
}
JsonObject kurentoOptionsJson = null;
if (params.get("kurentoOptions") != null) {
try {
kurentoOptionsJson = JsonParser.parseString(params.get("kurentoOptions").toString())
.getAsJsonObject();
} catch (Exception e) {
throw new Exception("Error in parameter 'kurentoOptions'. It is not a valid JSON object");
}
}
if (kurentoOptionsJson != null) {
try {
KurentoOptions.Builder builder2 = new KurentoOptions.Builder();
if (kurentoOptionsJson.has("videoMaxRecvBandwidth")) {
builder2.videoMaxRecvBandwidth(kurentoOptionsJson.get("videoMaxRecvBandwidth").getAsInt());
}
if (kurentoOptionsJson.has("videoMinRecvBandwidth")) {
builder2.videoMinRecvBandwidth(kurentoOptionsJson.get("videoMinRecvBandwidth").getAsInt());
}
if (kurentoOptionsJson.has("videoMaxSendBandwidth")) {
builder2.videoMaxSendBandwidth(kurentoOptionsJson.get("videoMaxSendBandwidth").getAsInt());
}
if (kurentoOptionsJson.has("videoMinSendBandwidth")) {
builder2.videoMinSendBandwidth(kurentoOptionsJson.get("videoMinSendBandwidth").getAsInt());
}
if (kurentoOptionsJson.has("allowedFilters")) {
JsonArray filters = kurentoOptionsJson.get("allowedFilters").getAsJsonArray();
String[] arrayOfFilters = new String[filters.size()];
Iterator<JsonElement> it = filters.iterator();
int index = 0;
while (it.hasNext()) {
arrayOfFilters[index] = it.next().getAsString();
index++;
}
builder2.allowedFilters(arrayOfFilters);
}
kurentoOptions = builder2.build();
} catch (Exception e) {
throw new Exception("Type error in some parameter of 'kurentoOptions': " + e.getMessage());
}
}
// Build WEBRTC options
builder.role(role).kurentoOptions(kurentoOptions);
} else if (ConnectionType.IPCAM.equals(type)) {
String rtspUri;
Boolean adaptativeBitrate;
Boolean onlyPlayWithSubscribers;
Integer networkCache;
try {
rtspUri = (String) params.get("rtspUri");
adaptativeBitrate = (Boolean) params.get("adaptativeBitrate");
onlyPlayWithSubscribers = (Boolean) params.get("onlyPlayWithSubscribers");
networkCache = (Integer) params.get("networkCache");
} catch (ClassCastException e) {
throw new Exception("Type error in some parameter: " + e.getMessage());
}
adaptativeBitrate = adaptativeBitrate != null ? adaptativeBitrate : true;
onlyPlayWithSubscribers = onlyPlayWithSubscribers != null ? onlyPlayWithSubscribers : true;
networkCache = networkCache != null ? networkCache : 2000;
// Build IPCAM options
builder.rtspUri(rtspUri).adaptativeBitrate(adaptativeBitrate)
.onlyPlayWithSubscribers(onlyPlayWithSubscribers).networkCache(networkCache).build();
}
return builder.build();
}
protected ResponseEntity<String> generateErrorResponse(String errorMessage, String path, HttpStatus status) { protected ResponseEntity<String> generateErrorResponse(String errorMessage, String path, HttpStatus status) {
JsonObject responseJson = new JsonObject(); JsonObject responseJson = new JsonObject();
responseJson.addProperty("timestamp", System.currentTimeMillis()); responseJson.addProperty("timestamp", System.currentTimeMillis());

View File

@ -45,6 +45,7 @@ import com.google.gson.JsonSyntaxException;
import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.OpenViduException.Code;
import io.openvidu.client.internal.ProtocolElements; import io.openvidu.client.internal.ProtocolElements;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.config.OpenviduConfig;
import io.openvidu.server.core.EndReason; import io.openvidu.server.core.EndReason;
import io.openvidu.server.core.IdentifierPrefixes; import io.openvidu.server.core.IdentifierPrefixes;
@ -248,7 +249,7 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase() token = IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
+ RandomStringUtils.randomAlphanumeric(15); + RandomStringUtils.randomAlphanumeric(15);
try { try {
sessionManager.newTokenForInsecureUser(session, token, null); sessionManager.newTokenForInsecureUser(session, token, new ConnectionOptions.Builder().build());
} catch (Exception e) { } catch (Exception e) {
throw new OpenViduException(Code.TOKEN_CANNOT_BE_CREATED_ERROR_CODE, throw new OpenViduException(Code.TOKEN_CANNOT_BE_CREATED_ERROR_CODE,
"Unable to create token for session " + sessionId + ": " + e.getMessage()); "Unable to create token for session " + sessionId + ": " + e.getMessage());
@ -492,7 +493,7 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
// user's stream) or if the user is the owner of the stream and has a token // user's stream) or if the user is the owner of the stream and has a token
// configured with this specific filter // configured with this specific filter
if (isModerator || (this.userIsStreamOwner(rpcConnection.getSessionId(), participant, streamId) if (isModerator || (this.userIsStreamOwner(rpcConnection.getSessionId(), participant, streamId)
&& participant.getToken().getKurentoTokenOptions().isFilterAllowed(filterType))) { && participant.getToken().getKurentoOptions().isFilterAllowed(filterType))) {
JsonObject filterOptions; JsonObject filterOptions;
try { try {
filterOptions = JsonParser.parseString(getStringParam(request, ProtocolElements.FILTER_OPTIONS_PARAM)) filterOptions = JsonParser.parseString(getStringParam(request, ProtocolElements.FILTER_OPTIONS_PARAM))

View File

@ -36,7 +36,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.server.core.Participant; import io.openvidu.server.core.Participant;
import io.openvidu.server.core.SessionManager; import io.openvidu.server.core.SessionManager;
import io.openvidu.server.core.Token; import io.openvidu.server.core.Token;
@ -115,7 +115,8 @@ public class SessionGarbageCollectorIntegrationTest {
} }
private void joinParticipant(String sessionId, String token) { private void joinParticipant(String sessionId, String token) {
Token t = new Token(token, sessionId, OpenViduRole.PUBLISHER, "SERVER_METADATA", true, null, null); ConnectionOptions connectionOptions = new ConnectionOptions.Builder().data("SERVER_METADATA").build();
Token t = new Token(token, sessionId, connectionOptions, null);
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
String participantPrivateId = "PARTICIPANT_PRIVATE_ID_" + uuid; String participantPrivateId = "PARTICIPANT_PRIVATE_ID_" + uuid;
String finalUserId = "FINAL_USER_ID_" + uuid; String finalUserId = "FINAL_USER_ID_" + uuid;

View File

@ -110,7 +110,7 @@ public class CustomHttpClient {
public JsonObject rest(HttpMethod method, String path, String body, int status, boolean matchKeys, public JsonObject rest(HttpMethod method, String path, String body, int status, boolean matchKeys,
boolean matchValues, boolean matchArrays, String jsonReturnedValue) throws Exception { boolean matchValues, boolean matchArrays, String jsonReturnedValue) throws Exception {
JsonObject jsonExpected = null; JsonObject jsonExpected = null;
jsonReturnedValue.replaceAll("'", "\""); jsonReturnedValue = jsonReturnedValue.replaceAll("'", "\"");
try { try {
jsonExpected = JsonParser.parseString(jsonReturnedValue).getAsJsonObject(); jsonExpected = JsonParser.parseString(jsonReturnedValue).getAsJsonObject();
} catch (JsonSyntaxException e1) { } catch (JsonSyntaxException e1) {
@ -171,7 +171,8 @@ public class CustomHttpClient {
public static void checkSameType(JsonElement expected, JsonElement actual, String key, boolean checkAlsoSameValue) public static void checkSameType(JsonElement expected, JsonElement actual, String key, boolean checkAlsoSameValue)
throws Exception { throws Exception {
if (!expected.getClass().equals(actual.getClass())) { if (!expected.getClass().equals(actual.getClass())) {
throw new Exception("Expected JSON element has not the same class as the actual JSON element. Expected: " throw new Exception("Expected JSON element \"" + key
+ "\" has not the same class as the actual JSON element. Expected: "
+ expected.getClass().getSimpleName() + ". Actual: " + actual.getClass().getSimpleName()); + expected.getClass().getSimpleName() + ". Actual: " + actual.getClass().getSimpleName());
} }
if (expected.isJsonNull()) { if (expected.isJsonNull()) {

View File

@ -45,6 +45,7 @@ import org.slf4j.LoggerFactory;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import io.github.bonigarcia.wdm.WebDriverManager; import io.github.bonigarcia.wdm.WebDriverManager;
@ -63,6 +64,12 @@ import io.openvidu.test.browsers.utils.Unzipper;
public class AbstractOpenViduTestAppE2eTest { public class AbstractOpenViduTestAppE2eTest {
final protected String DEFAULT_JSON_SESSION = "{'id':'STR','object':'session','sessionId':'STR','createdAt':0,'mediaMode':'STR','recordingMode':'STR','defaultOutputMode':'STR','defaultRecordingLayout':'STR','customSessionId':'STR','connections':{'numberOfElements':0,'content':[]},'recording':false}";
final protected String DEFAULT_JSON_PENDING_CONNECTION = "{'id':'STR','object':'connection','type':'WEBRTC','status':'pending','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':null,'location':null,'platform':null,'token':'STR','serverData':'STR','record':true,'role':'STR','kurentoOptions':null,'rtspUri':null,'adaptativeBitrate':null,'onlyPlayWithSubscribers':null,'networkCache':null,'clientData':null,'publishers':null,'subscribers':null}";
final protected String DEFAULT_JSON_ACTIVE_CONNECTION = "{'id':'STR','object':'connection','type':'WEBRTC','status':'active','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':0,'location':'STR','platform':'STR','token':'STR','serverData':'STR','record':true,'role':'STR','kurentoOptions':null,'rtspUri':null,'adaptativeBitrate':null,'onlyPlayWithSubscribers':null,'networkCache':null,'clientData':'STR','publishers':[],'subscribers':[]}";
final protected String DEFAULT_JSON_IPCAM_CONNECTION = "{'id':'STR','object':'connection','type':'IPCAM','status':'active','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':0,'location':'STR','platform':'IPCAM','token':null,'serverData':'STR','record':true,'role':null,'kurentoOptions':null,'rtspUri':'STR','adaptativeBitrate':true,'onlyPlayWithSubscribers':true,'networkCache':2000,'clientData':null,'publishers':[],'subscribers':[]}";
final protected String DEFAULT_JSON_TOKEN = "{'id':'STR','token':'STR','connectionId':'STR','createdAt':0,'session':'STR','role':'STR','data':'STR','kurentoOptions':{}}";
protected static String OPENVIDU_SECRET = "MY_SECRET"; protected static String OPENVIDU_SECRET = "MY_SECRET";
protected static String OPENVIDU_URL = "https://localhost:4443/"; protected static String OPENVIDU_URL = "https://localhost:4443/";
protected static String APP_URL = "http://localhost:4200/"; protected static String APP_URL = "http://localhost:4200/";
@ -546,4 +553,17 @@ public class AbstractOpenViduTestAppE2eTest {
+ " | awk '{print $1 }' | xargs -I {} docker rm -f {}"); + " | awk '{print $1 }' | xargs -I {} docker rm -f {}");
} }
protected String mergeJson(String json, String newProperties, String[] removeProperties) {
JsonObject jsonObj = JsonParser.parseString(json.replaceAll("'", "\"")).getAsJsonObject();
JsonObject newJsonObj = JsonParser.parseString(newProperties.replaceAll("'", "\"")).getAsJsonObject();
newJsonObj.entrySet().forEach(entry -> {
jsonObj.remove(entry.getKey());
jsonObj.add(entry.getKey(), entry.getValue());
});
for (String prop : removeProperties) {
jsonObj.remove(prop);
}
return jsonObj.toString().replaceAll("\"", "'");
}
} }

View File

@ -31,7 +31,6 @@ import io.openvidu.java.client.OpenViduHttpException;
import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.OpenViduRole;
import io.openvidu.java.client.Recording; import io.openvidu.java.client.Recording;
import io.openvidu.java.client.Session; import io.openvidu.java.client.Session;
import io.openvidu.java.client.Token;
import io.openvidu.test.browsers.utils.CustomHttpClient; import io.openvidu.test.browsers.utils.CustomHttpClient;
import io.openvidu.test.browsers.utils.Unzipper; import io.openvidu.test.browsers.utils.Unzipper;
@ -212,19 +211,19 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Updating only role should let record value untouched // Updating only role should let record value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'MODERATOR'}", HttpStatus.SC_OK, true, true, true, "{'role':'MODERATOR'}", HttpStatus.SC_OK, true, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_PENDING_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'pending','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token + "','role':'MODERATOR','serverData':'','record':false,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':" + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + "}",
+ createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}"); new String[0]));
// Updating only record should let role value untouched // Updating only record should let role value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'record':true}", HttpStatus.SC_OK, true, true, true, "{'record':true}", HttpStatus.SC_OK, true, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_PENDING_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'pending','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token + "','role':'MODERATOR','serverData':'','token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':null,'subscribers':null,'createdAt':" + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + "}",
+ createdAt + ",'activeAt':null,'platform':null,'location':null,'clientData':null}"); new String[0]));
// Test with openvidu-java-client // Test with openvidu-java-client
OpenVidu OV = new OpenVidu(OpenViduTestAppE2eTest.OPENVIDU_URL, OpenViduTestAppE2eTest.OPENVIDU_SECRET); OpenVidu OV = new OpenVidu(OpenViduTestAppE2eTest.OPENVIDU_URL, OpenViduTestAppE2eTest.OPENVIDU_SECRET);
@ -275,6 +274,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertTrue("Session object should have changed", session.fetch()); Assert.assertTrue("Session object should have changed", session.fetch());
connection = session.getActiveConnections().get(0); connection = session.getActiveConnections().get(0);
final Long activeAt = connection.activeAt();
Assert.assertTrue("activeAt should be greater than createdAt in Connection object", activeAt > createdAt);
Assert.assertEquals("Wrong role in Connection object", OpenViduRole.SUBSCRIBER, connection.getRole()); Assert.assertEquals("Wrong role in Connection object", OpenViduRole.SUBSCRIBER, connection.getRole());
Assert.assertFalse("Wrong record in Connection object", connection.record()); Assert.assertFalse("Wrong record in Connection object", connection.record());
@ -284,29 +285,37 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Updating only role should let record value untouched // Updating only role should let record value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'MODERATOR'}", HttpStatus.SC_OK, false, true, true, "{'role':'MODERATOR'}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_ACTIVE_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'MODERATOR','record':false,'token':'" + token + "','role':'MODERATOR','record':false,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + ",'activeAt':"
+ activeAt + ",'serverData':''}",
new String[] { "location", "platform", "clientData" }));
// Updating only record should let role value untouched // Updating only record should let role value untouched
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'record':true}", HttpStatus.SC_OK, false, true, true, "{'record':true}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_ACTIVE_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'MODERATOR','record':true,'token':'" + token + "','role':'MODERATOR','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + ",'activeAt':"
+ activeAt + ",'serverData':''}",
new String[] { "location", "platform", "clientData" }));
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'SUBSCRIBER','record':true,'data':'OTHER DATA'}", HttpStatus.SC_OK, false, true, true, "{'role':'SUBSCRIBER','record':true,'data':'OTHER DATA'}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_ACTIVE_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'SUBSCRIBER','record':true,'token':'" + token + "','role':'SUBSCRIBER','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + ",'activeAt':"
+ activeAt + ",'serverData':''}",
new String[] { "location", "platform", "clientData" }));
restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId, restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenConnectionId,
"{'role':'PUBLISHER'}", HttpStatus.SC_OK, false, true, true, "{'role':'PUBLISHER'}", HttpStatus.SC_OK, false, true, true,
"{'id':'" + tokenConnectionId mergeJson(DEFAULT_JSON_ACTIVE_CONNECTION,
+ "','object':'connection','type':'WEBRTC','status':'active','connectionId':'" "{'id':'" + tokenConnectionId + "','connectionId':'" + tokenConnectionId
+ tokenConnectionId + "','role':'PUBLISHER','record':true,'token':'" + token + "','role':'PUBLISHER','record':true,'token':'" + token
+ "','sessionId':'CUSTOM_SESSION_ID','serverData':'','publishers':[],'subscribers':[]}"); + "','sessionId':'CUSTOM_SESSION_ID','createdAt':" + createdAt + ",'activeAt':"
+ activeAt + ",'serverData':''}",
new String[] { "location", "platform", "clientData" }));
// Test with openvidu-node-client // Test with openvidu-node-client
user.getDriver().findElement(By.id("session-api-btn-0")).click(); user.getDriver().findElement(By.id("session-api-btn-0")).click();
@ -341,7 +350,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertFalse("Session object should not have changed", session.fetch()); Assert.assertFalse("Session object should not have changed", session.fetch());
Assert.assertEquals("Wrong connectionId in Connection object", tokenConnectionId, connection.getConnectionId()); Assert.assertEquals("Wrong connectionId in Connection object", tokenConnectionId, connection.getConnectionId());
Assert.assertEquals("Wrong role in Connection object", OpenViduRole.PUBLISHER, connection.getRole()); Assert.assertEquals("Wrong role in Connection object", OpenViduRole.PUBLISHER, connection.getRole());
Assert.assertTrue("Wrong record in Connection object", connection.record()); Assert.assertFalse("Wrong record in Connection object", connection.record());
Assert.assertEquals("Wrong status in Connection object", "active", connection.getStatus()); Assert.assertEquals("Wrong status in Connection object", "active", connection.getStatus());
connection = session.updateConnection(tokenConnectionId, connection = session.updateConnection(tokenConnectionId,
new ConnectionOptions.Builder().role(OpenViduRole.SUBSCRIBER).build()); new ConnectionOptions.Builder().role(OpenViduRole.SUBSCRIBER).build());
@ -397,9 +406,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
void openViduJavaClientProTest() throws Exception { void openViduJavaClientProTest() throws Exception {
Session session = OV.createSession(); Session session = OV.createSession();
Assert.assertFalse(session.fetch()); Assert.assertFalse(session.fetch());
Token token = session.createToken(); Connection connection = session.createConnection();
Assert.assertTrue(session.fetch()); Assert.assertFalse(session.fetch());
Connection connection = session.getConnection(token.getConnectionId());
Assert.assertEquals("Wrong role property", OpenViduRole.PUBLISHER, connection.getRole()); Assert.assertEquals("Wrong role property", OpenViduRole.PUBLISHER, connection.getRole());
Assert.assertTrue("Wrong record property", connection.record()); Assert.assertTrue("Wrong record property", connection.record());
session.updateConnection(connection.getConnectionId(), session.updateConnection(connection.getConnectionId(),

View File

@ -48,11 +48,14 @@ import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.ExpectedConditions;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.mashape.unirest.http.HttpMethod; import com.mashape.unirest.http.HttpMethod;
import io.openvidu.java.client.Connection; import io.openvidu.java.client.Connection;
import io.openvidu.java.client.ConnectionOptions;
import io.openvidu.java.client.ConnectionType;
import io.openvidu.java.client.KurentoOptions; import io.openvidu.java.client.KurentoOptions;
import io.openvidu.java.client.MediaMode; import io.openvidu.java.client.MediaMode;
import io.openvidu.java.client.OpenVidu; import io.openvidu.java.client.OpenVidu;
@ -66,8 +69,6 @@ import io.openvidu.java.client.RecordingMode;
import io.openvidu.java.client.RecordingProperties; import io.openvidu.java.client.RecordingProperties;
import io.openvidu.java.client.Session; import io.openvidu.java.client.Session;
import io.openvidu.java.client.SessionProperties; import io.openvidu.java.client.SessionProperties;
import io.openvidu.java.client.Token;
import io.openvidu.java.client.TokenOptions;
import io.openvidu.test.browsers.FirefoxUser; import io.openvidu.test.browsers.FirefoxUser;
import io.openvidu.test.browsers.utils.CustomHttpClient; import io.openvidu.test.browsers.utils.CustomHttpClient;
import io.openvidu.test.browsers.utils.layout.CustomLayoutHandler; import io.openvidu.test.browsers.utils.layout.CustomLayoutHandler;
@ -84,10 +85,6 @@ import io.openvidu.test.browsers.utils.webhook.CustomWebhook;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest { public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
final String DEFAULT_JSON_SESSION = "{'id':'STR','object':'STR','sessionId':'STR','createdAt':0,'mediaMode':'STR','recordingMode':'STR','defaultOutputMode':'STR','defaultRecordingLayout':'STR','customSessionId':'STR','connections':{'numberOfElements':0,'content':[]},'recording':false}";
final String DEFAULT_JSON_TOKEN = "{'id':'STR','object':'STR','token':'STR','connectionId':0,'session':'STR','createdAt':0,'role':'STR','data':'STR','record':true}";
final String DEFAULT_JSON_CONNECTION = "{'id':'STR','object':'STR','type':'STR','status':'STR','connectionId':'STR','sessionId':'STR','createdAt':0,'activeAt':0,'location':'STR','platform':'STR','role':'STR','record':true,'serverData':'STR','clientData':'STR','publishers':[],'subscribers':[]}";
@BeforeAll() @BeforeAll()
protected static void setupAll() { protected static void setupAll() {
checkFfmpegInstallation(); checkFfmpegInstallation();
@ -2141,27 +2138,19 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
KurentoOptions kurentoOptions = new KurentoOptions.Builder().videoMaxRecvBandwidth(250) KurentoOptions kurentoOptions = new KurentoOptions.Builder().videoMaxRecvBandwidth(250)
.allowedFilters(new String[] { "GStreamerFilter" }).build(); .allowedFilters(new String[] { "GStreamerFilter" }).build();
TokenOptions tokenOptionsModerator = new TokenOptions.Builder().role(OpenViduRole.MODERATOR) ConnectionOptions moderatorConnectionOptions = new ConnectionOptions.Builder().role(OpenViduRole.MODERATOR)
.data(serverDataModerator).kurentoOptions(kurentoOptions).build(); .data(serverDataModerator).kurentoOptions(kurentoOptions).build();
Token tokenModerator = session.createToken(tokenOptionsModerator); Connection connectionModerator = session.createConnection(moderatorConnectionOptions);
String tokenModeratorString = tokenModerator.getToken();
String connectionIdModerator = tokenModerator.getConnectionId();
TokenOptions tokenOptionsSubscriber = new TokenOptions.Builder().role(OpenViduRole.SUBSCRIBER) ConnectionOptions subscriberConnectionOptions = new ConnectionOptions.Builder().type(ConnectionType.WEBRTC)
.data(serverDataSubscriber).build(); .role(OpenViduRole.SUBSCRIBER).data(serverDataSubscriber).build();
Token tokenSubscriber = session.createToken(tokenOptionsSubscriber); Connection connectionSubscriber = session.createConnection(subscriberConnectionOptions);
String tokenSubscriberString = tokenSubscriber.getToken();
String connectionIdSubscriber = tokenSubscriber.getConnectionId();
Assert.assertTrue("Session.fetch() should return true if new pending connections", session.fetch()); Assert.assertFalse("Session.fetch() should return false after Session.createConnection", session.fetch());
Assert.assertFalse("OpenVidu.fetch() should return false after Session.fetch()", OV.fetch()); Assert.assertFalse("OpenVidu.fetch() should return false after Session.fetch()", OV.fetch());
Assert.assertEquals("Wrong number of active connections", 0, session.getActiveConnections().size()); Assert.assertEquals("Wrong number of active connections", 0, session.getActiveConnections().size());
Assert.assertEquals("Wrong number of connections", 2, session.getConnections().size()); Assert.assertEquals("Wrong number of connections", 2, session.getConnections().size());
Connection connectionModerator = session.getConnection(connectionIdModerator);
Connection connectionSubscriber = session.getConnection(connectionIdSubscriber);
Assert.assertEquals("Wrong connectionId property", connectionIdModerator,
connectionModerator.getConnectionId());
Assert.assertEquals("Wrong status property", "pending", connectionModerator.getStatus()); Assert.assertEquals("Wrong status property", "pending", connectionModerator.getStatus());
Assert.assertEquals("Wrong role property", OpenViduRole.MODERATOR, connectionModerator.getRole()); Assert.assertEquals("Wrong role property", OpenViduRole.MODERATOR, connectionModerator.getRole());
Assert.assertTrue("Wrong record property", connectionModerator.record()); Assert.assertTrue("Wrong record property", connectionModerator.record());
@ -2183,7 +2172,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Thread.sleep(1000); Thread.sleep(1000);
WebElement tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input")); WebElement tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input"));
tokeInput.clear(); tokeInput.clear();
tokeInput.sendKeys(tokenModeratorString); tokeInput.sendKeys(connectionModerator.getToken());
user.getDriver().findElement(By.id("save-btn")).click(); user.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(1000); Thread.sleep(1000);
@ -2198,7 +2187,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Thread.sleep(1000); Thread.sleep(1000);
tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input")); tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input"));
tokeInput.clear(); tokeInput.clear();
tokeInput.sendKeys(tokenSubscriberString); tokeInput.sendKeys(connectionSubscriber.getToken());
user.getDriver().findElement(By.id("save-btn")).click(); user.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(1000); Thread.sleep(1000);
@ -2514,8 +2503,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
} }
pub = connectionModerator.getPublishers().get(0); pub = connectionModerator.getPublishers().get(0);
// TODO: test delete unused Token, update unused Token and update ongoing // TODO: test delete unused Connection
// Connection
session.forceUnpublish(pub); session.forceUnpublish(pub);
user.getEventManager().waitUntilEventReaches("streamDestroyed", 6); user.getEventManager().waitUntilEventReaches("streamDestroyed", 6);
@ -2528,6 +2516,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertEquals("Wrong number of Subscribers", 0, con.getSubscribers().size()); Assert.assertEquals("Wrong number of Subscribers", 0, con.getSubscribers().size());
}); });
// Delete active Connection
session.forceDisconnect(connectionModerator); session.forceDisconnect(connectionModerator);
user.getEventManager().waitUntilEventReaches("sessionDisconnected", 1); user.getEventManager().waitUntilEventReaches("sessionDisconnected", 1);
user.getEventManager().waitUntilEventReaches("connectionDestroyed", 1); user.getEventManager().waitUntilEventReaches("connectionDestroyed", 1);
@ -2541,6 +2530,33 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertFalse("Session.fetch() should return true", OV.fetch()); Assert.assertFalse("Session.fetch() should return true", OV.fetch());
// Delete pending Connection
session = OV.createSession();
Connection con = session.createConnection();
Assert.assertEquals("Wrong number of Connections", 1, session.getConnections().size());
Assert.assertEquals("Wrong number of active Connections", 0, session.getActiveConnections().size());
Assert.assertFalse(session.fetch());
session.forceDisconnect(con);
Assert.assertEquals("Wrong number of Connections", 0, session.getConnections().size());
Assert.assertEquals("Wrong number of active Connections", 0, session.getActiveConnections().size());
Assert.assertFalse(session.fetch());
// Test IPCAM
final String rtsp = "rtsp://dummyurl.com";
Connection ipcamera = session.createConnection(new ConnectionOptions.Builder().type(ConnectionType.IPCAM)
.rtspUri(rtsp).adaptativeBitrate(false).onlyPlayWithSubscribers(false).networkCache(50).build());
Assert.assertFalse("OpenVidu.fetch() should return false", OV.fetch());
Assert.assertFalse("Session.fetch() should return false", session.fetch());
Assert.assertEquals("Wrong number of active connections", 1, session.getActiveConnections().size());
Assert.assertEquals("Wrong number of connections", 1, session.getConnections().size());
ipcamera = session.getConnection(ipcamera.getConnectionId());
Assert.assertEquals("Wrong type property of Connection object", "IPCAM", ipcamera.getType().name());
Assert.assertNull("Property role of an IPCAM connection should be null", ipcamera.getRole());
Assert.assertEquals("Wrong property rtspUri", rtsp, ipcamera.getRtspUri());
Assert.assertFalse("Wrong property adaptativeBitrate", ipcamera.adaptativeBitrate());
Assert.assertFalse("Wrong property onlyPlayWithSubscribers", ipcamera.onlyPlayWithSubscribers());
Assert.assertEquals("Wrong property networkCache", 50, ipcamera.getNetworkCache());
gracefullyLeaveParticipants(2); gracefullyLeaveParticipants(2);
} }
@ -2626,31 +2642,61 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// 200 // 200
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 'SERVER_DATA', 'kurentoOptions': {'videoMaxSendBandwidth':777,'allowedFilters': ['GStreamerFilter']}}"; body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 'SERVER_DATA', 'kurentoOptions': {'videoMaxSendBandwidth':777,'allowedFilters': ['GStreamerFilter']}}";
res = restClient.rest(HttpMethod.POST, "/openvidu/api/tokens", body, HttpStatus.SC_OK, true, false, true, res = restClient.rest(HttpMethod.POST, "/openvidu/api/tokens", body, HttpStatus.SC_OK, true, false, true,
"{'id':'STR','object':'STR','connectionId':'STR','session':'STR','createdAt':0,'role':'STR','data':'STR','record':true,'token':'STR','kurentoOptions':{'videoMaxSendBandwidth':777,'allowedFilters':['STR']}}"); mergeJson(DEFAULT_JSON_TOKEN,
"{'kurentoOptions':{'videoMaxSendBandwidth':777,'allowedFilters':['STR']}}", new String[0]));
final String token1 = res.get("token").getAsString(); final String token1 = res.get("token").getAsString();
final String connectionId1 = res.get("connectionId").getAsString();
final long createdAt1 = res.get("createdAt").getAsLong();
Assert.assertEquals("JSON return value from /openvidu/api/tokens should have equal srtings in 'id' and 'token'", Assert.assertEquals("JSON return value from /openvidu/api/tokens should have equal srtings in 'id' and 'token'",
res.get("id").getAsString(), token1); res.get("id").getAsString(), token1);
Assert.assertEquals("Wrong session parameter", "CUSTOM_SESSION_ID", res.get("session").getAsString()); Assert.assertEquals("Wrong session parameter", "CUSTOM_SESSION_ID", res.get("session").getAsString());
res = restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", null,
HttpStatus.SC_OK, true, true, false, "{'numberOfElements':1,'content':[]}");
JsonObject connection1 = res.getAsJsonObject().get("content").getAsJsonArray().get(0).getAsJsonObject();
final String connectionId1 = connection1.get("id").getAsString();
final long createdAt1 = connection1.get("createdAt").getAsLong();
/** POST /openvidu/api/sessions/CUSTOM_SESSION_ID/connection **/
// 400
body = "{'type':false}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_BAD_REQUEST);
body = "{'type':'NOT_EXISTS'}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_BAD_REQUEST);
body = "{'type':'WEBRTC','role':123}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_BAD_REQUEST);
body = "{'type':'WEBRTC','role':123}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_BAD_REQUEST);
body = "{'type':'WEBRTC','role':'MODERATOR','data':true}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_BAD_REQUEST);
// 200
String kurentoOpts = "'kurentoOptions':{'videoMaxSendBandwidth':777,'allowedFilters':['GStreamerFilter']}";
body = "{'type':'WEBRTC','role':'MODERATOR','data':'SERVER_DATA'," + kurentoOpts + "}";
res = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
HttpStatus.SC_OK, true, false, true,
mergeJson(DEFAULT_JSON_PENDING_CONNECTION, "{" + kurentoOpts + "}", new String[0]));
restClient.rest(HttpMethod.DELETE,
"/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + res.get("id").getAsString(),
HttpStatus.SC_NO_CONTENT);
// Default values // Default values
body = "{'session': 'CUSTOM_SESSION_ID'}"; res = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", "{}",
res = restClient.rest(HttpMethod.POST, "/openvidu/api/tokens", body, HttpStatus.SC_OK, true, false, true, HttpStatus.SC_OK);
DEFAULT_JSON_TOKEN); final String token2 = res.get("token").getAsString();
final String token2 = res.get("id").getAsString(); final String connectionId2 = res.get("id").getAsString();
final String connectionId2 = res.get("connectionId").getAsString();
/** GET /openvidu/api/sessions/ID/connection (with pending connections) **/ /** GET /openvidu/api/sessions/ID/connection (with pending connections) **/
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", null, HttpStatus.SC_OK, restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", null, HttpStatus.SC_OK,
true, true, false, "{'numberOfElements':2,'content':[]}"); true, true, false, "{'numberOfElements':2,'content':[]}");
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null, restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionId1, null,
HttpStatus.SC_OK, true, true, true, HttpStatus.SC_OK, true, true, true,
mergeJson(DEFAULT_JSON_PENDING_CONNECTION,
"{'id':'" + connectionId1 + "','connectionId':'" + connectionId1 "{'id':'" + connectionId1 + "','connectionId':'" + connectionId1
+ "','object':'connection','type':'WEBRTC','status':'pending','sessionId':'CUSTOM_SESSION_ID','token':'" + "','sessionId':'CUSTOM_SESSION_ID','token':'" + token1
+ token1 + "','role':'MODERATOR','serverData':'SERVER_DATA','record':true,'createdAt':" + "','serverData':'SERVER_DATA','role':'MODERATOR'," + kurentoOpts + ",'createdAt':"
+ createdAt1 + createdAt1 + "}",
+ ",'activeAt':null,'platform':null,'location':null,'clientData':null,'publishers':null,'subscribers':null}"); new String[0]));
/** POST /openvidu/api/signal (NOT ACTIVE SESSION) **/ /** POST /openvidu/api/signal (NOT ACTIVE SESSION) **/
body = "{}"; body = "{}";
@ -2864,14 +2910,14 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
**/ **/
body = "{'customSessionId': 'CUSTOM_SESSION_ID'}"; body = "{'customSessionId': 'CUSTOM_SESSION_ID'}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions", body, HttpStatus.SC_OK); restClient.rest(HttpMethod.POST, "/openvidu/api/sessions", body, HttpStatus.SC_OK);
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'SUBSCRIBER'}"; body = "{'type': 'WEBRTC', 'role': 'SUBSCRIBER'}";
res = restClient.rest(HttpMethod.POST, "/openvidu/api/tokens", body, HttpStatus.SC_OK, true, false, true, res = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
DEFAULT_JSON_TOKEN); HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_PENDING_CONNECTION);
final String tokenAConnectionId = res.get("connectionId").getAsString(); final String connectionIdA = res.get("id").getAsString();
final String tokenA = res.get("token").getAsString(); final String tokenA = res.get("token").getAsString();
res = restClient.rest(HttpMethod.POST, "/openvidu/api/tokens", body, HttpStatus.SC_OK, true, false, true, res = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection", body,
DEFAULT_JSON_TOKEN); HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_PENDING_CONNECTION);
final String tokenBConnectionId = res.get("connectionId").getAsString(); final String connectionIdB = res.get("connectionId").getAsString();
final String tokenB = res.get("token").getAsString(); final String tokenB = res.get("token").getAsString();
user.getDriver().findElement(By.id("one2one-btn")).click(); user.getDriver().findElement(By.id("one2one-btn")).click();
@ -2895,7 +2941,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Thread.sleep(1000); Thread.sleep(1000);
// Invalidate token // Invalidate token
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + tokenAConnectionId, restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/CUSTOM_SESSION_ID/connection/" + connectionIdA,
HttpStatus.SC_NO_CONTENT); HttpStatus.SC_NO_CONTENT);
// User should pop up invalid token // User should pop up invalid token
@ -2918,7 +2964,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
user.getEventManager().waitUntilEventReaches("connectionCreated", 1); user.getEventManager().waitUntilEventReaches("connectionCreated", 1);
// connectionId should be equal to the one brought by the token // connectionId should be equal to the one brought by the token
Assert.assertEquals("Wrong connectionId", tokenBConnectionId, Assert.assertEquals("Wrong connectionId", connectionIdB,
restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID", HttpStatus.SC_OK) restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/CUSTOM_SESSION_ID", HttpStatus.SC_OK)
.get("connections").getAsJsonObject().get("content").getAsJsonArray().get(0).getAsJsonObject() .get("connections").getAsJsonObject().get("content").getAsJsonArray().get(0).getAsJsonObject()
.get("connectionId").getAsString()); .get("connectionId").getAsString());
@ -3286,7 +3332,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Publish IP camera. Dummy URL because no user will subscribe to it [200] // Publish IP camera. Dummy URL because no user will subscribe to it [200]
String ipCamBody = "{'type':'IPCAM','rtspUri':'rtsp://dummyurl.com','adaptativeBitrate':true,'onlyPlayWithSubscribers':true,'networkCache':1000,'data':'MY_IP_CAMERA'}"; String ipCamBody = "{'type':'IPCAM','rtspUri':'rtsp://dummyurl.com','adaptativeBitrate':true,'onlyPlayWithSubscribers':true,'networkCache':1000,'data':'MY_IP_CAMERA'}";
JsonObject response = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/IP_CAM_SESSION/connection", JsonObject response = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/IP_CAM_SESSION/connection",
ipCamBody, HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_CONNECTION); ipCamBody, HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_IPCAM_CONNECTION);
CustomWebhook.waitForEvent("sessionCreated", 1); CustomWebhook.waitForEvent("sessionCreated", 1);
CustomWebhook.waitForEvent("participantJoined", 1); CustomWebhook.waitForEvent("participantJoined", 1);
@ -3294,7 +3340,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Assert.assertEquals("Wrong serverData property", "MY_IP_CAMERA", response.get("serverData").getAsString()); Assert.assertEquals("Wrong serverData property", "MY_IP_CAMERA", response.get("serverData").getAsString());
Assert.assertEquals("Wrong platform property", "IPCAM", response.get("platform").getAsString()); Assert.assertEquals("Wrong platform property", "IPCAM", response.get("platform").getAsString());
Assert.assertEquals("Wrong role property", "PUBLISHER", response.get("role").getAsString()); Assert.assertEquals("Wrong role property", JsonNull.INSTANCE, response.get("role"));
Assert.assertEquals("Wrong type property", "IPCAM", response.get("type").getAsString()); Assert.assertEquals("Wrong type property", "IPCAM", response.get("type").getAsString());
Assert.assertEquals("Wrong number of publishers in IPCAM participant", 1, Assert.assertEquals("Wrong number of publishers in IPCAM participant", 1,
@ -3384,7 +3430,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
+ "','adaptativeBitrate':true,'onlyPlayWithSubscribers':true,'networkCache':1000,'data':'MY_IP_CAMERA'}"; + "','adaptativeBitrate':true,'onlyPlayWithSubscribers':true,'networkCache':1000,'data':'MY_IP_CAMERA'}";
restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/TestSession/connection", ipCamBody, restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/TestSession/connection", ipCamBody,
HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_CONNECTION); HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_IPCAM_CONNECTION);
user.getEventManager().waitUntilEventReaches("connectionCreated", 2); user.getEventManager().waitUntilEventReaches("connectionCreated", 2);
user.getEventManager().waitUntilEventReaches("streamCreated", 2); user.getEventManager().waitUntilEventReaches("streamCreated", 2);
@ -3411,7 +3457,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
// Publish again the IPCAM // Publish again the IPCAM
response = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/TestSession/connection", ipCamBody, response = restClient.rest(HttpMethod.POST, "/openvidu/api/sessions/TestSession/connection", ipCamBody,
HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_CONNECTION); HttpStatus.SC_OK, true, false, true, DEFAULT_JSON_IPCAM_CONNECTION);
user.getEventManager().waitUntilEventReaches("connectionCreated", 3); user.getEventManager().waitUntilEventReaches("connectionCreated", 3);
user.getEventManager().waitUntilEventReaches("streamCreated", 3); user.getEventManager().waitUntilEventReaches("streamCreated", 3);
user.getEventManager().waitUntilEventReaches("streamPlaying", 3); user.getEventManager().waitUntilEventReaches("streamPlaying", 3);
@ -3523,9 +3569,8 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
checkNodeFetchChanged(true, true); checkNodeFetchChanged(true, true);
checkNodeFetchChanged(true, false); checkNodeFetchChanged(true, false);
Token token = session.createToken(); Connection connection = session.createConnection();
// TODO: when using createConnection this below should be false! Assert.assertFalse("Java fetch should be false", session.fetch());
Assert.assertTrue("Java fetch should be true", session.fetch());
Assert.assertFalse("Java fetch should be false", OV.fetch()); Assert.assertFalse("Java fetch should be false", OV.fetch());
checkNodeFetchChanged(true, true); checkNodeFetchChanged(true, true);
checkNodeFetchChanged(true, false); checkNodeFetchChanged(true, false);
@ -3550,7 +3595,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
Thread.sleep(1000); Thread.sleep(1000);
WebElement tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input")); WebElement tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input"));
tokeInput.clear(); tokeInput.clear();
tokeInput.sendKeys(token.getToken()); tokeInput.sendKeys(connection.getToken());
user.getDriver().findElement(By.id("save-btn")).click(); user.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(1000); Thread.sleep(1000);
user.getDriver().findElement(By.className("join-btn")).click(); user.getDriver().findElement(By.className("join-btn")).click();