OpenVidu SDKs: update with improved reset process

pull/553/head
pabloFuente 2020-10-16 13:45:15 +02:00
parent 77a63a8e54
commit b4c1df1878
8 changed files with 375 additions and 240 deletions

View File

@ -18,8 +18,10 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
@ -42,50 +44,7 @@ public class Connection {
protected List<String> subscribers = new ArrayList<>(); protected List<String> subscribers = new ArrayList<>();
protected Connection(JsonObject json) { protected Connection(JsonObject json) {
// These properties may be null this.resetWithJson(json);
if (!json.get("publishers").isJsonNull()) {
JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray();
jsonArrayPublishers.forEach(publisher -> {
JsonObject pubJson = publisher.getAsJsonObject();
JsonObject mediaOptions = pubJson.get("mediaOptions").getAsJsonObject();
Publisher pub = new Publisher(pubJson.get("streamId").getAsString(),
pubJson.get("createdAt").getAsLong(), mediaOptions.get("hasAudio").getAsBoolean(),
mediaOptions.get("hasVideo").getAsBoolean(), mediaOptions.get("audioActive"),
mediaOptions.get("videoActive"), mediaOptions.get("frameRate"), mediaOptions.get("typeOfVideo"),
mediaOptions.get("videoDimensions"));
this.publishers.put(pub.getStreamId(), pub);
});
}
if (!json.get("subscribers").isJsonNull()) {
JsonArray jsonArraySubscribers = json.get("subscribers").getAsJsonArray();
jsonArraySubscribers.forEach(subscriber -> {
this.subscribers.add((subscriber.getAsJsonObject()).get("streamId").getAsString());
});
}
if (!json.get("createdAt").isJsonNull()) {
this.createdAt = json.get("createdAt").getAsLong();
}
if (!json.get("location").isJsonNull()) {
this.location = json.get("location").getAsString();
}
if (!json.get("platform").isJsonNull()) {
this.platform = json.get("platform").getAsString();
}
if (!json.get("clientData").isJsonNull()) {
this.clientData = json.get("clientData").getAsString();
}
// These properties won't ever be null
this.connectionId = json.get("connectionId").getAsString();
this.status = json.get("status").getAsString();
String token = json.has("token") ? json.get("token").getAsString() : null;
OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString());
String data = json.get("serverData").getAsString();
Boolean record = json.get("record").getAsBoolean();
TokenOptions tokenOptions = new TokenOptions(role, data, record, null);
this.token = new Token(token, this.connectionId, tokenOptions);
} }
/** /**
@ -248,4 +207,81 @@ public class Connection {
this.subscribers = subscribers; this.subscribers = subscribers;
} }
protected Connection resetWithJson(JsonObject json) {
if (!json.get("publishers").isJsonNull()) {
JsonArray jsonArrayPublishers = json.get("publishers").getAsJsonArray();
// 1. Set to store fetched publishers and later remove closed ones
Set<String> fetchedPublisherIds = new HashSet<>();
jsonArrayPublishers.forEach(publisherJsonElement -> {
JsonObject publisherJson = publisherJsonElement.getAsJsonObject();
Publisher publisherObj = new Publisher(publisherJson);
String id = publisherObj.getStreamId();
fetchedPublisherIds.add(id);
// 2. Update existing Publisher
this.publishers.computeIfPresent(id, (pId, p) -> {
p = p.resetWithJson(publisherJson);
return p;
});
// 3. Add new Publisher
this.publishers.computeIfAbsent(id, pId -> {
return publisherObj;
});
});
// 4. Remove closed connections from local collection
this.publishers.entrySet().removeIf(entry -> !fetchedPublisherIds.contains(entry.getValue().getStreamId()));
}
if (!json.get("subscribers").isJsonNull()) {
JsonArray jsonArraySubscribers = json.get("subscribers").getAsJsonArray();
// 1. Array to store fetched Subscribers and later remove closed ones
Set<String> fetchedSubscriberIds = new HashSet<>();
jsonArraySubscribers.forEach(subscriber -> {
String sub = subscriber.getAsJsonObject().get("streamId").getAsString();
fetchedSubscriberIds.add(sub);
if (!this.subscribers.contains(sub)) {
// 2. Add new Subscriber
this.subscribers.add(sub);
}
});
// 3. Remove closed Subscribers from local collection
this.subscribers.removeIf(subId -> !fetchedSubscriberIds.contains(subId));
}
if (!json.get("createdAt").isJsonNull()) {
this.createdAt = json.get("createdAt").getAsLong();
}
if (!json.get("location").isJsonNull()) {
this.location = json.get("location").getAsString();
}
if (!json.get("platform").isJsonNull()) {
this.platform = json.get("platform").getAsString();
}
if (!json.get("clientData").isJsonNull()) {
this.clientData = json.get("clientData").getAsString();
}
// These properties won't ever be null
this.connectionId = json.get("connectionId").getAsString();
this.status = json.get("status").getAsString();
String token = json.has("token") ? json.get("token").getAsString() : null;
OpenViduRole role = OpenViduRole.valueOf(json.get("role").getAsString());
String data = json.get("serverData").getAsString();
Boolean record = json.get("record").getAsBoolean();
TokenOptions tokenOptions = new TokenOptions(role, data, record, null);
this.token = new Token(token, this.connectionId, tokenOptions);
return this;
}
} }

View File

@ -31,7 +31,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
@ -549,44 +548,55 @@ public class OpenVidu {
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)) {
JsonObject jsonSessions = httpResponseToJson(response); JsonObject jsonSessions = httpResponseToJson(response);
JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray(); JsonArray jsonArraySessions = jsonSessions.get("content").getAsJsonArray();
// Set to store fetched sessionIds and later remove closed sessions
Set<String> fetchedSessionIds = new HashSet<>();
// Boolean to store if any Session has changed // Boolean to store if any Session has changed
final boolean[] hasChanged = { false }; final boolean[] hasChanged = { false };
jsonArraySessions.forEach(session -> {
String sessionId = (session.getAsJsonObject()).get("sessionId").getAsString(); // 1. Set to store fetched sessionIds and later remove closed ones
fetchedSessionIds.add(sessionId); Set<String> fetchedSessionIds = new HashSet<>();
this.activeSessions.computeIfPresent(sessionId, (sId, s) -> { jsonArraySessions.forEach(sessionJsonElement -> {
JsonObject sessionJson = sessionJsonElement.getAsJsonObject();
final Session sessionObj = new Session(this, sessionJson);
String id = sessionObj.getSessionId();
fetchedSessionIds.add(id);
// 2. Update existing Session
this.activeSessions.computeIfPresent(id, (sId, s) -> {
String beforeJSON = s.toJson(); String beforeJSON = s.toJson();
s = s.resetSessionWithJson(session.getAsJsonObject()); s = s.resetWithJson(sessionJson);
String afterJSON = s.toJson(); String afterJSON = s.toJson();
boolean changed = !beforeJSON.equals(afterJSON); boolean changed = !beforeJSON.equals(afterJSON);
hasChanged[0] = hasChanged[0] || changed; hasChanged[0] = hasChanged[0] || changed;
log.info("Available session '{}' info fetched. Any change: {}", sessionId, changed); log.info("Available session '{}' info fetched. Any change: {}", id, changed);
return s; return s;
}); });
this.activeSessions.computeIfAbsent(sessionId, sId -> {
log.info("New session '{}' fetched", sessionId); // 3. Add new Session
this.activeSessions.computeIfAbsent(id, sId -> {
log.info("New session '{}' fetched", id);
hasChanged[0] = true; hasChanged[0] = true;
return new Session(this, session.getAsJsonObject()); return sessionObj;
}); });
}); });
// Remove closed sessions from activeSessions map // 4. Remove closed sessions from local collection
this.activeSessions = this.activeSessions.entrySet().stream().filter(entry -> { this.activeSessions.entrySet().removeIf(entry -> {
if (fetchedSessionIds.contains(entry.getKey())) { if (fetchedSessionIds.contains(entry.getKey())) {
return true; return false;
} else { } else {
log.info("Removing closed session {}", entry.getKey()); log.info("Removing closed session {}", entry.getKey());
hasChanged[0] = true; hasChanged[0] = true;
return false; return true;
} }
}).collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); });
log.info("Active sessions info fetched: {}", this.activeSessions.keySet()); log.info("Active sessions info fetched: {}", this.activeSessions.keySet());
return hasChanged[0]; return hasChanged[0];
} else { } else {
throw new OpenViduHttpException(statusCode); throw new OpenViduHttpException(statusCode);
} }

View File

@ -17,16 +17,15 @@
package io.openvidu.java.client; package io.openvidu.java.client;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
/** /**
* See {@link io.openvidu.java.client.Connection#getPublishers()}. * See {@link io.openvidu.java.client.Connection#getPublishers()}.
* *
* <br> * <br>
* This is a backend representation of a published media stream (see * This is a backend representation of a published media stream (see <a href=
* <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target="_blank"> OpenVidu * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* Browser Stream class</a>). * target="_blank"> OpenVidu Browser Stream class</a>).
*/ */
public class Publisher { public class Publisher {
@ -40,36 +39,18 @@ public class Publisher {
private String typeOfVideo; private String typeOfVideo;
private String videoDimensions; private String videoDimensions;
protected Publisher(String streamId, long createdAt, boolean hasAudio, boolean hasVideo, JsonElement audioActive, protected Publisher(JsonObject json) {
JsonElement videoActive, JsonElement frameRate, JsonElement typeOfVideo, JsonElement videoDimensions) { this.resetWithJson(json);
this.streamId = streamId;
this.createdAt = createdAt;
this.hasAudio = hasAudio;
this.hasVideo = hasVideo;
if (audioActive != null && !audioActive.isJsonNull()) {
this.audioActive = audioActive.getAsBoolean();
}
if (videoActive != null && !videoActive.isJsonNull()) {
this.videoActive = videoActive.getAsBoolean();
}
if (frameRate != null && !frameRate.isJsonNull()) {
this.frameRate = frameRate.getAsInt();
}
if (typeOfVideo != null && !typeOfVideo.isJsonNull()) {
this.typeOfVideo = typeOfVideo.getAsString();
}
if (videoDimensions != null && !videoDimensions.isJsonNull()) {
this.videoDimensions = videoDimensions.getAsString();
}
} }
/** /**
* Returns the unique identifier of the * Returns the unique identifier of the <a href=
* <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* "_blank">Stream</a> associated to this Publisher. Each Publisher is paired * target= "_blank">Stream</a> associated to this Publisher. Each Publisher is
* with only one Stream, so you can identify each Publisher by its * paired with only one Stream, so you can identify each Publisher by its
* <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html#streamid" target= * <a href=
* "_blank"><code>Stream.streamId</code></a> * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html#streamid"
* target= "_blank"><code>Stream.streamId</code></a>
*/ */
public String getStreamId() { public String getStreamId() {
return streamId; return streamId;
@ -84,56 +65,70 @@ public class Publisher {
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public boolean hasVideo() { public boolean hasVideo() {
return this.hasVideo; return this.hasVideo;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public boolean hasAudio() { public boolean hasAudio() {
return this.hasAudio; return this.hasAudio;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public Boolean isAudioActive() { public Boolean isAudioActive() {
return this.audioActive; return this.audioActive;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public Boolean isVideoActive() { public Boolean isVideoActive() {
return this.videoActive; return this.videoActive;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public Integer getFrameRate() { public Integer getFrameRate() {
return this.frameRate; return this.frameRate;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public String getTypeOfVideo() { public String getTypeOfVideo() {
return this.typeOfVideo; return this.typeOfVideo;
} }
/** /**
* See properties of <a href="https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html" target= * See properties of <a href=
* "_blank">Stream</a> object in OpenVidu Browser library to find out more * "https://docs.openvidu.io/en/stable/api/openvidu-browser/classes/stream.html"
* target= "_blank">Stream</a> object in OpenVidu Browser library to find out
* more
*/ */
public String getVideoDimensions() { public String getVideoDimensions() {
return this.videoDimensions; return this.videoDimensions;
@ -152,4 +147,32 @@ public class Publisher {
return json; return json;
} }
protected Publisher resetWithJson(JsonObject json) {
this.streamId = json.get("streamId").getAsString();
this.createdAt = json.get("createdAt").getAsLong();
if (json.has("mediaOptions") && !json.get("mediaOptions").isJsonNull()) {
JsonObject mediaOptions = json.get("mediaOptions").getAsJsonObject();
this.hasAudio = mediaOptions.get("hasAudio").getAsBoolean();
this.hasVideo = mediaOptions.get("hasVideo").getAsBoolean();
if (mediaOptions.has("audioActive") && !mediaOptions.get("audioActive").isJsonNull()) {
this.audioActive = mediaOptions.get("audioActive").getAsBoolean();
}
if (mediaOptions.has("videoActive") && !mediaOptions.get("videoActive").isJsonNull()) {
this.videoActive = mediaOptions.get("videoActive").getAsBoolean();
}
if (mediaOptions.has("frameRate") && !mediaOptions.get("frameRate").isJsonNull()) {
this.frameRate = mediaOptions.get("frameRate").getAsInt();
}
if (mediaOptions.has("typeOfVideo") && !mediaOptions.get("typeOfVideo").isJsonNull()) {
this.typeOfVideo = mediaOptions.get("typeOfVideo").getAsString();
}
if (mediaOptions.has("videoDimensions") && !mediaOptions.get("videoDimensions").isJsonNull()) {
this.videoDimensions = mediaOptions.get("videoDimensions").getAsString();
}
}
return this;
}
} }

View File

@ -19,8 +19,10 @@ package io.openvidu.java.client;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -66,7 +68,7 @@ public class Session {
protected Session(OpenVidu openVidu, JsonObject json) { protected Session(OpenVidu openVidu, JsonObject json) {
this.openVidu = openVidu; this.openVidu = openVidu;
this.resetSessionWithJson(json); this.resetWithJson(json);
} }
/** /**
@ -282,7 +284,7 @@ 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)) {
this.resetSessionWithJson(httpResponseToJson(response)); this.resetWithJson(httpResponseToJson(response));
final String afterJSON = this.toJson(); final String afterJSON = this.toJson();
boolean hasChanged = !beforeJSON.equals(afterJSON); boolean hasChanged = !beforeJSON.equals(afterJSON);
log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged); log.info("Session info fetched for session '{}'. Any change: {}", this.sessionId, hasChanged);
@ -694,7 +696,7 @@ public class Session {
this.recording = recording; this.recording = recording;
} }
protected Session resetSessionWithJson(JsonObject json) { protected Session resetWithJson(JsonObject json) {
this.sessionId = json.get("sessionId").getAsString(); this.sessionId = json.get("sessionId").getAsString();
this.createdAt = json.get("createdAt").getAsLong(); this.createdAt = json.get("createdAt").getAsLong();
this.recording = json.get("recording").getAsBoolean(); this.recording = json.get("recording").getAsBoolean();
@ -708,18 +710,37 @@ public class Session {
if (json.has("defaultCustomLayout")) { if (json.has("defaultCustomLayout")) {
builder.defaultCustomLayout(json.get("defaultCustomLayout").getAsString()); builder.defaultCustomLayout(json.get("defaultCustomLayout").getAsString());
} }
if (this.properties != null && this.properties.customSessionId() != null) { if (json.has("customSessionId")) {
builder.customSessionId(this.properties.customSessionId());
} else if (json.has("customSessionId")) {
builder.customSessionId(json.get("customSessionId").getAsString()); builder.customSessionId(json.get("customSessionId").getAsString());
} }
this.properties = builder.build(); this.properties = builder.build();
JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray(); JsonArray jsonArrayConnections = (json.get("connections").getAsJsonObject()).get("content").getAsJsonArray();
this.connections.clear();
// 1. Set to store fetched connections and later remove closed ones
Set<String> fetchedConnectionIds = new HashSet<>();
jsonArrayConnections.forEach(connectionJsonElement -> { jsonArrayConnections.forEach(connectionJsonElement -> {
Connection connectionObj = new Connection(connectionJsonElement.getAsJsonObject());
this.connections.put(connectionObj.getConnectionId(), connectionObj); JsonObject connectionJson = connectionJsonElement.getAsJsonObject();
Connection connectionObj = new Connection(connectionJson);
String id = connectionObj.getConnectionId();
fetchedConnectionIds.add(id);
// 2. Update existing Connection
this.connections.computeIfPresent(id, (cId, c) -> {
c = c.resetWithJson(connectionJson);
return c;
});
// 3. Add new Connection
this.connections.computeIfAbsent(id, cId -> {
return connectionObj;
});
}); });
// 4. Remove closed connections from local collection
this.connections.entrySet()
.removeIf(entry -> !fetchedConnectionIds.contains(entry.getValue().getConnectionId()));
return this; return this;
} }

View File

@ -100,21 +100,13 @@ export class Connection {
* @hidden * @hidden
*/ */
constructor(json) { constructor(json) {
// These properties may be null this.resetWithJson(json);
if (json.publishers != null) { }
json.publishers.forEach(publisher => {
this.publishers.push(new Publisher(publisher)); /**
}); * @hidden
} */
if (json.subscribers != null) { resetWithJson(json): Connection {
json.subscribers.forEach(subscriber => {
this.subscribers.push(subscriber.streamId);
});
}
this.createdAt = json.createdAt;
this.location = json.location;
this.platform = json.platform;
this.clientData = json.clientData;
// These properties won't ever be null // These properties won't ever be null
this.connectionId = json.connectionId; this.connectionId = json.connectionId;
@ -123,6 +115,62 @@ export class Connection {
this.role = json.role; this.role = json.role;
this.serverData = json.serverData; this.serverData = json.serverData;
this.record = json.record; this.record = json.record;
// These properties may be null
if (json.publishers != null) {
// 1. Array to store fetched Publishers and later remove closed ones
const fetchedPublisherIds: string[] = [];
json.publishers.forEach(jsonPublisher => {
const publisherObj: Publisher = new Publisher(jsonPublisher);
fetchedPublisherIds.push(publisherObj.streamId);
let storedPublisher = this.publishers.find(c => c.streamId === publisherObj.streamId);
if (!!storedPublisher) {
// 2. Update existing Publisher
storedPublisher.resetWithJson(jsonPublisher);
} else {
// 3. Add new Publisher
this.publishers.push(publisherObj);
}
});
// 4. Remove closed Publishers from local collection
for (var i = this.publishers.length - 1; i >= 0; --i) {
if (!fetchedPublisherIds.includes(this.publishers[i].streamId)) {
this.publishers.splice(i, 1);
}
}
}
if (json.subscribers != null) {
// 1. Array to store fetched Subscribers and later remove closed ones
const fetchedSubscriberIds: string[] = [];
json.subscribers.forEach(jsonSubscriber => {
fetchedSubscriberIds.push(jsonSubscriber.streamId)
if (this.subscribers.indexOf(jsonSubscriber.streamId) === -1) {
// 2. Add new Subscriber
this.subscribers.push(jsonSubscriber.streamId);
}
});
// 3. Remove closed Subscribers from local collection
for (var i = this.subscribers.length - 1; i >= 0; --i) {
if (!fetchedSubscriberIds.includes(this.subscribers[i])) {
this.subscribers.splice(i, 1);
}
}
}
this.createdAt = json.createdAt;
this.location = json.location;
this.platform = json.platform;
this.clientData = json.clientData;
return this;
} }
/** /**

View File

@ -429,47 +429,44 @@ export class OpenVidu {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
// Array to store fetched sessionIds and later remove closed sessions
const fetchedSessionIds: string[] = [];
// Boolean to store if any Session has changed // Boolean to store if any Session has changed
let hasChanged = false; let hasChanged = false;
res.data.content.forEach(session => { // 1. Array to store fetched sessionIds and later remove closed ones
fetchedSessionIds.push(session.sessionId); const fetchedSessionIds: string[] = [];
let sessionIndex = -1; res.data.content.forEach(jsonSession => {
let storedSession = this.activeSessions.find((s, index) => {
if (s.sessionId === session.sessionId) { const fetchedSession: Session = new Session(this, jsonSession);
sessionIndex = index; fetchedSessionIds.push(fetchedSession.sessionId);
return true; let storedSession = this.activeSessions.find(s => s.sessionId === fetchedSession.sessionId);
} else {
return false;
}
});
if (!!storedSession) { if (!!storedSession) {
const fetchedSession: Session = new Session(this).resetSessionWithJson(session);
// 2. Update existing Session
const changed: boolean = !storedSession.equalTo(fetchedSession); const changed: boolean = !storedSession.equalTo(fetchedSession);
if (changed) { storedSession.resetWithJson(jsonSession);
storedSession = fetchedSession;
this.activeSessions[sessionIndex] = storedSession;
}
console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed); console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed);
hasChanged = hasChanged || changed; hasChanged = hasChanged || changed;
} else { } else {
this.activeSessions.push(new Session(this, session));
console.log("New session '" + session.sessionId + "' info fetched"); // 3. Add new Session
this.activeSessions.push(fetchedSession);
console.log("New session '" + fetchedSession.sessionId + "' info fetched");
hasChanged = true; hasChanged = true;
} }
}); });
// Remove closed sessions from activeSessions array
this.activeSessions = this.activeSessions.filter(session => { // 4. Remove closed sessions from local collection
if (fetchedSessionIds.includes(session.sessionId)) { for (var i = this.activeSessions.length - 1; i >= 0; --i) {
return true; let sessionId = this.activeSessions[i].sessionId;
} else { if (!fetchedSessionIds.includes(sessionId)) {
console.log("Removing closed session '" + session.sessionId + "'"); console.log("Removing closed session '" + sessionId + "'");
hasChanged = true; hasChanged = true;
return false; this.activeSessions.splice(i, 1);
} }
}); }
console.log('Active sessions info fetched: ', fetchedSessionIds); console.log('Active sessions info fetched: ', fetchedSessionIds);
resolve(hasChanged); resolve(hasChanged);
} else { } else {
@ -505,26 +502,9 @@ export class OpenVidu {
const addWebRtcStatsToConnections = (connection: Connection, connectionsExtendedInfo: any) => { const addWebRtcStatsToConnections = (connection: Connection, connectionsExtendedInfo: any) => {
const connectionExtended = connectionsExtendedInfo.find(c => c.connectionId === connection.connectionId); const connectionExtended = connectionsExtendedInfo.find(c => c.connectionId === connection.connectionId);
if (!!connectionExtended) { if (!!connectionExtended) {
const publisherArray = [];
connection.publishers.forEach(pub => { connection.publishers.forEach(pub => {
const publisherExtended = connectionExtended.publishers.find(p => p.streamId === pub.streamId); const publisherExtended = connectionExtended.publishers.find(p => p.streamId === pub.streamId);
const pubAux = {}; pub['webRtc'] = {
// Standard properties
pubAux['streamId'] = pub.streamId;
pubAux['createdAt'] = pub.createdAt;
const mediaOptions = {
audioActive: pub.audioActive,
videoActive: pub.videoActive,
hasAudio: pub.hasAudio,
hasVideo: pub.hasVideo,
typeOfVideo: pub.typeOfVideo,
frameRate: pub.frameRate,
videoDimensions: pub.videoDimensions
};
pubAux['mediaOptions'] = mediaOptions;
const newPublisher = new Publisher(pubAux);
// WebRtc properties
newPublisher['webRtc'] = {
kms: { kms: {
events: publisherExtended.events, events: publisherExtended.events,
localCandidate: publisherExtended.localCandidate, localCandidate: publisherExtended.localCandidate,
@ -536,11 +516,10 @@ export class OpenVidu {
remoteSdp: publisherExtended.remoteSdp remoteSdp: publisherExtended.remoteSdp
} }
}; };
newPublisher['localCandidatePair'] = parseRemoteCandidatePair(newPublisher['webRtc'].kms.remoteCandidate); pub['localCandidatePair'] = parseRemoteCandidatePair(pub['webRtc'].kms.remoteCandidate);
if (!!publisherExtended.serverStats) { if (!!publisherExtended.serverStats) {
newPublisher['webRtc'].kms.serverStats = publisherExtended.serverStats; pub['webRtc'].kms.serverStats = publisherExtended.serverStats;
} }
publisherArray.push(newPublisher);
}); });
const subscriberArray = []; const subscriberArray = [];
connection.subscribers.forEach(sub => { connection.subscribers.forEach(sub => {
@ -569,7 +548,6 @@ export class OpenVidu {
} }
subscriberArray.push(subAux); subscriberArray.push(subAux);
}); });
connection.publishers = publisherArray;
connection.subscribers = subscriberArray; connection.subscribers = subscriberArray;
} }
}; };
@ -601,68 +579,64 @@ export class OpenVidu {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
// Array to store fetched sessionIds and later remove closed sessions
const fetchedSessionIds: string[] = [];
// Global changes // Global changes
let globalChanges = false; let globalChanges = false;
// Collection of sessionIds telling whether each one of them has changed or not // Collection of sessionIds telling whether each one of them has changed or not
const sessionChanges: ObjMap<boolean> = {}; const sessionChanges: ObjMap<boolean> = {};
res.data.content.forEach(session => { // 1. Array to store fetched sessionIds and later remove closed ones
fetchedSessionIds.push(session.sessionId); const fetchedSessionIds: string[] = [];
let sessionIndex = -1; res.data.content.forEach(jsonSession => {
let storedSession = this.activeSessions.find((s, index) => {
if (s.sessionId === session.sessionId) {
sessionIndex = index;
return true;
} else {
return false;
}
});
if (!!storedSession) {
const fetchedSession: Session = new Session(this).resetSessionWithJson(session);
fetchedSession.activeConnections.forEach(connection => {
addWebRtcStatsToConnections(connection, session.connections.content);
});
const fetchedSession: Session = new Session(this, jsonSession);
fetchedSession.connections.forEach(connection => {
addWebRtcStatsToConnections(connection, jsonSession.connections.content);
});
fetchedSessionIds.push(fetchedSession.sessionId);
let storedSession = this.activeSessions.find(s => s.sessionId === fetchedSession.sessionId);
if (!!storedSession) {
// 2. Update existing Session
let changed = !storedSession.equalTo(fetchedSession); let changed = !storedSession.equalTo(fetchedSession);
if (!changed) { // Check if server webrtc information has changed in any Publisher object (Session.equalTo does not check Publisher.webRtc auxiliary object) if (!changed) { // Check if server webrtc information has changed in any Publisher object (Session.equalTo does not check Publisher.webRtc auxiliary object)
fetchedSession.activeConnections.forEach((connection, index1) => { fetchedSession.connections.forEach((connection, index1) => {
for (let index2 = 0; (index2 < connection['publishers'].length && !changed); index2++) { for (let index2 = 0; (index2 < connection['publishers'].length && !changed); index2++) {
changed = changed || JSON.stringify(connection['publishers'][index2]['webRtc']) !== JSON.stringify(storedSession.activeConnections[index1]['publishers'][index2]['webRtc']); changed = changed || JSON.stringify(connection['publishers'][index2]['webRtc']) !== JSON.stringify(storedSession.connections[index1]['publishers'][index2]['webRtc']);
} }
}); });
} }
if (changed) { storedSession.resetWithJson(jsonSession);
storedSession = fetchedSession; storedSession.connections.forEach(connection => {
this.activeSessions[sessionIndex] = storedSession; addWebRtcStatsToConnections(connection, jsonSession.connections.content);
} });
console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed); console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed);
sessionChanges[storedSession.sessionId] = changed; sessionChanges[storedSession.sessionId] = changed;
globalChanges = globalChanges || changed; globalChanges = globalChanges || changed;
} else { } else {
const newSession = new Session(this, session);
newSession.activeConnections.forEach(connection => { // 3. Add new Session
addWebRtcStatsToConnections(connection, session.connections.content); this.activeSessions.push(fetchedSession);
}); console.log("New session '" + fetchedSession.sessionId + "' info fetched");
this.activeSessions.push(newSession); sessionChanges[fetchedSession.sessionId] = true;
console.log("New session '" + session.sessionId + "' info fetched");
sessionChanges[session.sessionId] = true;
globalChanges = true; globalChanges = true;
} }
}); });
// Remove closed sessions from activeSessions array
this.activeSessions = this.activeSessions.filter(session => { // 4. Remove closed sessions from local collection
if (fetchedSessionIds.includes(session.sessionId)) { for (var i = this.activeSessions.length - 1; i >= 0; --i) {
return true; let sessionId = this.activeSessions[i].sessionId;
} else { if (!fetchedSessionIds.includes(sessionId)) {
console.log("Removing closed session '" + session.sessionId + "'"); console.log("Removing closed session '" + sessionId + "'");
sessionChanges[session.sessionId] = true; sessionChanges[sessionId] = true;
globalChanges = true; globalChanges = true;
return false; this.activeSessions.splice(i, 1);
} }
}); }
console.log('Active sessions info fetched: ', fetchedSessionIds); console.log('Active sessions info fetched: ', fetchedSessionIds);
resolve({ changes: globalChanges, sessionChanges }); resolve({ changes: globalChanges, sessionChanges });
} else { } else {

View File

@ -74,6 +74,13 @@ export class Publisher {
* @hidden * @hidden
*/ */
constructor(json) { constructor(json) {
this.resetWithJson(json);
}
/**
* @hidden
*/
resetWithJson(json): Publisher {
this.streamId = json.streamId; this.streamId = json.streamId;
this.createdAt = json.createdAt; this.createdAt = json.createdAt;
this.hasAudio = json.mediaOptions.hasAudio; this.hasAudio = json.mediaOptions.hasAudio;
@ -83,6 +90,7 @@ export class Publisher {
this.frameRate = json.mediaOptions.frameRate; this.frameRate = json.mediaOptions.frameRate;
this.typeOfVideo = json.mediaOptions.typeOfVideo; this.typeOfVideo = json.mediaOptions.typeOfVideo;
this.videoDimensions = json.mediaOptions.videoDimensions; this.videoDimensions = json.mediaOptions.videoDimensions;
return this;
} }
/** /**

View File

@ -82,7 +82,7 @@ export class Session {
// Defined parameter // Defined parameter
if (!!propertiesOrJson.sessionId) { if (!!propertiesOrJson.sessionId) {
// Parameter is a JSON representation of Session ('sessionId' property always defined) // Parameter is a JSON representation of Session ('sessionId' property always defined)
this.resetSessionWithJson(propertiesOrJson); this.resetWithJson(propertiesOrJson);
} else { } else {
// Parameter is a SessionProperties object // Parameter is a SessionProperties object
this.properties = propertiesOrJson; this.properties = propertiesOrJson;
@ -224,7 +224,7 @@ export class Session {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
// SUCCESS response from openvidu-server // SUCCESS response from openvidu-server
this.resetSessionWithJson(res.data); this.resetWithJson(res.data);
const afterJSON: string = JSON.stringify(this, this.removeCircularOpenViduReference); const afterJSON: string = JSON.stringify(this, this.removeCircularOpenViduReference);
const hasChanged: boolean = !(beforeJSON === afterJSON); const hasChanged: boolean = !(beforeJSON === afterJSON);
console.log("Session info fetched for session '" + this.sessionId + "'. Any change: " + hasChanged); console.log("Session info fetched for session '" + this.sessionId + "'. Any change: " + hasChanged);
@ -488,42 +488,57 @@ export class Session {
/** /**
* @hidden * @hidden
*/ */
public resetSessionWithJson(json): Session { public resetWithJson(json): Session {
this.sessionId = json.sessionId; this.sessionId = json.sessionId;
this.createdAt = json.createdAt; this.createdAt = json.createdAt;
this.recording = json.recording; this.recording = json.recording;
let customSessionId: string;
let defaultCustomLayout: string;
if (!!this.properties) {
customSessionId = this.properties.customSessionId;
defaultCustomLayout = !!json.defaultCustomLayout ? json.defaultCustomLayout : this.properties.defaultCustomLayout;
}
this.properties = { this.properties = {
customSessionId: json.customSessionId,
mediaMode: json.mediaMode, mediaMode: json.mediaMode,
recordingMode: json.recordingMode, recordingMode: json.recordingMode,
defaultOutputMode: json.defaultOutputMode, defaultOutputMode: json.defaultOutputMode,
defaultRecordingLayout: json.defaultRecordingLayout defaultRecordingLayout: json.defaultRecordingLayout,
defaultCustomLayout: json.defaultCustomLayout
}; };
if (!!customSessionId) { if (json.defaultRecordingLayout == null) {
this.properties.customSessionId = customSessionId; delete this.properties.defaultRecordingLayout;
} else if (!!json.customSessionId) {
this.properties.customSessionId = json.customSessionId;
} }
if (!!defaultCustomLayout) { if (json.customSessionId == null) {
this.properties.defaultCustomLayout = defaultCustomLayout; delete this.properties.customSessionId;
}
if (json.defaultCustomLayout == null) {
delete this.properties.defaultCustomLayout;
} }
this.connections = []; // 1. Array to store fetched connections and later remove closed ones
this.activeConnections = []; const fetchedConnectionIds: string[] = [];
json.connections.content.forEach(jsonConnection => { json.connections.content.forEach(jsonConnection => {
const con = new Connection(jsonConnection);
this.connections.push(con); const connectionObj: Connection = new Connection(jsonConnection);
fetchedConnectionIds.push(connectionObj.connectionId);
let storedConnection = this.connections.find(c => c.connectionId === connectionObj.connectionId);
if (!!storedConnection) {
// 2. Update existing Connection
storedConnection.resetWithJson(jsonConnection);
} else {
// 3. Add new Connection
this.connections.push(connectionObj);
}
}); });
// 4. Remove closed sessions from local collection
for (var i = this.connections.length - 1; i >= 0; --i) {
if (!fetchedConnectionIds.includes(this.connections[i].connectionId)) {
this.connections.splice(i, 1);
}
}
// Order connections by time of creation // Order connections by time of creation
this.connections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0)); this.connections.sort((c1, c2) => (c1.createdAt > c2.createdAt) ? 1 : ((c2.createdAt > c1.createdAt) ? -1 : 0));
// Populate activeConnections array // Populate activeConnections array
this.updateActiveConnectionsArray(); this.updateActiveConnectionsArray();
return this; return this;
} }