From ff8b51dbf146f8633502e64909512c6d62f28224 Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Mon, 22 Mar 2021 19:23:03 +0100 Subject: [PATCH] openvidu-browser: ExceptionEvent --- openvidu-browser/src/OpenVidu/Connection.ts | 5 +- openvidu-browser/src/OpenVidu/Session.ts | 1 + openvidu-browser/src/OpenVidu/Stream.ts | 7 +- .../OpenViduInternal/Enums/OpenViduError.ts | 12 ++- .../OpenViduInternal/Events/ExceptionEvent.ts | 90 +++++++++++++++++++ .../OpenViduInternal/WebRtcPeer/WebRtcPeer.ts | 6 +- 6 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts diff --git a/openvidu-browser/src/OpenVidu/Connection.ts b/openvidu-browser/src/OpenVidu/Connection.ts index fe9d1e32..f03d09a0 100644 --- a/openvidu-browser/src/OpenVidu/Connection.ts +++ b/openvidu-browser/src/OpenVidu/Connection.ts @@ -22,6 +22,7 @@ import { RemoteConnectionOptions } from '../OpenViduInternal/Interfaces/Private/ import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions'; import { StreamOptionsServer } from '../OpenViduInternal/Interfaces/Private/StreamOptionsServer'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; +import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; /** * @hidden @@ -142,8 +143,8 @@ export class Connection { sdpMLineIndex: candidate.sdpMLineIndex }, (error, response) => { if (error) { - logger.error('Error sending ICE candidate: ' - + JSON.stringify(error)); + logger.error('Error sending ICE candidate: ' + JSON.stringify(error)); + this.session.emitEvent('exception', [new ExceptionEvent(this.session, ExceptionEventName.ICE_CANDIDATE_ERROR, this.session, "There was an unexpected error on the server-side processing an ICE candidate generated and sent by the client-side", error)]); } }); } diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 6eaf05b1..ecdade1d 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -76,6 +76,7 @@ let platform: PlatformUtils; * - networkQualityLevelChanged ([[NetworkQualityLevelChangedEvent]]) * - reconnecting * - reconnected + * - exception ([[ExceptionEvent]]) */ export class Session extends EventDispatcher { diff --git a/openvidu-browser/src/OpenVidu/Stream.ts b/openvidu-browser/src/OpenVidu/Stream.ts index 6ee5c5f7..0a6a9a1a 100644 --- a/openvidu-browser/src/OpenVidu/Stream.ts +++ b/openvidu-browser/src/OpenVidu/Stream.ts @@ -22,8 +22,9 @@ import { StreamManager } from './StreamManager'; import { Subscriber } from './Subscriber'; import { InboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/InboundStreamOptions'; import { OutboundStreamOptions } from '../OpenViduInternal/Interfaces/Private/OutboundStreamOptions'; -import { WebRtcPeer, WebRtcPeerSendonly, WebRtcPeerRecvonly, WebRtcPeerSendrecv } from '../OpenViduInternal/WebRtcPeer/WebRtcPeer'; +import { WebRtcPeer, WebRtcPeerSendonly, WebRtcPeerRecvonly, WebRtcPeerSendrecv, WebRtcPeerConfiguration } from '../OpenViduInternal/WebRtcPeer/WebRtcPeer'; import { WebRtcStats } from '../OpenViduInternal/WebRtcStats/WebRtcStats'; +import { ExceptionEvent, ExceptionEventName } from '../OpenViduInternal/Events/ExceptionEvent'; import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpeakingEvent'; import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; @@ -805,10 +806,11 @@ export class Stream { video: this.isSendVideo() }; - const options = { + const options: WebRtcPeerConfiguration = { mediaStream: this.mediaStream, mediaConstraints: userMediaConstraints, onicecandidate: this.connection.sendIceCandidate.bind(this.connection), + onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) }, iceServers: this.getIceServersConf(), simulcast: false }; @@ -937,6 +939,7 @@ export class Stream { offerConstraints); const options = { onicecandidate: this.connection.sendIceCandidate.bind(this.connection), + onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) }, mediaConstraints: offerConstraints, iceServers: this.getIceServersConf(), simulcast: false diff --git a/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts b/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts index 7acd86b8..468afc01 100644 --- a/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts +++ b/openvidu-browser/src/OpenViduInternal/Enums/OpenViduError.ts @@ -102,12 +102,13 @@ export enum OpenViduErrorName { OPENVIDU_PERMISSION_DENIED = 'OPENVIDU_PERMISSION_DENIED', /** - * _Not in use yet_ + * There is no connection to the Session. This error will be thrown when any method requiring a connection to + * openvidu-server is called before successfully calling method [[Session.connect]] */ OPENVIDU_NOT_CONNECTED = 'OPENVIDU_NOT_CONNECTED', /** - * _Not in use yet_ + * Generic error */ GENERIC_ERROR = 'GENERIC_ERROR' } @@ -117,7 +118,14 @@ export enum OpenViduErrorName { */ export class OpenViduError { + /** + * Uniquely identifying name of the error + */ name: OpenViduErrorName; + + /** + * Full description of the error + */ message: string; /** diff --git a/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts new file mode 100644 index 00000000..ac17aeee --- /dev/null +++ b/openvidu-browser/src/OpenViduInternal/Events/ExceptionEvent.ts @@ -0,0 +1,90 @@ +/* + * (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 { Session } from '../../OpenVidu/Session'; +import { Stream } from '../../OpenVidu/Stream'; +import { Event } from './Event'; + + +/** + * Defines property [[ExceptionEvent.name]] + */ +export enum ExceptionEventName { + + /** + * There was an unexpected error on the server-side processing an ICE candidate generated and sent by the client-side. + * + * [[ExceptionEvent]] objects with this [[ExceptionEvent.name]] will have as [[ExceptionEvent.origin]] property a [[Session]] object. + */ + ICE_CANDIDATE_ERROR = 'ICE_CANDIDATE_ERROR', + + /** + * The [ICE connection state](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState) + * of an [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) reached `failed` status. + * + * [[ExceptionEvent]] objects with this [[ExceptionEvent.name]] will have as [[ExceptionEvent.origin]] property a [[Stream]] object. + */ + ICE_CONNECTION_FAILED = 'ICE_CONNECTION_FAILED' +} + +/** + * Defines event `exception` dispatched by [[Session]] object. + * + * This event acts as a global handler for asynchronous errors that may be triggered for multiple reasons and from multiple origins. + */ +export class ExceptionEvent extends Event { + + /** + * Name of the exception + */ + name: ExceptionEventName; + + /** + * Object affected by the exception. Depending on the [[ExceptionEvent.name]] property: + * - [[Session]]: `ICE_CANDIDATE_ERROR` + * - [[Stream]]: `ICE_CONNECTION_FAILED` + */ + origin: Session | Stream; + + /** + * Informative description of the exception + */ + message: string; + + /** + * Any extra information associated to the exception + */ + data?: any; + + /** + * @hidden + */ + constructor(session: Session, name: ExceptionEventName, origin: Session | Stream, message: string, data?: any) { + super(false, session, 'exception'); + this.name = name; + this.origin = origin; + this.message = message; + this.data = data; + } + + /** + * @hidden + */ + // tslint:disable-next-line:no-empty + callDefaultBehavior() { } + +} \ No newline at end of file diff --git a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts b/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts index 5b0d1a3a..ade09f05 100644 --- a/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts +++ b/openvidu-browser/src/OpenViduInternal/WebRtcPeer/WebRtcPeer.ts @@ -17,6 +17,7 @@ import freeice = require('freeice'); import uuid = require('uuid'); +import { ExceptionEventName } from '../Events/ExceptionEvent'; import { OpenViduLogger } from '../Logger/OpenViduLogger'; import { PlatformUtils } from '../Utils/Platform'; @@ -37,6 +38,7 @@ export interface WebRtcPeerConfiguration { }; simulcast: boolean; onicecandidate: (event: RTCIceCandidate) => void; + onexception: (exceptionName: ExceptionEventName, message: string, data?: any) => void; iceServers: RTCIceServer[] | undefined; mediaStream?: MediaStream; mode?: 'sendonly' | 'recvonly' | 'sendrecv'; @@ -322,7 +324,9 @@ export class WebRtcPeer { logger.warn('IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') change to "disconnected". Possible network disconnection'); break; case 'failed': - logger.error('IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') to "failed"'); + const msg = 'IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') to "failed"'; + logger.error(msg); + this.configuration.onexception(ExceptionEventName.ICE_CONNECTION_FAILED, msg); break; case 'closed': logger.log('IceConnectionState of RTCPeerConnection ' + this.id + ' (' + otherId + ') change to "closed"');