openvidu-browser: Wrapped platform library

pull/550/head
csantosm 2020-10-13 16:13:37 +02:00
parent e8121bf35c
commit 433d640a8a
9 changed files with 280 additions and 175 deletions

View File

@ -17,8 +17,8 @@
import { Stream } from './Stream'; import { Stream } from './Stream';
import { LocalRecorderState } from '../OpenViduInternal/Enums/LocalRecorderState'; import { LocalRecorderState } from '../OpenViduInternal/Enums/LocalRecorderState';
import platform = require('platform');
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
/** /**
@ -30,6 +30,11 @@ declare var MediaRecorder: any;
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method * Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method
@ -211,7 +216,7 @@ export class LocalRecorder {
this.videoPreview.id = this.id; this.videoPreview.id = this.id;
this.videoPreview.autoplay = true; this.videoPreview.autoplay = true;
if (platform.name === 'Safari') { if (platform.isSafariBrowser()) {
this.videoPreview.setAttribute('playsinline', 'true'); this.videoPreview.setAttribute('playsinline', 'true');
} }

View File

@ -28,6 +28,7 @@ import { CustomMediaStreamConstraints } from '../OpenViduInternal/Interfaces/Pri
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
import * as screenSharingAuto from '../OpenViduInternal/ScreenSharing/Screen-Capturing-Auto'; import * as screenSharingAuto from '../OpenViduInternal/ScreenSharing/Screen-Capturing-Auto';
import * as screenSharing from '../OpenViduInternal/ScreenSharing/Screen-Capturing'; import * as screenSharing from '../OpenViduInternal/ScreenSharing/Screen-Capturing';
@ -39,13 +40,6 @@ import EventEmitter = require('wolfy87-eventemitter');
* @hidden * @hidden
*/ */
import RpcBuilder = require('../OpenViduInternal/KurentoUtils/kurento-jsonrpc'); import RpcBuilder = require('../OpenViduInternal/KurentoUtils/kurento-jsonrpc');
/**
* @hidden
*/
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isIonicAndroid'] = platform.os!!.family === 'Android' && platform.name == "Android Browser";
/** /**
* @hidden * @hidden
@ -60,6 +54,11 @@ declare var cordova: any;
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Entrypoint of OpenVidu Browser library. * Entrypoint of OpenVidu Browser library.
* Use it to initialize objects of type [[Session]], [[Publisher]] and [[LocalRecorder]] * Use it to initialize objects of type [[Session]], [[Publisher]] and [[LocalRecorder]]
@ -122,7 +121,7 @@ export class OpenVidu {
logger.info("'OpenVidu' initialized"); logger.info("'OpenVidu' initialized");
logger.info("openvidu-browser version: " + this.libraryVersion); logger.info("openvidu-browser version: " + this.libraryVersion);
if (platform.os!!.family === 'iOS' || platform.os!!.family === 'Android') { if (platform.isMobileDevice()) {
// Listen to orientationchange only on mobile devices // Listen to orientationchange only on mobile devices
(<any>window).addEventListener('orientationchange', () => { (<any>window).addEventListener('orientationchange', () => {
this.publishers.forEach(publisher => { this.publishers.forEach(publisher => {
@ -135,7 +134,7 @@ export class OpenVidu {
const getNewVideoDimensions = (): Promise<{ newWidth: number, newHeight: number }> => { const getNewVideoDimensions = (): Promise<{ newWidth: number, newHeight: number }> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (platform['isIonicIos']) { if (platform.isIonicIos()) {
// iOS Ionic. Limitation: must get new dimensions from an existing video element already inserted into DOM // iOS Ionic. Limitation: must get new dimensions from an existing video element already inserted into DOM
resolve({ resolve({
newWidth: publisher.stream.streamManager.videos[0].video.videoWidth, newWidth: publisher.stream.streamManager.videos[0].video.videoWidth,
@ -146,8 +145,8 @@ export class OpenVidu {
// New resolution got from different places for Chrome and Firefox. Chrome needs a videoWidth and videoHeight of a videoElement. // New resolution got from different places for Chrome and Firefox. Chrome needs a videoWidth and videoHeight of a videoElement.
// Firefox needs getSettings from the videoTrack // Firefox needs getSettings from the videoTrack
const firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings(); const firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
const newWidth = <number>((platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth); const newWidth = <number>((platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) ? firefoxSettings.width : publisher.videoReference.videoWidth);
const newHeight = <number>((platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight); const newHeight = <number>((platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) ? firefoxSettings.height : publisher.videoReference.videoHeight);
resolve({ newWidth, newHeight }); resolve({ newWidth, newHeight });
} }
}); });
@ -336,8 +335,8 @@ export class OpenVidu {
*/ */
checkSystemRequirements(): number { checkSystemRequirements(): number {
if (this.isIPhoneOrIPad()) { if (platform.isIPhoneOrIPad()) {
if (this.isIOSWithSafari() || platform['isIonicIos']) { if (platform.isIOSWithSafari() || platform.isIonicIos()) {
return 1; return 1;
} }
return 0; return 0;
@ -345,10 +344,10 @@ export class OpenVidu {
// Accept: Chrome (desktop and Android), Firefox (desktop and Android), Opera (desktop and Android), // 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) // Safari (OSX and iOS), Ionic (Android and iOS), Samsung Internet Browser (Android)
if (this.isSafariBrowser() || this.isChromeBrowser() || this.isChromeMobileBrowser() || if (platform.isSafariBrowser() || platform.isChromeBrowser() || platform.isChromeMobileBrowser() ||
this.isFirefoxBrowser() || this.isFirefoxMobileBrowser() || this.isOperaBrowser() || platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser() || platform.isOperaBrowser() ||
this.isOperaMobileBrowser() || this.isAndroidBrowser() || this.isElectron() || platform.isOperaMobileBrowser() || platform.isAndroidBrowser() || platform.isElectron() ||
this.isSamsungBrowser() platform.isSamsungBrowser()
) { ) {
return 1; return 1;
} }
@ -362,22 +361,8 @@ export class OpenVidu {
* Checks if the browser supports screen-sharing. Desktop Chrome, Firefox and Opera support screen-sharing * Checks if the browser supports screen-sharing. Desktop Chrome, Firefox and Opera support screen-sharing
* @returns 1 if the browser supports screen-sharing, 0 otherwise * @returns 1 if the browser supports screen-sharing, 0 otherwise
*/ */
checkScreenSharingCapabilities(): number { checkScreenSharingCapabilities(): boolean {
const browser = platform.name; return platform.canScreenShare();
const version = platform?.version ? parseFloat(platform.version) : -1;
const family = platform.os!!.family;
// Reject mobile devices
if (family === 'iOS' || family === 'Android') {
return 0;
}
if ((browser !== 'Chrome') && (browser !== 'Firefox') && (browser !== 'Opera') && (browser !== 'Electron') &&
(browser === 'Safari' && version < 13)) {
return 0;
} else {
return 1;
}
} }
@ -390,7 +375,7 @@ export class OpenVidu {
const devices: Device[] = []; const devices: Device[] = [];
// Ionic Android devices // Ionic Android devices
if (platform['isIonicAndroid'] && typeof cordova != "undefined" && cordova?.plugins?.EnumerateDevicesPlugin) { if (platform.isIonicAndroid() && typeof cordova != "undefined" && cordova?.plugins?.EnumerateDevicesPlugin) {
cordova.plugins.EnumerateDevicesPlugin.getEnumerateDevices().then((pluginDevices: Device[]) => { cordova.plugins.EnumerateDevicesPlugin.getEnumerateDevices().then((pluginDevices: Device[]) => {
let pluginAudioDevices: Device[] = []; let pluginAudioDevices: Device[] = [];
let videoDevices: Device[] = []; let videoDevices: Device[] = [];
@ -582,10 +567,10 @@ export class OpenVidu {
// Video is deviceId or screen sharing // Video is deviceId or screen sharing
if (options.videoSource === 'screen' || if (options.videoSource === 'screen' ||
options.videoSource === 'window' || options.videoSource === 'window' ||
(platform.name === 'Electron' && options.videoSource.startsWith('screen:'))) { (platform.isElectron() && options.videoSource.startsWith('screen:'))) {
// Video is screen sharing // Video is screen sharing
mustAskForAudioTrackLater = !myConstraints.audioTrack && (options.audioSource !== null && options.audioSource !== false); mustAskForAudioTrackLater = !myConstraints.audioTrack && (options.audioSource !== null && options.audioSource !== false);
if (navigator.mediaDevices['getDisplayMedia'] && platform.name !== 'Electron') { if (navigator.mediaDevices['getDisplayMedia'] && !platform.isElectron()) {
// getDisplayMedia supported // getDisplayMedia supported
navigator.mediaDevices['getDisplayMedia']({ video: true }) navigator.mediaDevices['getDisplayMedia']({ video: true })
.then(mediaStream => { .then(mediaStream => {
@ -872,98 +857,6 @@ export class OpenVidu {
return mediaStream; 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 * @hidden
*/ */
@ -984,12 +877,12 @@ export class OpenVidu {
// Screen sharing // Screen sharing
if (!this.checkScreenSharingCapabilities()) { if (!this.checkScreenSharingCapabilities()) {
const error = new OpenViduError(OpenViduErrorName.SCREEN_SHARING_NOT_SUPPORTED, 'You can only screen share in desktop Chrome, Firefox, Opera, Safari (>=13.0) or Electron. Detected client: ' + platform.name); const error = new OpenViduError(OpenViduErrorName.SCREEN_SHARING_NOT_SUPPORTED, 'You can only screen share in desktop Chrome, Firefox, Opera, Safari (>=13.0) or Electron. Detected client: ' + platform.getName());
logger.error(error); logger.error(error);
reject(error); reject(error);
} else { } else {
if (platform.name === 'Electron') { if (platform.isElectron()) {
const prefix = "screen:"; const prefix = "screen:";
const videoSourceString: string = videoSource; const videoSourceString: string = videoSource;
const electronScreenId = videoSourceString.substr(videoSourceString.indexOf(prefix) + prefix.length); const electronScreenId = videoSourceString.substr(videoSourceString.indexOf(prefix) + prefix.length);
@ -1003,7 +896,7 @@ export class OpenVidu {
} else { } else {
if (!!this.advancedConfiguration.screenShareChromeExtension && !(platform.name!.indexOf('Firefox') !== -1) && !navigator.mediaDevices['getDisplayMedia']) { if (!!this.advancedConfiguration.screenShareChromeExtension && !(platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) && !navigator.mediaDevices['getDisplayMedia']) {
// Custom screen sharing extension for Chrome (and Opera) and no support for MediaDevices.getDisplayMedia() // Custom screen sharing extension for Chrome (and Opera) and no support for MediaDevices.getDisplayMedia()
@ -1042,7 +935,7 @@ export class OpenVidu {
resolve(myConstraints); resolve(myConstraints);
} else { } else {
// Default screen sharing extension for Chrome/Opera, or is Firefox < 66 // Default screen sharing extension for Chrome/Opera, or is Firefox < 66
const firefoxString = platform.name!.indexOf('Firefox') !== -1 ? publisherProperties.videoSource : undefined; const firefoxString = (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) ? publisherProperties.videoSource : undefined;
screenSharingAuto.getScreenId(firefoxString, (error, sourceId, screenConstraints) => { screenSharingAuto.getScreenId(firefoxString, (error, sourceId, screenConstraints) => {
if (!!error) { if (!!error) {
@ -1150,7 +1043,7 @@ export class OpenVidu {
private isScreenShare(videoSource: string) { private isScreenShare(videoSource: string) {
return videoSource === 'screen' || return videoSource === 'screen' ||
videoSource === 'window' || videoSource === 'window' ||
(platform.name === 'Electron' && videoSource.startsWith('screen:')) (platform.isElectron() && videoSource.startsWith('screen:'))
} }
} }

View File

@ -27,15 +27,19 @@ import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPro
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent';
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import platform = require('platform');
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Packs local media streams. Participants can publish it to a session. Initialized with [[OpenVidu.initPublisher]] method * Packs local media streams. Participants can publish it to a session. Initialized with [[OpenVidu.initPublisher]] method
* *
@ -400,7 +404,7 @@ export class Publisher extends StreamManager {
if (this.stream.isSendVideo()) { if (this.stream.isSendVideo()) {
if (!this.stream.isSendScreen()) { if (!this.stream.isSendScreen()) {
if (platform['isIonicIos'] || platform.name === 'Safari') { if (platform.isIonicIos() || platform.isSafariBrowser()) {
// iOS Ionic or Safari. Limitation: cannot set videoDimensions directly, as the videoReference is not loaded // iOS Ionic or Safari. Limitation: cannot set videoDimensions directly, as the videoReference is not loaded
// if not added to DOM. Must add it to DOM and wait for videoWidth and videoHeight properties to be defined // if not added to DOM. Must add it to DOM and wait for videoWidth and videoHeight properties to be defined
@ -436,7 +440,7 @@ export class Publisher extends StreamManager {
// Orientation must be checked for mobile devices (width and height are reversed) // Orientation must be checked for mobile devices (width and height are reversed)
const { width, height } = this.getVideoDimensions(mediaStream); const { width, height } = this.getVideoDimensions(mediaStream);
if ((platform.os!!.family === 'iOS' || platform.os!!.family === 'Android') && (window.innerHeight > window.innerWidth)) { if (platform.isMobileDevice() && (window.innerHeight > window.innerWidth)) {
// Mobile portrait mode // Mobile portrait mode
this.stream.videoDimensions = { this.stream.videoDimensions = {
width: height || 0, width: height || 0,
@ -460,8 +464,8 @@ export class Publisher extends StreamManager {
}; };
this.screenShareResizeInterval = setInterval(() => { this.screenShareResizeInterval = setInterval(() => {
const firefoxSettings = mediaStream.getVideoTracks()[0].getSettings(); const firefoxSettings = mediaStream.getVideoTracks()[0].getSettings();
const newWidth = (platform.name === 'Chrome' || platform.name === 'Opera') ? this.videoReference.videoWidth : firefoxSettings.width; const newWidth = (platform.isChromeBrowser() || platform.isOperaBrowser()) ? this.videoReference.videoWidth : firefoxSettings.width;
const newHeight = (platform.name === 'Chrome' || platform.name === 'Opera') ? this.videoReference.videoHeight : firefoxSettings.height; const newHeight = (platform.isChromeBrowser() || platform.isOperaBrowser()) ? this.videoReference.videoHeight : firefoxSettings.height;
if (this.stream.isLocalStreamPublished && if (this.stream.isLocalStreamPublished &&
(newWidth !== this.stream.videoDimensions.width || (newWidth !== this.stream.videoDimensions.width ||
newHeight !== this.stream.videoDimensions.height)) { newHeight !== this.stream.videoDimensions.height)) {
@ -631,7 +635,7 @@ export class Publisher extends StreamManager {
startTime = Date.now(); startTime = Date.now();
this.setPermissionDialogTimer(timeForDialogEvent); this.setPermissionDialogTimer(timeForDialogEvent);
if (this.stream.isSendScreen() && navigator.mediaDevices['getDisplayMedia'] && platform.name !== 'Electron') { if (this.stream.isSendScreen() && navigator.mediaDevices['getDisplayMedia'] && !platform.isElectron()) {
navigator.mediaDevices['getDisplayMedia']({ video: true }) navigator.mediaDevices['getDisplayMedia']({ video: true })
.then(mediaStream => { .then(mediaStream => {
this.openvidu.addAlreadyProvidedTracks(myConstraints, mediaStream); this.openvidu.addAlreadyProvidedTracks(myConstraints, mediaStream);
@ -680,7 +684,7 @@ export class Publisher extends StreamManager {
initializeVideoReference(mediaStream: MediaStream) { initializeVideoReference(mediaStream: MediaStream) {
this.videoReference = document.createElement('video'); this.videoReference = document.createElement('video');
if (platform.name === 'Safari') { if (platform.isSafariBrowser()) {
this.videoReference.setAttribute('playsinline', 'true'); this.videoReference.setAttribute('playsinline', 'true');
} }

View File

@ -40,15 +40,19 @@ import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPro
import { NetworkQualityLevelChangedEvent } from '../OpenViduInternal/Events/NetworkQualityLevelChangedEvent'; import { NetworkQualityLevelChangedEvent } from '../OpenViduInternal/Events/NetworkQualityLevelChangedEvent';
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import platform = require('platform');
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Represents a video call. It can also be seen as a videoconference room where multiple users can connect. * Represents a video call. It can also be seen as a videoconference room where multiple users can connect.
* Participants who publish their videos to a session can be seen by the rest of users connected to that specific session. * Participants who publish their videos to a session can be seen by the rest of users connected to that specific session.
@ -193,7 +197,7 @@ export class Session extends EventDispatcher {
reject(error); reject(error);
}); });
} else { } else {
reject(new OpenViduError(OpenViduErrorName.BROWSER_NOT_SUPPORTED, 'Browser ' + platform.name + ' (version ' + platform.version + ') for ' + platform.os!!.family + ' is not supported in OpenVidu')); reject(new OpenViduError(OpenViduErrorName.BROWSER_NOT_SUPPORTED, 'Browser ' + platform.getName() + ' (version ' + platform.getVersion() + ') for ' + platform.getFamily() + ' is not supported in OpenVidu'));
} }
}); });
} }
@ -1122,7 +1126,7 @@ export class Session extends EventDispatcher {
const joinParams = { const joinParams = {
token: (!!token) ? token : '', token: (!!token) ? token : '',
session: this.sessionId, session: this.sessionId,
platform: !!platform.description ? platform.description : 'unknown', platform: !!platform.getDescription() ? platform.getDescription() : 'unknown',
metadata: !!this.options.metadata ? this.options.metadata : '', metadata: !!this.options.metadata ? this.options.metadata : '',
secret: this.openvidu.getSecret(), secret: this.openvidu.getSecret(),
recorder: this.openvidu.getRecorder() recorder: this.openvidu.getRecorder()
@ -1132,10 +1136,10 @@ export class Session extends EventDispatcher {
sendVideoData(streamManager: StreamManager, intervalSeconds: number = 1) { sendVideoData(streamManager: StreamManager, intervalSeconds: number = 1) {
if( if(
this.openvidu.isChromeBrowser() || this.openvidu.isChromeMobileBrowser() || this.openvidu.isOperaBrowser() || platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() ||
this.openvidu.isOperaMobileBrowser() || this.openvidu.isElectron() || this.openvidu.isSafariBrowser() || platform.isOperaMobileBrowser() || platform.isElectron() || platform.isSafariBrowser() ||
this.openvidu.isAndroidBrowser() || this.openvidu.isSamsungBrowser() || platform.isAndroidBrowser() || platform.isSamsungBrowser() ||
(this.openvidu.isIPhoneOrIPad() && this.openvidu.isIOSWithSafari()) (platform.isIPhoneOrIPad() && platform.isIOSWithSafari())
) { ) {
setTimeout(async () => { setTimeout(async () => {
const statsMap = await streamManager.stream.getWebRtcPeer().pc.getStats(); const statsMap = await streamManager.stream.getWebRtcPeer().pc.getStats();
@ -1154,7 +1158,7 @@ export class Session extends EventDispatcher {
} }
}); });
}, intervalSeconds * 1000); }, intervalSeconds * 1000);
} else if (this.openvidu.isFirefoxBrowser() || this.openvidu.isFirefoxMobileBrowser()) { } else if (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) {
// Basic version for Firefox. It does not support stats // Basic version for Firefox. It does not support stats
this.openvidu.sendRequest('videoData', { this.openvidu.sendRequest('videoData', {
height: streamManager.stream.videoDimensions.height, height: streamManager.stream.videoDimensions.height,
@ -1167,7 +1171,7 @@ export class Session extends EventDispatcher {
} }
}); });
} else { } else {
console.error('Browser ' + platform.name + ' (version ' + platform.version + ') for ' + platform.os!!.family + ' is not supported in OpenVidu for Network Quality'); logger.error('Browser ' + platform.getName() + ' (version ' + platform.getVersion() + ') for ' + platform.getFamily() + ' is not supported in OpenVidu for Network Quality');
} }
} }

View File

@ -30,19 +30,22 @@ import { PublisherSpeakingEvent } from '../OpenViduInternal/Events/PublisherSpea
import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent';
import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent';
import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError';
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
import hark = require('hark'); import hark = require('hark');
import platform = require('platform');
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Represents each one of the media streams available in OpenVidu Server for certain session. * Represents each one of the media streams available in OpenVidu Server for certain session.
@ -537,7 +540,7 @@ export class Stream extends EventDispatcher {
*/ */
isSendScreen(): boolean { isSendScreen(): boolean {
let screen = this.outboundStreamOpts.publisherProperties.videoSource === 'screen'; let screen = this.outboundStreamOpts.publisherProperties.videoSource === 'screen';
if (platform.name === 'Electron') { if (platform.isElectron()) {
screen = typeof this.outboundStreamOpts.publisherProperties.videoSource === 'string' && screen = typeof this.outboundStreamOpts.publisherProperties.videoSource === 'string' &&
this.outboundStreamOpts.publisherProperties.videoSource.startsWith('screen:'); this.outboundStreamOpts.publisherProperties.videoSource.startsWith('screen:');
} }

View File

@ -22,14 +22,19 @@ import { Event } from '../OpenViduInternal/Events/Event';
import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent';
import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent';
import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import platform = require('platform');
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger'; import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
/** /**
* Interface in charge of displaying the media streams in the HTML DOM. This wraps any [[Publisher]] and [[Subscriber]] object. * Interface in charge of displaying the media streams in the HTML DOM. This wraps any [[Publisher]] and [[Subscriber]] object.
* You can insert as many video players fo the same Stream as you want by calling [[StreamManager.addVideoElement]] or * You can insert as many video players fo the same Stream as you want by calling [[StreamManager.addVideoElement]] or
@ -121,7 +126,7 @@ export class StreamManager extends EventDispatcher {
id: '', id: '',
canplayListenerAdded: false canplayListenerAdded: false
}; };
if (platform.name === 'Safari') { if (platform.isSafariBrowser()) {
this.firstVideoElement.video.setAttribute('playsinline', 'true'); this.firstVideoElement.video.setAttribute('playsinline', 'true');
} }
this.targetElement = targEl; this.targetElement = targEl;
@ -379,7 +384,7 @@ export class StreamManager extends EventDispatcher {
video.autoplay = true; video.autoplay = true;
video.controls = false; video.controls = false;
if (platform.name === 'Safari') { if (platform.isSafariBrowser()) {
video.setAttribute('playsinline', 'true'); video.setAttribute('playsinline', 'true');
} }
@ -463,7 +468,7 @@ export class StreamManager extends EventDispatcher {
updateMediaStream(mediaStream: MediaStream) { updateMediaStream(mediaStream: MediaStream) {
this.videos.forEach(streamManagerVideo => { this.videos.forEach(streamManagerVideo => {
streamManagerVideo.video.srcObject = mediaStream; streamManagerVideo.video.srcObject = mediaStream;
if (platform['isIonicIos']) { if (platform.isIonicIos()) {
// iOS Ionic. LIMITATION: must reinsert the video in the DOM for // iOS Ionic. LIMITATION: must reinsert the video in the DOM for
// the media stream to be updated // the media stream to be updated
const vParent = streamManagerVideo.video.parentElement; const vParent = streamManagerVideo.video.parentElement;
@ -506,7 +511,7 @@ export class StreamManager extends EventDispatcher {
} }
private mirrorVideo(video): void { private mirrorVideo(video): void {
if (!platform['isIonicIos']) { if (!platform.isIonicIos()) {
video.style.transform = 'rotateY(180deg)'; video.style.transform = 'rotateY(180deg)';
video.style.webkitTransform = 'rotateY(180deg)'; video.style.webkitTransform = 'rotateY(180deg)';
} }

View File

@ -0,0 +1,183 @@
import platform = require("platform");
export class PlatformUtils {
private static instance: PlatformUtils;
private constructor() {}
static getInstance(): PlatformUtils {
if (!PlatformUtils.instance) {
PlatformUtils.instance = new PlatformUtils();
}
return PlatformUtils.instance;
}
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
*/
public isIonicIos(): boolean {
return this.isIPhoneOrIPad() && platform.ua!!.indexOf("Safari") === -1;
}
/**
* @hidden
*/
public isIonicAndroid(): boolean {
return (
platform.os!!.family === "Android" && platform.name == "Android Browser"
);
}
/**
* @hidden
*/
public isMobileDevice(): boolean {
return platform.os!!.family === "iOS" || platform.os!!.family === "Android";
}
/**
* @hidden
*/
public canScreenShare(): boolean {
const version = platform?.version ? parseFloat(platform.version) : -1;
// Reject mobile devices
if (this.isMobileDevice()) {
return false;
}
return (
this.isChromeBrowser() ||
this.isFirefoxBrowser() ||
this.isOperaBrowser() ||
this.isElectron() ||
(this.isSafariBrowser() && version >= 13)
);
}
/**
* @hidden
*/
public getName(): string {
return platform.name || "";
}
/**
* @hidden
*/
public getVersion(): string {
return platform.version || "";
}
/**
* @hidden
*/
public getFamily(): string {
return platform.os!!.family || "";
}
/**
* @hidden
*/
public getDescription(): string {
return platform.description || "";
}
}

View File

@ -17,12 +17,17 @@
import freeice = require('freeice'); import freeice = require('freeice');
import uuid = require('uuid'); import uuid = require('uuid');
import platform = require('platform');
import { OpenViduLogger } from '../Logger/OpenViduLogger'; import { OpenViduLogger } from '../Logger/OpenViduLogger';
import { PlatformUtils } from '../Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
export interface WebRtcPeerConfiguration { export interface WebRtcPeerConfiguration {
@ -139,7 +144,7 @@ export class WebRtcPeer {
logger.debug('RTCPeerConnection constraints: ' + JSON.stringify(constraints)); logger.debug('RTCPeerConnection constraints: ' + JSON.stringify(constraints));
if (platform.name === 'Safari' && platform.ua!!.indexOf('Safari') !== -1) { if (platform.isSafariBrowser() && !platform.isIonicIos()) {
// Safari (excluding Ionic), at least on iOS just seems to support unified plan, whereas in other browsers is not yet ready and considered experimental // Safari (excluding Ionic), at least on iOS just seems to support unified plan, whereas in other browsers is not yet ready and considered experimental
if (offerAudio) { if (offerAudio) {
this.pc.addTransceiver('audio', { this.pc.addTransceiver('audio', {
@ -217,7 +222,7 @@ export class WebRtcPeer {
* @hidden * @hidden
*/ */
setRemoteDescription(answer: RTCSessionDescriptionInit, needsTimeoutOnProcessAnswer: boolean, resolve: (value?: string | PromiseLike<string> | undefined) => void, reject: (reason?: any) => void) { setRemoteDescription(answer: RTCSessionDescriptionInit, needsTimeoutOnProcessAnswer: boolean, resolve: (value?: string | PromiseLike<string> | undefined) => void, reject: (reason?: any) => void) {
if (platform['isIonicIos']) { if (platform.isIonicIos()) {
// Ionic iOS platform // Ionic iOS platform
if (needsTimeoutOnProcessAnswer) { if (needsTimeoutOnProcessAnswer) {
// 400 ms have not elapsed yet since first remote stream triggered Stream#initWebRtcPeerReceive // 400 ms have not elapsed yet since first remote stream triggered Stream#initWebRtcPeerReceive

View File

@ -18,13 +18,16 @@
// tslint:disable:no-string-literal // tslint:disable:no-string-literal
import { Stream } from '../../OpenVidu/Stream'; import { Stream } from '../../OpenVidu/Stream';
import platform = require('platform');
import { OpenViduLogger } from '../Logger/OpenViduLogger'; import { OpenViduLogger } from '../Logger/OpenViduLogger';
import { PlatformUtils } from '../Utils/Platform';
/** /**
* @hidden * @hidden
*/ */
const logger: OpenViduLogger = OpenViduLogger.getInstance(); const logger: OpenViduLogger = OpenViduLogger.getInstance();
/**
* @hidden
*/
const platform: PlatformUtils = PlatformUtils.getInstance();
export class WebRtcStats { export class WebRtcStats {
@ -103,7 +106,7 @@ export class WebRtcStats {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.getStatsAgnostic(this.stream.getRTCPeerConnection(), this.getStatsAgnostic(this.stream.getRTCPeerConnection(),
(stats) => { (stats) => {
if ((platform.name!.indexOf('Chrome') !== -1) || (platform.name!.indexOf('Opera') !== -1)) { if (platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() || platform.isOperaMobileBrowser()) {
let localCandidateId, remoteCandidateId, googCandidatePair; let localCandidateId, remoteCandidateId, googCandidatePair;
const localCandidates = {}; const localCandidates = {};
const remoteCandidates = {}; const remoteCandidates = {};
@ -181,7 +184,7 @@ export class WebRtcStats {
const f = (stats) => { const f = (stats) => {
if (platform.name!.indexOf('Firefox') !== -1) { if (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) {
stats.forEach((stat) => { stats.forEach((stat) => {
let json = {}; let json = {};
@ -278,7 +281,7 @@ export class WebRtcStats {
sendPost(JSON.stringify(json)); sendPost(JSON.stringify(json));
} }
}); });
} else if ((platform.name!.indexOf('Chrome') !== -1) || (platform.name!.indexOf('Opera') !== -1)) { } else if (platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() || platform.isOperaMobileBrowser()) {
for (const key of Object.keys(stats)) { for (const key of Object.keys(stats)) {
const stat = stats[key]; const stat = stats[key];
if (stat.type === 'ssrc') { if (stat.type === 'ssrc') {
@ -377,7 +380,7 @@ export class WebRtcStats {
logger.log(response); logger.log(response);
const standardReport = {}; const standardReport = {};
if (platform.name!.indexOf('Firefox') !== -1) { if (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) {
Object.keys(response).forEach(key => { Object.keys(response).forEach(key => {
logger.log(response[key]); logger.log(response[key]);
}); });
@ -400,13 +403,13 @@ export class WebRtcStats {
} }
private getStatsAgnostic(pc, successCb, failureCb) { private getStatsAgnostic(pc, successCb, failureCb) {
if (platform.name!.indexOf('Firefox') !== -1) { if (platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) {
// getStats takes args in different order in Chrome and Firefox // getStats takes args in different order in Chrome and Firefox
return pc.getStats(null).then(response => { return pc.getStats(null).then(response => {
const report = this.standardizeReport(response); const report = this.standardizeReport(response);
successCb(report); successCb(report);
}).catch(failureCb); }).catch(failureCb);
} else if ((platform.name!.indexOf('Chrome') !== -1) || (platform.name!.indexOf('Opera') !== -1)) { } else if (platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() || platform.isOperaMobileBrowser()) {
// In Chrome, the first two arguments are reversed // In Chrome, the first two arguments are reversed
return pc.getStats((response) => { return pc.getStats((response) => {
const report = this.standardizeReport(response); const report = this.standardizeReport(response);