openvidu-node-client: equalTo mehtods and OpenVidu.fetchWebRtc

pull/121/head
pabloFuente 2018-09-19 15:36:26 +02:00
parent 5039f5e00c
commit 1d1f9d0457
4 changed files with 260 additions and 10 deletions

View File

@ -92,4 +92,36 @@ export class Connection {
this.publishers = publishers; this.publishers = publishers;
this.subscribers = subscribers; this.subscribers = subscribers;
} }
/**
* @hidden
*/
equalTo(other: Connection): boolean {
let equals: boolean = (
this.connectionId === other.connectionId &&
this.createdAt === other.createdAt &&
this.role === other.role &&
this.token === other.token &&
this.location === other.location &&
this.platform === other.platform &&
this.serverData === other.serverData &&
this.clientData === other.clientData &&
this.subscribers.length === other.subscribers.length &&
this.publishers.length === other.publishers.length);
if (equals) {
equals = JSON.stringify(this.subscribers) === JSON.stringify(other.subscribers);
if (equals) {
let i = 0;
while (equals && i < this.publishers.length) {
equals = this.publishers[i].equalTo(other.publishers[i]);
i++;
}
return equals;
} else {
return false;
}
} else {
return false;
}
}
} }

View File

@ -15,12 +15,13 @@
* *
*/ */
import { Session } from './Session'; import axios from 'axios';
import { SessionProperties } from './SessionProperties'; import { Connection } from './Connection';
import { Recording } from './Recording'; import { Recording } from './Recording';
import { RecordingProperties } from './RecordingProperties'; import { RecordingProperties } from './RecordingProperties';
import { Session } from './Session';
import { SessionProperties } from './SessionProperties';
import axios from 'axios';
export class OpenVidu { export class OpenVidu {
@ -415,12 +416,22 @@ export class OpenVidu {
res.data.content.forEach(session => { res.data.content.forEach(session => {
fetchedSessionIds.push(session.sessionId); fetchedSessionIds.push(session.sessionId);
let storedSession = this.activeSessions.find(s => s.sessionId === session.sessionId); let sessionIndex = -1;
let storedSession = this.activeSessions.find((s, index) => {
if (s.sessionId === session.sessionId) {
sessionIndex = index;
return true;
} else {
return false;
}
});
if (!!storedSession) { if (!!storedSession) {
const beforeJSON: string = JSON.stringify(storedSession); const fetchedSession: Session = new Session().resetSessionWithJson(session);
storedSession = storedSession.resetSessionWithJson(session); const changed: boolean = !storedSession.equalTo(fetchedSession);
const afterJSON: string = JSON.stringify(storedSession); if (changed) {
const changed: boolean = !(beforeJSON === afterJSON); 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 {
@ -462,6 +473,164 @@ export class OpenVidu {
}); });
} }
/**
* @hidden
*/
fetchWebRtc(): Promise<boolean> {
// tslint:disable:no-string-literal
const addWebRtcStatsToConnections = (connection: Connection, connectionsExtendedInfo: any) => {
const connectionExtended = connectionsExtendedInfo.find(c => c.connectionId === connection.connectionId);
if (!!connectionExtended) {
connection['publishersWebRtc'] = [];
connection.publishers.forEach(pub => {
const publisherExtended = connectionExtended.publishers.find(p => p.streamId === pub.streamId);
const pubAux = {};
// Standard properties
pubAux['streamId'] = pub.streamId;
pubAux['createdAt'] = pub.createdAt;
pubAux['audioActive'] = pub.audioActive;
pubAux['videoActive'] = pub.videoActive;
pubAux['hasAudio'] = pub.hasAudio;
pubAux['hasVideo'] = pub.hasVideo;
pubAux['typeOfVideo'] = pub.typeOfVideo;
pubAux['frameRate'] = pub.frameRate;
pubAux['videoDimensions'] = pub.videoDimensions;
// WebRtc properties
pubAux['webRtc'] = {
kms: {
events: publisherExtended.events,
localCandidate: publisherExtended.localCandidate,
remoteCandidate: publisherExtended.remoteCandidate,
receivedCandidates: publisherExtended.receivedCandidates,
webrtcTagName: publisherExtended.webrtcTagName
}
};
if (!!publisherExtended.serverStats) {
pubAux['webRtc'].kms.serverStats = publisherExtended.serverStats;
}
connection['publishersWebRtc'].push(pubAux);
});
connection['subscribersWebRtc'] = [];
connection.subscribers.forEach(sub => {
const subscriberExtended = connectionExtended.subscribers.find(s => s.streamId === sub);
const subAux = {};
// Standard properties
subAux['streamId'] = sub;
subAux['publisher'] = subscriberExtended.publisher;
// WebRtc properties
subAux['createdAt'] = subscriberExtended.createdAt;
subAux['webRtc'] = {
kms: {
events: subscriberExtended.events,
localCandidate: subscriberExtended.localCandidate,
remoteCandidate: subscriberExtended.remoteCandidate,
receivedCandidates: subscriberExtended.receivedCandidates,
webrtcTagName: subscriberExtended.webrtcTagName
}
};
if (!!subscriberExtended.serverStats) {
subAux['webRtc'].kms.serverStats = subscriberExtended.serverStats;
}
connection['subscribersWebRtc'].push(subAux);
});
}
};
return new Promise<boolean>((resolve, reject) => {
axios.get(
'https://' + OpenVidu.hostname + ':' + OpenVidu.port + OpenVidu.API_SESSIONS + '?webRtcStats=true',
{
headers: {
Authorization: OpenVidu.basicAuth
}
}
)
.then(res => {
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
let hasChanged = false;
res.data.content.forEach(session => {
fetchedSessionIds.push(session.sessionId);
let sessionIndex = -1;
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().resetSessionWithJson(session);
let changed = !storedSession.equalTo(fetchedSession);
fetchedSession.activeConnections.forEach((connection, index1) => {
addWebRtcStatsToConnections(connection, session.connections.content);
if (!changed) { // Check if server information has changed in any Publisher/Subscriber
for (let index2 = 0; (index2 < connection['publishersWebRtc'].length && !changed); index2++) {
changed = changed || JSON.stringify(connection['publishersWebRtc'][index2]['webRtc']) !== JSON.stringify(storedSession.activeConnections[index1]['publishersWebRtc'][index2]['webRtc']);
}
if (!changed) {
for (let index2 = 0; (index2 < connection['subscribersWebRtc'].length && !changed); index2++) {
changed = changed || JSON.stringify(connection['subscribersWebRtc'][index2]['webRtc']) !== JSON.stringify(storedSession.activeConnections[index1]['subscribersWebRtc'][index2]['webRtc']);
}
}
}
});
if (changed) {
storedSession = fetchedSession;
this.activeSessions[sessionIndex] = storedSession;
}
console.log("Available session '" + storedSession.sessionId + "' info fetched. Any change: " + changed);
hasChanged = hasChanged || changed;
} else {
const newSession = new Session(session);
newSession.activeConnections.forEach(connection => {
addWebRtcStatsToConnections(connection, session.connections.content);
});
this.activeSessions.push(newSession);
console.log("New session '" + session.sessionId + "' info fetched");
hasChanged = true;
}
});
// Remove closed sessions from activeSessions array
this.activeSessions = this.activeSessions.filter(session => {
if (fetchedSessionIds.includes(session.sessionId)) {
return true;
} else {
console.log("Removing closed session '" + session.sessionId + "'");
hasChanged = true;
return false;
}
});
console.log('Active sessions info fetched: ', fetchedSessionIds);
resolve(hasChanged);
} else {
// ERROR response from openvidu-server. Resolve HTTP status
reject(new Error(res.status.toString()));
}
}).catch(error => {
if (error.response) {
// The request was made and the server responded with a status code (not 2xx)
reject(new Error(error.response.status.toString()));
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error', error.message);
}
});
});
}
// tslint:enable:no-string-literal
private getBasicAuth(secret: string): string { private getBasicAuth(secret: string): string {
return 'Basic ' + this.Buffer('OPENVIDUAPP:' + secret).toString('base64'); return 'Basic ' + this.Buffer('OPENVIDUAPP:' + secret).toString('base64');
} }

View File

@ -15,7 +15,6 @@
* *
*/ */
import { OpenViduRole } from './OpenViduRole';
/** /**
* See [[Connection.publishers]] * See [[Connection.publishers]]
@ -31,6 +30,11 @@ export class Publisher {
*/ */
streamId: string; streamId: string;
/**
* Timestamp when this Publisher started publishing, in UTC milliseconds (ms since Jan 1, 1970, 00:00:00 UTC)
*/
createdAt: number;
/** /**
* See properties of [Stream](/api/openvidu-browser/classes/stream.html) object in OpenVidu Browser library to find out more * See properties of [Stream](/api/openvidu-browser/classes/stream.html) object in OpenVidu Browser library to find out more
*/ */
@ -66,8 +70,12 @@ export class Publisher {
*/ */
videoDimensions: string; videoDimensions: string;
/**
* @hidden
*/
constructor(json) { constructor(json) {
this.streamId = json.streamId; this.streamId = json.streamId;
this.createdAt = json.createdAt;
this.hasAudio = json.mediaOptions.hasAudio; this.hasAudio = json.mediaOptions.hasAudio;
this.hasVideo = json.mediaOptions.hasVideo; this.hasVideo = json.mediaOptions.hasVideo;
this.audioActive = json.mediaOptions.audioActive; this.audioActive = json.mediaOptions.audioActive;
@ -77,4 +85,21 @@ export class Publisher {
this.videoDimensions = json.mediaOptions.videoDimensions; this.videoDimensions = json.mediaOptions.videoDimensions;
} }
/**
* @hidden
*/
equalTo(other: Publisher): boolean {
return (
this.streamId === other.streamId &&
this.createdAt === other.createdAt &&
this.hasAudio === other.hasAudio &&
this.hasVideo === other.hasVideo &&
this.audioActive === other.audioActive &&
this.videoActive === other.videoActive &&
this.frameRate === other.frameRate &&
this.typeOfVideo === other.typeOfVideo &&
this.videoDimensions === other.videoDimensions
);
}
} }

View File

@ -15,6 +15,7 @@
* *
*/ */
import axios from 'axios';
import { Connection } from './Connection'; import { Connection } from './Connection';
import { MediaMode } from './MediaMode'; import { MediaMode } from './MediaMode';
import { OpenVidu } from './OpenVidu'; import { OpenVidu } from './OpenVidu';
@ -25,7 +26,6 @@ import { RecordingMode } from './RecordingMode';
import { SessionProperties } from './SessionProperties'; import { SessionProperties } from './SessionProperties';
import { TokenOptions } from './TokenOptions'; import { TokenOptions } from './TokenOptions';
import axios from 'axios';
export class Session { export class Session {
@ -429,6 +429,7 @@ export class Session {
*/ */
public resetSessionWithJson(json): Session { public resetSessionWithJson(json): Session {
this.sessionId = json.sessionId; this.sessionId = json.sessionId;
this.createdAt = json.createdAt;
this.recording = json.recording; this.recording = json.recording;
let customSessionId: string; let customSessionId: string;
let defaultCustomLayout: string; let defaultCustomLayout: string;
@ -474,4 +475,27 @@ export class Session {
return this; return this;
} }
/**
* @hidden
*/
equalTo(other: Session): boolean {
let equals: boolean = (
this.sessionId === other.sessionId &&
this.createdAt === other.createdAt &&
this.recording === other.recording &&
this.activeConnections.length === other.activeConnections.length &&
JSON.stringify(this.properties) === JSON.stringify(other.properties)
);
if (equals) {
let i = 0;
while (equals && i < this.activeConnections.length) {
equals = this.activeConnections[i].equalTo(other.activeConnections[i]);
i++;
}
return equals;
} else {
return false;
}
}
} }