diff --git a/openvidu-browser/package.json b/openvidu-browser/package.json index 7db1badd..6f7ee148 100644 --- a/openvidu-browser/package.json +++ b/openvidu-browser/package.json @@ -1,7 +1,7 @@ { "author": "OpenVidu", "dependencies": { - "@types/node": "11.13.6", + "@types/node": "12.0.0", "@types/platform": "1.3.2", "freeice": "2.2.2", "hark": "1.2.3", @@ -24,8 +24,8 @@ "tsify": "4.0.1", "tslint": "5.16.0", "typedoc": "0.14.2", - "typescript": "3.4.4", - "uglify-js": "3.5.6" + "typescript": "3.4.5", + "uglify-js": "3.5.11" }, "license": "Apache-2.0", "main": "lib/index.js", diff --git a/openvidu-browser/src/OpenVidu/OpenVidu.ts b/openvidu-browser/src/OpenVidu/OpenVidu.ts index fc23effd..556ad677 100644 --- a/openvidu-browser/src/OpenVidu/OpenVidu.ts +++ b/openvidu-browser/src/OpenVidu/OpenVidu.ts @@ -19,12 +19,15 @@ import { LocalRecorder } from './LocalRecorder'; import { Publisher } from './Publisher'; import { Session } from './Session'; import { Stream } from './Stream'; +import { StreamManager } from './StreamManager'; import { StreamPropertyChangedEvent } from '../OpenViduInternal/Events/StreamPropertyChangedEvent'; import { Device } from '../OpenViduInternal/Interfaces/Public/Device'; import { OpenViduAdvancedConfiguration } from '../OpenViduInternal/Interfaces/Public/OpenViduAdvancedConfiguration'; import { PublisherProperties } from '../OpenViduInternal/Interfaces/Public/PublisherProperties'; import { OpenViduError, OpenViduErrorName } from '../OpenViduInternal/Enums/OpenViduError'; import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode'; +import { VideoElementEvent } from '../OpenViduInternal/Events/VideoElementEvent'; +import { StreamManagerEvent } from '../OpenViduInternal/Events/StreamManagerEvent'; import * as screenSharingAuto from '../OpenViduInternal/ScreenSharing/Screen-Capturing-Auto'; import * as screenSharing from '../OpenViduInternal/ScreenSharing/Screen-Capturing'; @@ -109,6 +112,7 @@ export class OpenVidu { console.info("Detected IE Explorer " + platform.version); this.importIEAdapterJS(); this.importURLLibrary(); + this.setGlobalIEFunctions(); } if (platform.os!!.family === 'iOS' || platform.os!!.family === 'Android') { @@ -781,7 +785,7 @@ export class OpenVidu { } private importURLLibrary(): void { - const moduleSpecifier = 'https://polyfill.io/v3/polyfill.min.js?features=URL'; + const moduleSpecifier = 'https://cdn.jsdelivr.net/npm/url-polyfill@1.1.5/url-polyfill.min.js'; const scriptId = 'url-script-element'; var script = document.createElement('script'); script.async = false; @@ -800,4 +804,50 @@ export class OpenVidu { } } + private setGlobalIEFunctions(): void { + // FIX: the IE plugin seems to require the handler functions to be globally accessible. Store the functions with unique streamId + + // Global handler for onloadedmetadata + (window).IEOnLoadedMetadata = (simVideo: HTMLVideoElement, str: Stream) => { + const videoDimensionsSet = () => { + str.videoDimensions = { + width: simVideo.videoWidth, + height: simVideo.videoHeight + }; + + // TODO: if screen-share, set this.screenShareResizeInterval + + str.isLocalStreamReadyToPublish = true; + str.ee.emitEvent('stream-ready-to-publish', []); + }; + let interval; + if (simVideo.videoWidth === 0) { + interval = setInterval(() => { + if (simVideo.videoWidth !== 0) { + clearInterval(interval); + videoDimensionsSet(); + } + }, 40); + } else { + videoDimensionsSet(); + } + }; + // Global handler for oncanplay + (window).IEOnCanPlay = (strManager: StreamManager) => { + if (strManager.stream.isLocal()) { + if (!strManager.stream.displayMyRemote()) { + console.info("Your local 'Stream' with id [" + strManager.stream.streamId + '] video is now playing'); + strManager.ee.emitEvent('videoPlaying', [new VideoElementEvent(strManager.videos[0].video, strManager, 'videoPlaying')]); + } else { + console.info("Your own remote 'Stream' with id [" + strManager.stream.streamId + '] video is now playing'); + strManager.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(strManager.videos[0].video, strManager, 'remoteVideoPlaying')]); + } + } else { + console.info("Remote 'Stream' with id [" + strManager.stream.streamId + '] video is now playing'); + strManager.ee.emitEvent('videoPlaying', [new VideoElementEvent(strManager.videos[0].video, strManager, 'videoPlaying')]); + } + strManager.ee.emitEvent('streamPlaying', [new StreamManagerEvent(strManager, 'streamPlaying', undefined)]); + }; + } + } \ No newline at end of file diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index 27ac6668..52c71fdc 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -322,6 +322,16 @@ export class Publisher extends StreamManager { if (platform['isInternetExplorer']) { this.videoReference = video; } + } else { + if (platform['isInternetExplorer']) { + // IE cannot have a video reference not inserted into DOM + // Pick up the first video element of videos array + this.videoReference = this.videos[0].video; + if (!this.videoReference) { + console.warn('IE requires the video element to be defined when initializing a Publisher. ' + + 'Be sure to initialize the publisher passing a pre-existing targetElement') + } + } } this.stream.setMediaStream(mediaStream); @@ -331,43 +341,15 @@ export class Publisher extends StreamManager { this.videoReference = this.customAttachMediaStreamIE(this.videoReference, mediaStream); if (this.stream.isSendVideo()) { if (!this.stream.isSendScreen()) { - /*this.videoReference.onloadedmetadata = () => { - this.stream.videoDimensions = { - width: this.videoReference.videoWidth, - height: this.videoReference.videoHeight - }; - - // TODO: if screen-share, set this.screenShareResizeInterval - - console.warn(this.stream.videoDimensions); - this.stream.isLocalStreamReadyToPublish = true; - this.stream.ee.emitEvent('stream-ready-to-publish', []); - }*/ - - this.stream.videoDimensions = { - width: this.videoReference.videoWidth, - height: this.videoReference.videoHeight - }; - - // TODO: if screen-share, set this.screenShareResizeInterval - - console.warn(this.stream.videoDimensions); - this.stream.isLocalStreamReadyToPublish = true; - this.stream.ee.emitEvent('stream-ready-to-publish', []); - - this.videoReference.onplaying = () => { - console.warn("PLAYINNNGNGNGNGNGNG!!!"); - } - + this.videoReference.addEventListener('loadedmetadata', (window).IEOnLoadedMetadata(this.videoReference, this.stream)); } } - }); } else { this.videoReference.srcObject = mediaStream; } - if (!this.stream.displayMyRemote()) { + if (!this.stream.displayMyRemote() && (platform.name !== 'IE')) { // When we are subscribed to our remote we don't still set the MediaStream object in the video elements to // avoid early 'streamPlaying' event this.stream.updateMediaStreamInVideos(); @@ -395,18 +377,18 @@ export class Publisher extends StreamManager { }; let interval; - this.videoReference.onloadedmetadata = () => { + this.videoReference.addEventListener('loadedmetadata', () => { if (this.videoReference.videoWidth === 0) { interval = setInterval(() => { if (this.videoReference.videoWidth !== 0) { - videoDimensionsSet(); clearInterval(interval); + videoDimensionsSet(); } - }, 10); + }, 40); } else { videoDimensionsSet(); } - }; + }); } else if (platform.name !== 'IE') { // Rest of platforms except IE // With no screen share, video dimension can be set directly from MediaStream (getSettings) @@ -430,7 +412,7 @@ export class Publisher extends StreamManager { } } else { // With screen share, video dimension must be got from a video element (onloadedmetadata event) - this.videoReference.onloadedmetadata = () => { + this.videoReference.addEventListener('loadedmetadata', () => { this.stream.videoDimensions = { width: this.videoReference.videoWidth, height: this.videoReference.videoHeight @@ -467,7 +449,7 @@ export class Publisher extends StreamManager { }, 500); this.stream.isLocalStreamReadyToPublish = true; this.stream.ee.emitEvent('stream-ready-to-publish', []); - }; + }); } } else { this.stream.isLocalStreamReadyToPublish = true; diff --git a/openvidu-browser/src/OpenVidu/StreamManager.ts b/openvidu-browser/src/OpenVidu/StreamManager.ts index 775d9f4a..72938f62 100644 --- a/openvidu-browser/src/OpenVidu/StreamManager.ts +++ b/openvidu-browser/src/OpenVidu/StreamManager.ts @@ -87,11 +87,11 @@ export class StreamManager implements EventDispatcher { /** * @hidden */ - protected ee = new EventEmitter(); + ee = new EventEmitter(); /** * @hidden */ - protected canPlayListener: EventListenerOrEventListenerObject; + protected canPlayListener: EventListener; /** @@ -123,21 +123,23 @@ export class StreamManager implements EventDispatcher { this.element = targEl; } } - this.canPlayListener = () => { - if (this.stream.isLocal()) { - if (!this.stream.displayMyRemote()) { - console.info("Your local 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); + if (!platform['isInternetExplorer']) { + this.canPlayListener = () => { + if (this.stream.isLocal()) { + if (!this.stream.displayMyRemote()) { + console.info("Your local 'Stream' with id [" + this.stream.streamId + '] video is now playing'); + this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); + } else { + console.info("Your own remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); + this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'remoteVideoPlaying')]); + } } else { - console.info("Your own remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('remoteVideoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'remoteVideoPlaying')]); + console.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); + this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); } - } else { - console.info("Remote 'Stream' with id [" + this.stream.streamId + '] video is now playing'); - this.ee.emitEvent('videoPlaying', [new VideoElementEvent(this.videos[0].video, this, 'videoPlaying')]); - } - this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); - }; + this.ee.emitEvent('streamPlaying', [new StreamManagerEvent(this, 'streamPlaying', undefined)]); + }; + } } /** @@ -393,7 +395,7 @@ export class StreamManager implements EventDispatcher { this.videos.forEach(streamManagerVideo => { // Remove oncanplay event listener (only OpenVidu browser one, not the user ones) - streamManagerVideo.video.removeEventListener('canplay', this.canPlayListener); + streamManagerVideo.video.removeEventListener('canplay', platform['isInternetExplorer'] ? (window).IEOnCanPlay : this.canPlayListener); if (!!streamManagerVideo.targetElement) { // Only remove from DOM videos created by OpenVidu Browser (those generated by passing a valid targetElement in OpenVidu.initPublisher // and Session.subscribe or those created by StreamManager.createVideoElement). All this videos triggered a videoElementCreated event @@ -428,7 +430,7 @@ export class StreamManager implements EventDispatcher { */ addPlayEventToFirstVideo() { if ((!!this.videos[0]) && (!!this.videos[0].video) && (this.videos[0].video.oncanplay === null)) { - this.videos[0].video.addEventListener('canplay', this.canPlayListener); + this.videos[0].video.addEventListener('canplay', platform['isInternetExplorer'] ? (window).IEOnCanPlay(this) : this.canPlayListener); } } @@ -482,6 +484,12 @@ export class StreamManager implements EventDispatcher { protected customAttachMediaStreamIE(video: HTMLVideoElement, mediaStream: MediaStream): HTMLVideoElement { var simVideo = attachMediaStream(video, mediaStream); + if (!simVideo) { + console.error('The video element used by IE to insert its custom media element is not properly added to DOM (must be inserted and visible)'); + console.error(video); + return simVideo; + } + // Replace HTMLVideoElemet (if exists) with new HTMLObjectElement returned by IE plugin for (let i = 0; i < this.videos.length; i++) { if (this.videos[i].video === video) { @@ -492,7 +500,6 @@ export class StreamManager implements EventDispatcher { // Always launch videoElementCreated event after IE plugin has inserted simulated video into DOM this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(simVideo, this, 'videoElementCreated')]); - this.addPlayEventToFirstVideo(); return simVideo; }