diff --git a/openvidu-browser/src/OpenVidu/OpenVidu.ts b/openvidu-browser/src/OpenVidu/OpenVidu.ts index d889901c..29be9863 100644 --- a/openvidu-browser/src/OpenVidu/OpenVidu.ts +++ b/openvidu-browser/src/OpenVidu/OpenVidu.ts @@ -183,6 +183,7 @@ export class OpenVidu { } else { this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]); publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]); + this.session.sendVideoData(publisher); } }); clearTimeout(repeatUntilChange); @@ -334,12 +335,9 @@ export class OpenVidu { * @returns 1 if the browser supports OpenVidu, 0 otherwise */ checkSystemRequirements(): number { - const browser = platform.name; - const family = platform.os!!.family; - const userAgent = !!platform.ua ? platform.ua : navigator.userAgent; - if (this.isIPhoneOrIPad(userAgent)) { - if (this.isIOSWithSafari(userAgent) || platform['isIonicIos']) { + if (this.isIPhoneOrIPad()) { + if (this.isIOSWithSafari() || platform['isIonicIos']) { return 1; } return 0; @@ -347,13 +345,10 @@ export class OpenVidu { // Accept: Chrome (desktop and Android), Firefox (desktop and Android), Opera (desktop and Android), // Safari (OSX and iOS), Ionic (Android and iOS), Samsung Internet Browser (Android) - if ( - (browser === 'Safari') || - (browser === 'Chrome') || (browser === 'Chrome Mobile') || - (browser === 'Firefox') || (browser === 'Firefox Mobile') || - (browser === 'Opera') || (browser === 'Opera Mobile') || - (browser === 'Android Browser') || (browser === 'Electron') || - (browser === 'Samsung Internet Mobile') || (browser === 'Samsung Internet') + if (this.isSafariBrowser() || this.isChromeBrowser() || this.isChromeMobileBrowser() || + this.isFirefoxBrowser() || this.isFirefoxMobileBrowser() || this.isOperaBrowser() || + this.isOperaMobileBrowser() || this.isAndroidBrowser() || this.isElectron() || + this.isSamsungBrowser() ) { return 1; } @@ -877,6 +872,98 @@ export class OpenVidu { return mediaStream; } + /** + * @hidden + */ + public isChromeBrowser(): boolean { + return platform.name === 'Chrome'; + } + + /** + * @hidden + */ + public isSafariBrowser(): boolean { + return platform.name === 'Safari'; + } + + /** + * @hidden + */ + public isChromeMobileBrowser(): boolean { + return platform.name === 'Chrome Mobile'; + } + + /** + * @hidden + */ + public isFirefoxBrowser(): boolean { + return platform.name === 'Firefox'; + } + + /** + * @hidden + */ + public isFirefoxMobileBrowser(): boolean { + return platform.name === 'Firefox Mobile'; + } + + /** + * @hidden + */ + public isOperaBrowser(): boolean { + return platform.name === 'Opera'; + } + + /** + * @hidden + */ + public isOperaMobileBrowser(): boolean { + return platform.name === 'Opera Mobile'; + } + + /** + * @hidden + */ + public isAndroidBrowser(): boolean { + return platform.name === 'Android Browser'; + } + + /** + * @hidden + */ + public isElectron(): boolean { + return platform.name === 'Electron'; + } + + /** + * @hidden + */ + public isSamsungBrowser(): boolean { + return platform.name === 'Samsung Internet Mobile' || platform.name === 'Samsung Internet'; + } + + /** + * @hidden + */ + public isIPhoneOrIPad(): boolean { + const userAgent = !!platform.ua ? platform.ua : navigator.userAgent; + + const isTouchable = 'ontouchend' in document; + const isIPad = /\b(\w*Macintosh\w*)\b/.test(userAgent) && isTouchable; + const isIPhone = /\b(\w*iPhone\w*)\b/.test(userAgent) && /\b(\w*Mobile\w*)\b/.test(userAgent) && isTouchable; + + return isIPad || isIPhone; + } + + /** + * @hidden + */ + public isIOSWithSafari(): boolean { + const userAgent = !!platform.ua ? platform.ua : navigator.userAgent; + return /\b(\w*Apple\w*)\b/.test(navigator.vendor) && /\b(\w*Safari\w*)\b/.test(userAgent) + && !/\b(\w*CriOS\w*)\b/.test(userAgent) && !/\b(\w*FxiOS\w*)\b/.test(userAgent); + } + /** * @hidden */ @@ -1066,18 +1153,4 @@ export class OpenVidu { (platform.name === 'Electron' && videoSource.startsWith('screen:')) } - private isIPhoneOrIPad(userAgent): boolean { - const isTouchable = 'ontouchend' in document; - const isIPad = /\b(\w*Macintosh\w*)\b/.test(userAgent) && isTouchable; - const isIPhone = /\b(\w*iPhone\w*)\b/.test(userAgent) && /\b(\w*Mobile\w*)\b/.test(userAgent) && isTouchable; - - return isIPad || isIPhone; - } - - private isIOSWithSafari(userAgent): boolean { - return /\b(\w*Apple\w*)\b/.test(navigator.vendor) && /\b(\w*Safari\w*)\b/.test(userAgent) - && !/\b(\w*CriOS\w*)\b/.test(userAgent) && !/\b(\w*FxiOS\w*)\b/.test(userAgent); - } - - -} \ No newline at end of file + } \ No newline at end of file diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index 60151ca6..15aa155a 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -142,6 +142,7 @@ export class Publisher extends StreamManager { } else { this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'audioActive', value, !value, 'publishAudio')]); this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'audioActive', value, !value, 'publishAudio')]); + this.session.sendVideoData(this.stream.streamManager); } }); } @@ -189,6 +190,7 @@ export class Publisher extends StreamManager { } else { this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'videoActive', value, !value, 'publishVideo')]); this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'videoActive', value, !value, 'publishVideo')]); + this.session.sendVideoData(this.stream.streamManager); } }); } @@ -308,6 +310,7 @@ export class Publisher extends StreamManager { mediaStream.removeTrack(removedTrack); removedTrack.stop(); mediaStream.addTrack(track); + this.session.sendVideoData(this.stream.streamManager); } return new Promise((resolve, reject) => { @@ -481,6 +484,7 @@ export class Publisher extends StreamManager { } else { this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'videoDimensions', this.stream.videoDimensions, oldValue, 'screenResized')]); this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'videoDimensions', this.stream.videoDimensions, oldValue, 'screenResized')]); + this.session.sendVideoData(this.stream.streamManager); } }); } diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 09f5a38a..e3b1c55b 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -37,7 +37,7 @@ import { SessionDisconnectedEvent } from '../OpenViduInternal/Events/SessionDisc import { SignalEvent } from '../OpenViduInternal/Events/SignalEvent'; import { StreamEvent } from '../OpenViduInternal/Events/StreamEvent'; import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; -import { NetworkQualityChangedEvent, NetworkQualityChangedReason } from '../OpenViduInternal/Events/NetworkQualityChangedEvent'; +import { NetworkQualityChangedEvent } from '../OpenViduInternal/Events/NetworkQualityChangedEvent'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; @@ -378,6 +378,7 @@ export class Session extends EventDispatcher { this.connection.addStream(publisher.stream); publisher.stream.publish() .then(() => { + this.sendVideoData(publisher, 5); resolve(); }) .catch(error => { @@ -391,6 +392,7 @@ export class Session extends EventDispatcher { publisher.reestablishStreamPlayingEvent(); publisher.stream.publish() .then(() => { + this.sendVideoData(publisher, 5); resolve(); }) .catch(error => { @@ -898,6 +900,7 @@ export class Session extends EventDispatcher { break; } this.ee.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, stream, msg.property, msg.newValue, oldValue, msg.reason)]); + this.sendVideoData(stream.streamManager); if (!!stream.streamManager) { stream.streamManager.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(stream.streamManager, stream, msg.property, msg.newValue, oldValue, msg.reason)]); } @@ -926,9 +929,8 @@ export class Session extends EventDispatcher { * @hidden */ onNetworkQualityChangedChanged(msg): void { - if (msg.connectionId === this.connection.connectionId) { - this.ee.emitEvent('networkQualityChanged', [new NetworkQualityChangedEvent(this, msg.newValue, msg.oldValue, msg.reason)]); + this.ee.emitEvent('networkQualityChanged', [new NetworkQualityChangedEvent(this, msg.qualityLevel)]); } } @@ -1125,6 +1127,36 @@ export class Session extends EventDispatcher { return joinParams; } + sendVideoData(streamManager: StreamManager, intervalSeconds: number = 1) { + if( + this.openvidu.isChromeBrowser() || this.openvidu.isChromeMobileBrowser() || this.openvidu.isOperaBrowser() || + this.openvidu.isOperaMobileBrowser() || this.openvidu.isElectron() || this.openvidu.isSafariBrowser() || + this.openvidu.isAndroidBrowser() || this.openvidu.isSamsungBrowser() || + (this.openvidu.isIPhoneOrIPad() && this.openvidu.isIOSWithSafari()) + ) { + const statsRequest = setInterval(async () => { + const statsMap = await streamManager.stream.getWebRtcPeer().pc.getStats(); + statsMap.forEach((stats) => { + + if ("frameWidth" in stats) { + this.openvidu.sendRequest('videoData', { + height: stats.frameHeight, + width: stats.frameWidth, + videoActive: streamManager.stream.videoActive, + audioActive: streamManager.stream.audioActive + }, (error, response) => { + if (error) { + logger.error("Error sending 'videoData' event", error); + } + clearInterval(statsRequest); + }); + } + }); + }, intervalSeconds * 1000); + } else { + console.error('Browser ' + platform.name + ' (version ' + platform.version + ') for ' + platform.os!!.family + ' is not supported in OpenVidu for Network Quality'); + } + } /* Private methods */ diff --git a/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityChangedEvent.ts b/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityChangedEvent.ts index 710950e0..9aa5450b 100644 --- a/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityChangedEvent.ts +++ b/openvidu-browser/src/OpenViduInternal/Events/NetworkQualityChangedEvent.ts @@ -24,29 +24,18 @@ import { Session } from '../../OpenVidu/Session'; */ export class NetworkQualityChangedEvent extends Event { - /** - * Cause of the change on the neteotk quality event - */ - reason: NetworkQualityChangedReason; /** * New value of the property (after change, current value) */ - newValue: Object; - - /** - * Previous value of the property (before change) - */ - oldValue: Object; + qualityLevel: Object; /** * @hidden */ - constructor(target: Session, newValue: Object, oldValue: Object, reason: NetworkQualityChangedReason) { + constructor(target: Session, qualityLevel: Object) { super(false, target, 'networkQualityChanged'); - this.newValue = newValue; - this.oldValue = oldValue; - this.reason = reason; + this.qualityLevel = qualityLevel; } /** @@ -56,8 +45,3 @@ export class NetworkQualityChangedEvent extends Event { callDefaultBehavior() { } } - -export enum NetworkQualityChangedReason { - ABOVE_MAX = "above_max", - BELOW_MIN = "below_min" -} diff --git a/openvidu-browser/src/index.ts b/openvidu-browser/src/index.ts index d9c509ae..b36d1958 100644 --- a/openvidu-browser/src/index.ts +++ b/openvidu-browser/src/index.ts @@ -24,7 +24,6 @@ export { VideoElementEvent } from './OpenViduInternal/Events/VideoElementEvent'; export { StreamPropertyChangedEvent } from './OpenViduInternal/Events/StreamPropertyChangedEvent'; export { FilterEvent } from './OpenViduInternal/Events/FilterEvent'; export { NetworkQualityChangedEvent } from './OpenViduInternal/Events/NetworkQualityChangedEvent'; -export { NetworkQualityChangedReason } from './OpenViduInternal/Events/NetworkQualityChangedEvent'; export { Capabilities } from './OpenViduInternal/Interfaces/Public/Capabilities'; export { Device } from './OpenViduInternal/Interfaces/Public/Device';