openvidu-browser: onForciblyReconnectSubscriber

pull/648/head
pabloFuente 2021-06-30 15:33:05 +02:00
parent ffcb56cc0d
commit 00d64ded9b
4 changed files with 155 additions and 88 deletions

View File

@ -117,12 +117,14 @@ export class OpenVidu {
* @hidden
*/
webrtcStatsInterval: number = -1;
/**
* @hidden
*/
sendBrowserLogs: OpenViduLoggerConfiguration = OpenViduLoggerConfiguration.disabled;
/**
* @hidden
*/
isPro: boolean = false;
/**
* @hidden
*/
@ -768,7 +770,8 @@ export class OpenVidu {
filterEventDispatched: this.session.onFilterEventDispatched.bind(this.session),
iceCandidate: this.session.recvIceCandidate.bind(this.session),
mediaError: this.session.onMediaError.bind(this.session),
masterNodeCrashedNotification: this.onMasterNodeCrashedNotification.bind(this)
masterNodeCrashedNotification: this.onMasterNodeCrashedNotification.bind(this),
forciblyReconnectSubscriber: this.session.onForciblyReconnectSubscriber.bind(this.session)
}
};
this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config);

View File

@ -778,8 +778,6 @@ export class Session extends EventDispatcher {
* @hidden
*/
onParticipantLeft(event: { connectionId: string, reason: string }): void {
if (this.remoteConnections.size > 0) {
this.getRemoteConnection(event.connectionId, 'onParticipantLeft').then(connection => {
if (!!connection.stream) {
const stream = connection.stream;
@ -797,7 +795,6 @@ export class Session extends EventDispatcher {
logger.error(openViduError);
});
}
}
/**
* @hidden
@ -1123,6 +1120,61 @@ export class Session extends EventDispatcher {
});
}
/**
* @hidden
*/
onForciblyReconnectSubscriber(event: { connectionId: string, streamId: string, sdpOffer: string }): Promise<void> {
return new Promise((resolve, reject) => {
this.getRemoteConnection(event.connectionId, 'onForciblyReconnectSubscriber')
.then(connection => {
if (!!connection.stream && connection.stream.streamId === event.streamId) {
const stream = connection.stream;
if (stream.setupReconnectionEventEmitter(resolve, reject)) {
// Ongoing reconnection
// Wait for the event emitter to be free (with success or error) and call the method again
if (stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] != null) {
// Two or more onForciblyReconnectSubscriber events were received while a reconnection process
// of the subscriber was already taking place. Always use the last one to retry the re-subscription
// process, as that SDP offer will be the only one available at the server side. Ignore previous ones
stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] = event;
reject('Ongoing forced subscriber reconnection');
} else {
// One onForciblyReconnectSubscriber even has been received while a reconnection process
// of the subscriber was already taking place. Set up a listener to wait for it to retry the
// forced reconnection process
stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'] = event;
const callback = () => {
const eventAux = stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'];
delete stream.reconnectionEventEmitter!['onForciblyReconnectSubscriberLastEvent'];
this.onForciblyReconnectSubscriber(eventAux);
}
stream.reconnectionEventEmitter!.once('success', () => {
callback();
});
stream.reconnectionEventEmitter!.once('error', () => {
callback();
});
}
return;
}
stream.completeWebRtcPeerReceive(true, event.sdpOffer)
.then(() => stream.finalResolveForSubscription(true, resolve))
.catch(error => stream.finalRejectForSubscription(true, `Error while forcibly reconnecting remote stream ${event.streamId}: ${error.toString()}`, reject));
} else {
const errMsg = "No stream with streamId '" + event.streamId + "' found for connection '" + event.connectionId + "' on 'streamPropertyChanged' event";
logger.error(errMsg);
reject(errMsg);
}
})
.catch(openViduError => {
logger.error(openViduError);
reject(openViduError);
});
});
}
/**
* @hidden
*/
@ -1463,6 +1515,7 @@ export class Session extends EventDispatcher {
if (!!sendBrowserLogs) {
this.openvidu.sendBrowserLogs = sendBrowserLogs;
}
this.openvidu.isPro = !!webrtcStatsInterval && !!sendBrowserLogs;
this.openvidu.wsUri = 'wss://' + url.host + '/openvidu';
this.openvidu.httpUri = 'https://' + url.host;

View File

@ -818,22 +818,33 @@ export class Stream {
/**
* @hidden
*/
initWebRtcPeerSend(reconnect: boolean): Promise<void> {
return new Promise((resolve, reject) => {
if (reconnect) {
setupReconnectionEventEmitter(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): boolean {
if (this.reconnectionEventEmitter == undefined) {
// There is no ongoing reconnection
this.reconnectionEventEmitter = new EventEmitter();
return false;
} else {
// Ongoing reconnection
console.warn(`Trying to reconnect stream ${this.streamId} (Publisher) but an ongoing reconnection process is active. Waiting for response...`);
console.warn(`Trying to reconnect stream ${this.streamId} (${this.isLocal() ? 'Publisher' : 'Subscriber'}) but an ongoing reconnection process is active. Waiting for response...`);
this.reconnectionEventEmitter.once('success', () => {
resolve();
});
this.reconnectionEventEmitter.once('error', error => {
reject(error);
});
return true;
}
}
/**
* @hidden
*/
initWebRtcPeerSend(reconnect: boolean): Promise<void> {
return new Promise((resolve, reject) => {
if (reconnect) {
if (this.setupReconnectionEventEmitter(resolve, reject)) {
// Ongoing reconnection
return;
}
} else {
@ -959,27 +970,7 @@ export class Stream {
/**
* @hidden
*/
initWebRtcPeerReceive(reconnect: boolean): Promise<void> {
return new Promise((resolve, reject) => {
if (reconnect) {
if (this.reconnectionEventEmitter == undefined) {
// There is no ongoing reconnection
this.reconnectionEventEmitter = new EventEmitter();
} else {
// Ongoing reconnection
console.warn(`Trying to reconnect stream ${this.streamId} (Subscriber) but an ongoing reconnection process is active. Waiting for response...`);
this.reconnectionEventEmitter.once('success', () => {
resolve();
});
this.reconnectionEventEmitter.once('error', error => {
reject(error);
});
return;
}
}
const finalResolve = () => {
finalResolveForSubscription(reconnect: boolean, resolve: (value: void | PromiseLike<void>) => void) {
logger.info("'Subscriber' (" + this.streamId + ") successfully " + (reconnect ? "reconnected" : "subscribed"));
this.remotePeerSuccessfullyEstablished(reconnect);
this.initWebRtcStats();
@ -990,7 +981,11 @@ export class Stream {
resolve();
}
const finalReject = error => {
/**
* @hidden
*/
finalRejectForSubscription(reconnect: boolean, error: any, reject: (reason?: any) => void) {
logger.error("Error for 'Subscriber' (" + this.streamId + ") while trying to " + (reconnect ? "reconnect" : "subscribe") + ": " + error.toString());
if (reconnect) {
this.reconnectionEventEmitter?.emitEvent('error', [error]);
delete this.reconnectionEventEmitter;
@ -998,21 +993,34 @@ export class Stream {
reject(error);
}
/**
* @hidden
*/
initWebRtcPeerReceive(reconnect: boolean): Promise<void> {
return new Promise((resolve, reject) => {
if (reconnect) {
if (this.setupReconnectionEventEmitter(resolve, reject)) {
// Ongoing reconnection
return;
}
}
if (this.session.openvidu.mediaServer === 'mediasoup') {
// Server initiates negotiation
this.initWebRtcPeerReceiveFromServer(reconnect)
.then(() => finalResolve())
.catch(error => finalReject(error));
.then(() => this.finalResolveForSubscription(reconnect, resolve))
.catch(error => this.finalRejectForSubscription(reconnect, error, reject));
} else {
// Client initiates negotiation
this.initWebRtcPeerReceiveFromClient(reconnect)
.then(() => finalResolve())
.catch(error => finalReject(error));
.then(() => this.finalResolveForSubscription(reconnect, resolve))
.catch(error => this.finalRejectForSubscription(reconnect, error, reject));
}
});
@ -1320,7 +1328,10 @@ export class Stream {
return state;
}
private initWebRtcStats(): void {
/**
* @hidden
*/
initWebRtcStats(): void {
this.webRtcStats = new WebRtcStats(this);
this.webRtcStats.initWebRtcStats();

View File

@ -28,10 +28,10 @@ export class OpenViduLogger {
*/
static configureJSNLog(openVidu: OpenVidu, token: string) {
try {
// If dev mode
// If dev mode or...
if ((window['LOG_JSNLOG_RESULTS']) ||
// If instance is created and it is OpenVidu Pro
(this.instance && openVidu.webrtcStatsInterval > -1
(this.instance && openVidu.isPro
// If logs are enabled
&& this.instance.isOpenViduBrowserLogsDebugActive(openVidu)
// Only reconfigure it if session or finalUserId has changed