openvidu-browser: IExplorer support

pull/255/head
pabloFuente 2019-05-10 10:36:10 +02:00
parent 89db47dd37
commit 8f25b937e2
7 changed files with 258 additions and 94 deletions

View File

@ -96,8 +96,8 @@ export class Connection {
*/
sendIceCandidate(candidate: RTCIceCandidate): void {
console.debug((!!this.stream.outboundStreamOpts ? 'Local' : 'Remote'), 'candidate for',
this.connectionId, JSON.stringify(candidate));
console.debug((!!this.stream.outboundStreamOpts ? 'Local' : 'Remote') + 'candidate for' +
this.connectionId, candidate);
this.session.openvidu.sendRequest('onIceCandidate', {
endpointName: this.connectionId,

View File

@ -32,6 +32,9 @@ import * as screenSharing from '../OpenViduInternal/ScreenSharing/Screen-Capturi
import RpcBuilder = require('../OpenViduInternal/KurentoUtils/kurento-jsonrpc');
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isInternetExplorer'] = platform.name === 'IE' && platform.version !== undefined && parseInt(platform.version) >= 11;
platform['isReactNative'] = navigator.product === 'ReactNative';
declare const AdapterJS: any;
/**
* @hidden
@ -96,6 +99,10 @@ export class OpenVidu {
console.info("'OpenVidu' initialized");
console.info("openvidu-browser version: " + this.libraryVersion);
if (platform['isInternetExplorer']) {
this.importIEAdapterJS();
}
if (platform.os!!.family === 'iOS' || platform.os!!.family === 'Android') {
// Listen to orientationchange only on mobile devices
@ -216,12 +223,12 @@ export class OpenVidu {
properties = {
audioSource: (typeof properties.audioSource !== 'undefined') ? properties.audioSource : undefined,
frameRate: (properties.videoSource instanceof MediaStreamTrack) ? undefined : ((typeof properties.frameRate !== 'undefined') ? properties.frameRate : undefined),
frameRate: (typeof MediaStreamTrack !== 'undefined' && properties.videoSource instanceof MediaStreamTrack) ? undefined : ((typeof properties.frameRate !== 'undefined') ? properties.frameRate : undefined),
insertMode: (typeof properties.insertMode !== 'undefined') ? ((typeof properties.insertMode === 'string') ? VideoInsertMode[properties.insertMode] : properties.insertMode) : VideoInsertMode.APPEND,
mirror: (typeof properties.mirror !== 'undefined') ? properties.mirror : true,
publishAudio: (typeof properties.publishAudio !== 'undefined') ? properties.publishAudio : true,
publishVideo: (typeof properties.publishVideo !== 'undefined') ? properties.publishVideo : true,
resolution: (properties.videoSource instanceof MediaStreamTrack) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
resolution: (typeof MediaStreamTrack !== 'undefined' && properties.videoSource instanceof MediaStreamTrack) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
videoSource: (typeof properties.videoSource !== 'undefined') ? properties.videoSource : undefined,
filter: properties.filter
};
@ -325,7 +332,8 @@ export class OpenVidu {
(browser !== 'Chrome') && (browser !== 'Chrome Mobile') &&
(browser !== 'Firefox') && (browser !== 'Firefox Mobile') &&
(browser !== 'Opera') && (browser !== 'Opera Mobile') &&
(browser !== 'Android Browser')
(browser !== 'Android Browser') &&
(browser !== 'IE' || platform.version !== undefined && parseInt(platform.version) < 11)
) {
return 0;
} else {
@ -431,7 +439,9 @@ export class OpenVidu {
return new Promise<MediaStream>((resolve, reject) => {
this.generateMediaConstraints(options)
.then(constraints => {
navigator.mediaDevices.getUserMedia(constraints)
let userMediaFunc = () => {
navigator.mediaDevices.getUserMedia(constraints)
.then(mediaStream => {
resolve(mediaStream);
})
@ -445,6 +455,15 @@ export class OpenVidu {
}
reject(new OpenViduError(errorName, errorMessage));
});
}
if (platform['isInternetExplorer']) {
AdapterJS.webRTCReady(isUsingPlugin => {
userMediaFunc();
});
} else {
userMediaFunc();
}
})
.catch((error: OpenViduError) => {
reject(error);
@ -742,4 +761,19 @@ export class OpenVidu {
}
}
private importIEAdapterJS(): void {
const moduleSpecifier = 'https://cdn.temasys.io/adapterjs/0.15.x/adapter.screenshare.min.js';
//Create a script tag
var script = document.createElement('script');
// Assign a URL to the script element
script.src = moduleSpecifier;
// Get the first script tag on the page (we'll insert our new one before it)
var ref = document.querySelector('script');
// Insert the new node before the reference node
if (ref && ref.parentNode) {
ref.parentNode.insertBefore(script, ref);
console.info("Detected IE Explorer " + platform.version + ". IEAdapter imported");
}
}
}

View File

@ -30,6 +30,9 @@ import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isInternetExplorer'] = platform.name === 'IE' && platform.version !== undefined && parseInt(platform.version) >= 11;
platform['isReactNative'] = navigator.product === 'ReactNative';
declare const AdapterJS: any, attachMediaStream;
/**
* Packs local media streams. Participants can publish it to a session. Initialized with [[OpenVidu.initPublisher]] method
@ -67,6 +70,10 @@ export class Publisher extends StreamManager {
* @hidden
*/
screenShareResizeInterval: NodeJS.Timer;
/**
* @hidden
*/
IEAdapter: any;
/**
* @hidden
@ -284,12 +291,12 @@ export class Publisher extends StreamManager {
this.accessAllowed = true;
this.accessDenied = false;
if (this.properties.audioSource instanceof MediaStreamTrack) {
if (typeof MediaStreamTrack !== 'undefined' && this.properties.audioSource instanceof MediaStreamTrack) {
mediaStream.removeTrack(mediaStream.getAudioTracks()[0]);
mediaStream.addTrack((<MediaStreamTrack>this.properties.audioSource));
}
if (this.properties.videoSource instanceof MediaStreamTrack) {
if (typeof MediaStreamTrack !== 'undefined' && this.properties.videoSource instanceof MediaStreamTrack) {
mediaStream.removeTrack(mediaStream.getVideoTracks()[0]);
mediaStream.addTrack((<MediaStreamTrack>this.properties.videoSource));
}
@ -309,19 +316,62 @@ export class Publisher extends StreamManager {
if (platform.name === 'Safari') {
this.videoReference.setAttribute('playsinline', 'true');
}
this.videoReference.srcObject = mediaStream;
if (!!this.firstVideoElement) {
let video = this.createVideoElement(this.firstVideoElement.targetElement, <VideoInsertMode>this.properties.insertMode);
if (platform['isInternetExplorer']) {
this.videoReference = video;
}
}
this.stream.setMediaStream(mediaStream);
if (platform['isInternetExplorer']) {
AdapterJS.webRTCReady(isUsingPlugin => {
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!!!");
}
}
}
});
} else {
this.videoReference.srcObject = mediaStream;
}
if (!this.stream.displayMyRemote()) {
// 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();
}
if (!!this.firstVideoElement) {
this.createVideoElement(this.firstVideoElement.targetElement, <VideoInsertMode>this.properties.insertMode);
}
delete this.firstVideoElement;
if (this.stream.isSendVideo()) {
@ -357,8 +407,8 @@ export class Publisher extends StreamManager {
videoDimensionsSet();
}
};
} else {
// Rest of platforms
} else if (platform.name !== 'IE') {
// Rest of platforms except IE
// With no screen share, video dimension can be set directly from MediaStream (getSettings)
// Orientation must be checked for mobile devices (width and height are reversed)
const { width, height } = mediaStream.getVideoTracks()[0].getSettings();
@ -480,14 +530,14 @@ export class Publisher extends StreamManager {
// - video track is given and no audio
// - audio track is given and no video
// - both video and audio tracks are given
if ((this.properties.videoSource instanceof MediaStreamTrack && !this.properties.audioSource)
|| (this.properties.audioSource instanceof MediaStreamTrack && !this.properties.videoSource)
|| (this.properties.videoSource instanceof MediaStreamTrack && this.properties.audioSource instanceof MediaStreamTrack)) {
if ((typeof MediaStreamTrack !== 'undefined' && this.properties.videoSource instanceof MediaStreamTrack && !this.properties.audioSource)
|| (typeof MediaStreamTrack !== 'undefined' && this.properties.audioSource instanceof MediaStreamTrack && !this.properties.videoSource)
|| (typeof MediaStreamTrack !== 'undefined' && this.properties.videoSource instanceof MediaStreamTrack && this.properties.audioSource instanceof MediaStreamTrack)) {
const mediaStream = new MediaStream();
if (this.properties.videoSource instanceof MediaStreamTrack) {
if (typeof MediaStreamTrack !== 'undefined' && this.properties.videoSource instanceof MediaStreamTrack) {
mediaStream.addTrack((<MediaStreamTrack>this.properties.videoSource));
}
if (this.properties.audioSource instanceof MediaStreamTrack) {
if (typeof MediaStreamTrack !== 'undefined' && this.properties.audioSource instanceof MediaStreamTrack) {
mediaStream.addTrack((<MediaStreamTrack>this.properties.audioSource));
}
// MediaStreamTracks are handled within callback - just call callback with new MediaStream() and let it handle the sources
@ -521,11 +571,16 @@ export class Publisher extends StreamManager {
afterGetMedia(mediaStream, definedAudioConstraint);
});
} else {
navigator.mediaDevices.getUserMedia(constraintsAux)
let userMediaFunc = () => {
navigator.mediaDevices.getUserMedia(constraintsAux)
.then(mediaStream => {
afterGetMedia(mediaStream, definedAudioConstraint);
})
.catch(error => {
console.error(error);
this.clearPermissionDialogTimer(startTime, timeForDialogEvent);
if (error.name === 'Error') {
// Safari OverConstrainedError has as name property 'Error' instead of 'OverConstrainedError'
@ -598,6 +653,16 @@ export class Publisher extends StreamManager {
}
});
}
if (platform['isInternetExplorer']) {
AdapterJS.webRTCReady(isUsingPlugin => {
userMediaFunc();
})
} else {
userMediaFunc();
}
}
} else {
reject(new OpenViduError(OpenViduErrorName.NO_INPUT_SOURCE_SET,

View File

@ -160,7 +160,7 @@ export class Session implements EventDispatcher {
reject(error);
});
} else {
reject(new OpenViduError(OpenViduErrorName.BROWSER_NOT_SUPPORTED, 'Browser ' + platform.name + ' for ' + platform.os!!.family + ' is not supported in OpenVidu'));
reject(new OpenViduError(OpenViduErrorName.BROWSER_NOT_SUPPORTED, 'Browser ' + platform.name + ' (version ' + platform.version + ') for ' + platform.os!!.family + ' is not supported in OpenVidu'));
}
});
}
@ -882,10 +882,17 @@ export class Session implements EventDispatcher {
this.getConnection(msg.senderConnectionId, 'Connection not found for connectionId ' + msg.senderConnectionId + ' owning endpoint ' + msg.endpointName + '. Ice candidate will be ignored: ' + candidate)
.then(connection => {
const stream = connection.stream;
stream.getWebRtcPeer().addIceCandidate(candidate).catch(error => {
console.error('Error adding candidate for ' + stream.streamId
+ ' stream of endpoint ' + msg.endpointName + ': ' + error);
});
if (platform['isInternetExplorer']) {
(<any>stream.getWebRtcPeer()).addIceCandidate(candidate, () => {}, error => {
console.error('Error adding candidate for ' + stream.streamId
+ ' stream of endpoint ' + msg.endpointName + ': ' + error);
});
} else {
stream.getWebRtcPeer().addIceCandidate(candidate).catch(error => {
console.error('Error adding candidate for ' + stream.streamId
+ ' stream of endpoint ' + msg.endpointName + ': ' + error);
});
}
})
.catch(openViduError => {
console.error(openViduError);
@ -1023,10 +1030,10 @@ export class Session implements EventDispatcher {
const joinParams = {
token: (!!token) ? token : '',
session: this.sessionId,
platform: platform.description,
platform: !!platform.description ? platform.description : 'unknown',
metadata: !!this.options.metadata ? this.options.metadata : '',
secret: this.openvidu.getSecret(),
recorder: this.openvidu.getRecorder(),
recorder: this.openvidu.getRecorder()
};
this.openvidu.sendRequest('joinRoom', joinParams, (error, response) => {

View File

@ -35,6 +35,9 @@ import EventEmitter = require('wolfy87-eventemitter');
import hark = require('hark');
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isInternetExplorer'] = platform.name === 'IE' && platform.version !== undefined && parseInt(platform.version) >= 11;
platform['isReactNative'] = navigator.product === 'ReactNative';
declare const AdapterJS: any;
/**
@ -221,7 +224,7 @@ export class Stream implements EventDispatcher {
if (this.hasVideo) {
this.videoActive = !!this.outboundStreamOpts.publisherProperties.publishVideo;
this.frameRate = this.outboundStreamOpts.publisherProperties.frameRate;
if (this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack) {
if (typeof MediaStreamTrack !== 'undefined' && this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack) {
this.typeOfVideo = 'CUSTOM';
} else {
this.typeOfVideo = this.isSendScreen() ? 'SCREEN' : 'CAMERA';
@ -455,7 +458,7 @@ export class Stream implements EventDispatcher {
disposeWebRtcPeer(): void {
if (this.webRtcPeer) {
const isSenderAndCustomTrack: boolean = !!this.outboundStreamOpts &&
this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack;
typeof MediaStreamTrack !== 'undefined' && this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack;
this.webRtcPeer.dispose(isSenderAndCustomTrack);
}
if (this.speechEvent) {
@ -693,7 +696,7 @@ export class Stream implements EventDispatcher {
let typeOfVideo = '';
if (this.isSendVideo()) {
typeOfVideo = this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack ? 'CUSTOM' : (this.isSendScreen() ? 'SCREEN' : 'CAMERA');
typeOfVideo = (typeof MediaStreamTrack !== 'undefined' && this.outboundStreamOpts.publisherProperties.videoSource instanceof MediaStreamTrack) ? 'CUSTOM' : (this.isSendScreen() ? 'SCREEN' : 'CAMERA');
}
this.session.openvidu.sendRequest('publishVideo', {
@ -795,20 +798,30 @@ export class Stream implements EventDispatcher {
});
};
this.webRtcPeer = new WebRtcPeerRecvonly(options);
this.webRtcPeer.generateOffer()
.then(offer => {
successCallback(offer);
})
.catch(error => {
reject(new Error('(subscribe) SDP offer error: ' + JSON.stringify(error)));
const initWebRtcPeer = () => {
this.webRtcPeer = new WebRtcPeerRecvonly(options);
this.webRtcPeer.generateOffer()
.then(offer => {
successCallback(offer);
})
.catch(error => {
reject(new Error('(subscribe) SDP offer error: ' + JSON.stringify(error)));
});
};
if (platform['isInternetExplorer']) {
AdapterJS.webRTCReady(isUsingPlugin => {
initWebRtcPeer();
});
} else {
initWebRtcPeer();
}
});
}
private remotePeerSuccessfullyEstablished(): void {
if (platform['isIonicIos']) {
// iOS Ionic. LIMITATION: must use deprecated WebRTC API
if (platform['isIonicIos'] || platform['isInternetExplorer']) {
// iOS Ionic or IExplorer. LIMITATION: must use deprecated WebRTC API
const pc1: any = this.webRtcPeer.pc;
this.mediaStream = pc1.getRemoteStreams()[0];
} else {
@ -836,7 +849,7 @@ export class Stream implements EventDispatcher {
}
}
this.ee.emitEvent('mediastream-updated', []);
this.updateMediaStreamInVideos();
if (!this.displayMyRemote() && !!this.mediaStream.getAudioTracks()[0] && this.session.speakingEventsEnabled) {
this.enableSpeakingEvents();
}

View File

@ -26,6 +26,9 @@ import { VideoInsertMode } from '../OpenViduInternal/Enums/VideoInsertMode';
import EventEmitter = require('wolfy87-eventemitter');
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isInternetExplorer'] = platform.name === 'IE' && platform.version !== undefined && parseInt(platform.version) >= 11;
platform['isReactNative'] = navigator.product === 'ReactNative';
declare const attachMediaStream;
/**
* Interface in charge of displaying the media streams in the HTML DOM. This wraps any [[Publisher]] and [[Subscriber]] object.
@ -240,6 +243,10 @@ export class StreamManager implements EventDispatcher {
video.srcObject = this.stream.getMediaStream();
}
if (platform['isInternetExplorer'] && !!this.stream.getMediaStream()) {
video = this.customAttachMediaStreamIE(video, this.stream.getMediaStream());
}
// If the video element is already part of this StreamManager do nothing
for (const v of this.videos) {
if (v.video === video) {
@ -293,7 +300,7 @@ export class StreamManager implements EventDispatcher {
throw new Error("The provided 'targetElement' couldn't be resolved to any HTML element: " + targetElement);
}
const video = document.createElement('video');
let video = document.createElement('video');
this.initializeVideoProperties(video);
let insMode = !!insertMode ? insertMode : VideoInsertMode.APPEND;
@ -319,6 +326,10 @@ export class StreamManager implements EventDispatcher {
break;
}
if (platform['isInternetExplorer'] && !!this.stream.getMediaStream()) {
video = this.customAttachMediaStreamIE(video, this.stream.getMediaStream());
}
const v: StreamManagerVideo = {
targetElement: targEl,
video,
@ -327,9 +338,12 @@ export class StreamManager implements EventDispatcher {
};
this.pushNewStreamManagerVideo(v);
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(v.video, this, 'videoElementCreated')]);
this.lazyLaunchVideoElementCreatedEvent = !!this.firstVideoElement;
let launchVideoCreatedEvent = !platform['isInternetExplorer'];
if (launchVideoCreatedEvent) {
// For IE the event is called in this.customAttachMediaStreamIE
this.ee.emitEvent('videoElementCreated', [new VideoElementEvent(v.video, this, 'videoElementCreated')]);
}
this.lazyLaunchVideoElementCreatedEvent = !!this.firstVideoElement && launchVideoCreatedEvent;
return video;
}
@ -432,6 +446,9 @@ export class StreamManager implements EventDispatcher {
vParent!!.replaceChild(newVideo, streamManagerVideo.video);
streamManagerVideo.video = newVideo;
}
if (platform['isInternetExplorer']) {
this.customAttachMediaStreamIE(streamManagerVideo.video, mediaStream);
}
});
}
@ -462,4 +479,21 @@ export class StreamManager implements EventDispatcher {
video.style.webkitTransform = 'unset';
}
protected customAttachMediaStreamIE(video: HTMLVideoElement, mediaStream: MediaStream): HTMLVideoElement {
var simVideo = attachMediaStream(video, mediaStream);
// 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) {
this.videos[i].video = simVideo;
break;
}
}
// 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;
}
}

View File

@ -19,6 +19,8 @@ import freeice = require('freeice');
import uuid = require('uuid');
import platform = require('platform');
platform['isIonicIos'] = (platform.product === 'iPhone' || platform.product === 'iPad') && platform.ua!!.indexOf('Safari') === -1;
platform['isInternetExplorer'] = platform.name === 'IE' && platform.version !== undefined && parseInt(platform.version) >= 11;
platform['isReactNative'] = navigator.product === 'ReactNative';
export interface WebRtcPeerConfiguration {
mediaConstraints: {
@ -66,7 +68,11 @@ export class WebRtcPeer {
this.pc.onsignalingstatechange = () => {
if (this.pc.signalingState === 'stable') {
while (this.iceCandidateList.length > 0) {
this.pc.addIceCandidate(<RTCIceCandidate>this.iceCandidateList.shift());
if (platform['isInternetExplorer']) {
(<any>this.pc).addIceCandidate(<RTCIceCandidate>this.iceCandidateList.shift(), () => {}, () => {});
} else {
this.pc.addIceCandidate(<RTCIceCandidate>this.iceCandidateList.shift());
}
}
}
};
@ -87,8 +93,8 @@ export class WebRtcPeer {
reject('The peer connection object is in "closed" state. This is most likely due to an invocation of the dispose method before accepting in the dialogue');
}
if (!!this.configuration.mediaStream) {
if (platform['isIonicIos']) {
// iOS Ionic. LIMITATION: must use deprecated WebRTC API
if (platform['isIonicIos'] || platform['isInternetExplorer']) {
// iOS Ionic and IExplorer. LIMITATION: must use deprecated WebRTC API
const pc2: any = this.pc;
pc2.addStream(this.configuration.mediaStream);
} else {
@ -114,8 +120,8 @@ export class WebRtcPeer {
this.remoteCandidatesQueue = [];
this.localCandidatesQueue = [];
if (platform['isIonicIos']) {
// iOS Ionic. LIMITATION: must use deprecated WebRTC API
if (platform['isIonicIos'] || platform['isInternetExplorer']) {
// iOS Ionic or IExplorer. LIMITATION: must use deprecated WebRTC API
// Stop senders deprecated
const pc1: any = this.pc;
for (const sender of pc1.getLocalStreams()) {
@ -156,7 +162,7 @@ export class WebRtcPeer {
}
/**
* 1) Function that creates an offer, sets it as local description and returns the offer param
* Function that creates an offer, sets it as local description and returns the offer param
* to send to OpenVidu Server (will be the remote description of other peer)
*/
generateOffer(): Promise<string> {
@ -209,11 +215,43 @@ export class WebRtcPeer {
}
})
.catch(error => reject(error));
} else if (platform['isInternetExplorer']) {
// IE Explorer cannot use Promise base API
let setLocalDescriptionOnSuccess = () => {
const localDescription = this.pc.localDescription;
if (!!localDescription) {
console.debug('Local description set', localDescription.sdp);
resolve(localDescription.sdp);
} else {
reject('Local description is not defined');
}
}
let setLocalDescriptionOnError = error => {
reject(error);
}
let createOfferOnSuccess = offer => {
console.debug('Created SDP offer');
(<any>this.pc).setLocalDescription(offer, setLocalDescriptionOnSuccess, setLocalDescriptionOnError);
};
let createOfferOnError = error => {
reject(error);
};
// FIX: for IExplorer WebRTC peer connections must be negotiated to receive video and audio
constraints.offerToReceiveAudio = true;
constraints.offerToReceiveVideo = true;
(<any>this.pc).createOffer(createOfferOnSuccess, createOfferOnError, constraints);
} else {
// Rest of platforms
this.pc.createOffer(constraints).then(offer => {
console.debug('Created SDP offer');
return this.pc.setLocalDescription(offer);
}).then(() => {
})
.then(() => {
const localDescription = this.pc.localDescription;
if (!!localDescription) {
console.debug('Local description set', localDescription.sdp);
@ -222,58 +260,21 @@ export class WebRtcPeer {
reject('Local description is not defined');
}
})
.catch(error => reject(error));
.catch(error => reject(error));
}
});
}
/**
* 2) Function to invoke when a SDP offer is received. Sets it as remote description,
* generates and answer and returns it to send it to OpenVidu Server
*/
processOffer(sdpOffer: string): Promise<ConstrainDOMString> {
return new Promise((resolve, reject) => {
const offer: RTCSessionDescriptionInit = {
type: 'offer',
sdp: sdpOffer
};
console.debug('SDP offer received, setting remote description');
if (this.pc.signalingState === 'closed') {
reject('PeerConnection is closed');
}
this.pc.setRemoteDescription(offer)
.then(() => {
return this.pc.createAnswer();
}).then(answer => {
console.debug('Created SDP answer');
return this.pc.setLocalDescription(answer);
}).then(() => {
const localDescription = this.pc.localDescription;
if (!!localDescription) {
console.debug('Local description set', localDescription.sdp);
resolve(<string>localDescription.sdp);
} else {
reject('Local description is not defined');
}
}).catch(error => reject(error));
});
}
/**
* 3) Function invoked when a SDP answer is received. Final step in SDP negotiation, the peer
* Function invoked when a SDP answer is received. Final step in SDP negotiation, the peer
* just needs to set the answer as its remote description
*/
processAnswer(sdpAnswer: string, needsTimeoutOnProcessAswer: boolean): Promise<string> {
return new Promise((resolve, reject) => {
const answer: RTCSessionDescriptionInit = {
type: 'answer',
sdp: sdpAnswer
};
console.debug('SDP answer received, setting remote description');
if (this.pc.signalingState === 'closed') {
@ -285,7 +286,13 @@ export class WebRtcPeer {
this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error));
}, 250);
} else {
this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error));
if (platform['isInternetExplorer']) {
// IE Explorer cannot use Promise base API
(<any>this.pc).setRemoteDescription(answer, resolve(), error => reject(error));
} else {
// Rest of platforms
this.pc.setRemoteDescription(answer).then(() => resolve()).catch(error => reject(error));
}
}
});
}
@ -303,7 +310,11 @@ export class WebRtcPeer {
break;
case 'stable':
if (!!this.pc.remoteDescription) {
this.pc.addIceCandidate(iceCandidate).then(() => resolve()).catch(error => reject(error));
if (platform['isInternetExplorer']) {
(<any>this.pc).addIceCandidate(iceCandidate, () => resolve(), error => reject(error));
} else {
this.pc.addIceCandidate(iceCandidate).then(() => resolve()).catch(error => reject(error));
}
}
break;
default: