\n"
/***/ }),
/***/ 298:
/***/ (function(module, exports) {
function Mapper() {
var sources = {};
this.forEach = function (callback) {
for (var key in sources) {
var source = sources[key];
for (var key2 in source)
callback(source[key2]);
}
;
};
this.get = function (id, source) {
var ids = sources[source];
if (ids == undefined)
return undefined;
return ids[id];
};
this.remove = function (id, source) {
var ids = sources[source];
if (ids == undefined)
return;
delete ids[id];
// Check it's empty
for (var i in ids) {
return false;
}
delete sources[source];
};
this.set = function (value, id, source) {
if (value == undefined)
return this.remove(id, source);
var ids = sources[source];
if (ids == undefined)
sources[source] = ids = {};
ids[id] = value;
};
}
;
Mapper.prototype.pop = function (id, source) {
var value = this.get(id, source);
if (value == undefined)
return undefined;
this.remove(id, source);
return value;
};
module.exports = Mapper;
/***/ }),
/***/ 299:
/***/ (function(module, exports, __webpack_require__) {
/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* 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.
*
*/
var JsonRpcClient = __webpack_require__(300);
exports.JsonRpcClient = JsonRpcClient;
/***/ }),
/***/ 300:
/***/ (function(module, exports, __webpack_require__) {
/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* 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.
*
*/
var RpcBuilder = __webpack_require__(137);
var WebSocketWithReconnection = __webpack_require__(136);
Date.now = Date.now || function () {
return +new Date;
};
var PING_INTERVAL = 5000;
var RECONNECTING = 'RECONNECTING';
var CONNECTED = 'CONNECTED';
var DISCONNECTED = 'DISCONNECTED';
var Logger = console;
/**
*
* heartbeat: interval in ms for each heartbeat message,
* sendCloseMessage : true / false, before closing the connection, it sends a closeSession message
*
* ws : {
* uri : URI to conntect to,
* useSockJS : true (use SockJS) / false (use WebSocket) by default,
* onconnected : callback method to invoke when connection is successful,
* ondisconnect : callback method to invoke when the connection is lost,
* onreconnecting : callback method to invoke when the client is reconnecting,
* onreconnected : callback method to invoke when the client succesfully reconnects,
* onerror : callback method to invoke when there is an error
* },
* rpc : {
* requestTimeout : timeout for a request,
* sessionStatusChanged: callback method for changes in session status,
* mediaRenegotiation: mediaRenegotiation
* }
*
*/
function JsonRpcClient(configuration) {
var self = this;
var wsConfig = configuration.ws;
var notReconnectIfNumLessThan = -1;
var pingNextNum = 0;
var enabledPings = true;
var pingPongStarted = false;
var pingInterval;
var status = DISCONNECTED;
var onreconnecting = wsConfig.onreconnecting;
var onreconnected = wsConfig.onreconnected;
var onconnected = wsConfig.onconnected;
var onerror = wsConfig.onerror;
configuration.rpc.pull = function (params, request) {
request.reply(null, "push");
};
wsConfig.onreconnecting = function () {
Logger.debug("--------- ONRECONNECTING -----------");
if (status === RECONNECTING) {
Logger.error("Websocket already in RECONNECTING state when receiving a new ONRECONNECTING message. Ignoring it");
return;
}
status = RECONNECTING;
if (onreconnecting) {
onreconnecting();
}
};
wsConfig.onreconnected = function () {
Logger.debug("--------- ONRECONNECTED -----------");
if (status === CONNECTED) {
Logger.error("Websocket already in CONNECTED state when receiving a new ONRECONNECTED message. Ignoring it");
return;
}
status = CONNECTED;
enabledPings = true;
updateNotReconnectIfLessThan();
usePing();
if (onreconnected) {
onreconnected();
}
};
wsConfig.onconnected = function () {
Logger.debug("--------- ONCONNECTED -----------");
if (status === CONNECTED) {
Logger.error("Websocket already in CONNECTED state when receiving a new ONCONNECTED message. Ignoring it");
return;
}
status = CONNECTED;
enabledPings = true;
usePing();
if (onconnected) {
onconnected();
}
};
wsConfig.onerror = function (error) {
Logger.debug("--------- ONERROR -----------");
status = DISCONNECTED;
if (onerror) {
onerror(error);
}
};
var ws = new WebSocketWithReconnection(wsConfig);
Logger.debug('Connecting websocket to URI: ' + wsConfig.uri);
var rpcBuilderOptions = {
request_timeout: configuration.rpc.requestTimeout,
ping_request_timeout: configuration.rpc.heartbeatRequestTimeout
};
var rpc = new RpcBuilder(RpcBuilder.packers.JsonRPC, rpcBuilderOptions, ws, function (request) {
Logger.debug('Received request: ' + JSON.stringify(request));
try {
var func = configuration.rpc[request.method];
if (func === undefined) {
Logger.error("Method " + request.method + " not registered in client");
}
else {
func(request.params, request);
}
}
catch (err) {
Logger.error('Exception processing request: ' + JSON.stringify(request));
Logger.error(err);
}
});
this.send = function (method, params, callback) {
if (method !== 'ping') {
Logger.debug('Request: method:' + method + " params:" + JSON.stringify(params));
}
var requestTime = Date.now();
rpc.encode(method, params, function (error, result) {
if (error) {
try {
Logger.error("ERROR:" + error.message + " in Request: method:" +
method + " params:" + JSON.stringify(params) + " request:" +
error.request);
if (error.data) {
Logger.error("ERROR DATA:" + JSON.stringify(error.data));
}
}
catch (e) { }
error.requestTime = requestTime;
}
if (callback) {
if (result != undefined && result.value !== 'pong') {
Logger.debug('Response: ' + JSON.stringify(result));
}
callback(error, result);
}
});
};
function updateNotReconnectIfLessThan() {
Logger.debug("notReconnectIfNumLessThan = " + pingNextNum + ' (old=' +
notReconnectIfNumLessThan + ')');
notReconnectIfNumLessThan = pingNextNum;
}
function sendPing() {
if (enabledPings) {
var params = null;
if (pingNextNum == 0 || pingNextNum == notReconnectIfNumLessThan) {
params = {
interval: configuration.heartbeat || PING_INTERVAL
};
}
pingNextNum++;
self.send('ping', params, (function (pingNum) {
return function (error, result) {
if (error) {
Logger.debug("Error in ping request #" + pingNum + " (" +
error.message + ")");
if (pingNum > notReconnectIfNumLessThan) {
enabledPings = false;
updateNotReconnectIfLessThan();
Logger.debug("Server did not respond to ping message #" +
pingNum + ". Reconnecting... ");
ws.reconnectWs();
}
}
};
})(pingNextNum));
}
else {
Logger.debug("Trying to send ping, but ping is not enabled");
}
}
/*
* If configuration.hearbeat has any value, the ping-pong will work with the interval
* of configuration.hearbeat
*/
function usePing() {
if (!pingPongStarted) {
Logger.debug("Starting ping (if configured)");
pingPongStarted = true;
if (configuration.heartbeat != undefined) {
pingInterval = setInterval(sendPing, configuration.heartbeat);
sendPing();
}
}
}
this.close = function () {
Logger.debug("Closing jsonRpcClient explicitly by client");
if (pingInterval != undefined) {
Logger.debug("Clearing ping interval");
clearInterval(pingInterval);
}
pingPongStarted = false;
enabledPings = false;
if (configuration.sendCloseMessage) {
Logger.debug("Sending close message");
this.send('closeSession', null, function (error, result) {
if (error) {
Logger.error("Error sending close message: " + JSON.stringify(error));
}
ws.close();
});
}
else {
ws.close();
}
};
// This method is only for testing
this.forceClose = function (millis) {
ws.forceClose(millis);
};
this.reconnect = function () {
ws.reconnectWs();
};
}
module.exports = JsonRpcClient;
/***/ }),
/***/ 301:
/***/ (function(module, exports, __webpack_require__) {
/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* 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.
*
*/
var WebSocketWithReconnection = __webpack_require__(136);
exports.WebSocketWithReconnection = WebSocketWithReconnection;
/***/ }),
/***/ 302:
/***/ (function(module, exports) {
/**
* JsonRPC 2.0 packer
*/
/**
* Pack a JsonRPC 2.0 message
*
* @param {Object} message - object to be packaged. It requires to have all the
* fields needed by the JsonRPC 2.0 message that it's going to be generated
*
* @return {String} - the stringified JsonRPC 2.0 message
*/
function pack(message, id) {
var result = {
jsonrpc: "2.0"
};
// Request
if (message.method) {
result.method = message.method;
if (message.params)
result.params = message.params;
// Request is a notification
if (id != undefined)
result.id = id;
}
else if (id != undefined) {
if (message.error) {
if (message.result !== undefined)
throw new TypeError("Both result and error are defined");
result.error = message.error;
}
else if (message.result !== undefined)
result.result = message.result;
else
throw new TypeError("No result or error is defined");
result.id = id;
}
;
return JSON.stringify(result);
}
;
/**
* Unpack a JsonRPC 2.0 message
*
* @param {String} message - string with the content of the JsonRPC 2.0 message
*
* @throws {TypeError} - Invalid JsonRPC version
*
* @return {Object} - object filled with the JsonRPC 2.0 message content
*/
function unpack(message) {
var result = message;
if (typeof message === 'string' || message instanceof String) {
result = JSON.parse(message);
}
// Check if it's a valid message
var version = result.jsonrpc;
if (version !== '2.0')
throw new TypeError("Invalid JsonRPC version '" + version + "': " + message);
// Response
if (result.method == undefined) {
if (result.id == undefined)
throw new TypeError("Invalid message: " + message);
var result_defined = result.result !== undefined;
var error_defined = result.error !== undefined;
// Check only result or error is defined, not both or none
if (result_defined && error_defined)
throw new TypeError("Both result and error are defined: " + message);
if (!result_defined && !error_defined)
throw new TypeError("No result or error is defined: " + message);
result.ack = result.id;
delete result.id;
}
// Return unpacked message
return result;
}
;
exports.pack = pack;
exports.unpack = unpack;
/***/ }),
/***/ 303:
/***/ (function(module, exports) {
function pack(message) {
throw new TypeError("Not yet implemented");
}
;
function unpack(message) {
throw new TypeError("Not yet implemented");
}
;
exports.pack = pack;
exports.unpack = unpack;
/***/ }),
/***/ 304:
/***/ (function(module, exports, __webpack_require__) {
var JsonRPC = __webpack_require__(302);
var XmlRPC = __webpack_require__(303);
exports.JsonRPC = JsonRPC;
exports.XmlRPC = XmlRPC;
/***/ }),
/***/ 305:
/***/ (function(module, exports, __webpack_require__) {
/*
* (C) Copyright 2014-2015 Kurento (http://kurento.org/)
*
* 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.
*/
var freeice = __webpack_require__(229);
var inherits = __webpack_require__(117);
var UAParser = __webpack_require__(312);
var uuid = __webpack_require__(314);
var hark = __webpack_require__(231);
var EventEmitter = __webpack_require__(116).EventEmitter;
var recursive = __webpack_require__(235).recursive.bind(undefined, true);
var sdpTranslator = __webpack_require__(294);
var logger = window.Logger || console;
// var gUM = navigator.mediaDevices.getUserMedia || function (constraints) {
// return new Promise(navigator.getUserMedia(constraints, function (stream) {
// videoStream = stream
// start()
// }).eror(callback));
// }
try {
__webpack_require__(234);
}
catch (error) {
if (typeof getScreenConstraints === 'undefined') {
logger.warn('screen sharing is not available');
getScreenConstraints = function getScreenConstraints(sendSource, callback) {
callback(new Error("This library is not enabled for screen sharing"));
};
}
}
var MEDIA_CONSTRAINTS = {
audio: true,
video: {
width: 640,
framerate: 15
}
};
// Somehow, the UAParser constructor gets an empty window object.
// We need to pass the user agent string in order to get information
var ua = (window && window.navigator) ? window.navigator.userAgent : '';
var parser = new UAParser(ua);
var browser = parser.getBrowser();
var usePlanB = false;
if (browser.name === 'Chrome' || browser.name === 'Chromium') {
logger.debug(browser.name + ": using SDP PlanB");
usePlanB = true;
}
function noop(error) {
if (error)
logger.error(error);
}
function trackStop(track) {
track.stop && track.stop();
}
function streamStop(stream) {
stream.getTracks().forEach(trackStop);
}
/**
* Returns a string representation of a SessionDescription object.
*/
var dumpSDP = function (description) {
if (typeof description === 'undefined' || description === null) {
return '';
}
return 'type: ' + description.type + '\r\n' + description.sdp;
};
function bufferizeCandidates(pc, onerror) {
var candidatesQueue = [];
pc.addEventListener('signalingstatechange', function () {
if (this.signalingState === 'stable') {
while (candidatesQueue.length) {
var entry = candidatesQueue.shift();
this.addIceCandidate(entry.candidate, entry.callback, entry.callback);
}
}
});
return function (candidate, callback) {
callback = callback || onerror;
switch (pc.signalingState) {
case 'closed':
callback(new Error('PeerConnection object is closed'));
break;
case 'stable':
if (pc.remoteDescription) {
pc.addIceCandidate(candidate, callback, callback);
break;
}
default:
candidatesQueue.push({
candidate: candidate,
callback: callback
});
}
};
}
/* Simulcast utilities */
function removeFIDFromOffer(sdp) {
var n = sdp.indexOf("a=ssrc-group:FID");
if (n > 0) {
return sdp.slice(0, n);
}
else {
return sdp;
}
}
function getSimulcastInfo(videoStream) {
var videoTracks = videoStream.getVideoTracks();
if (!videoTracks.length) {
logger.warn('No video tracks available in the video stream');
return '';
}
var lines = [
'a=x-google-flag:conference',
'a=ssrc-group:SIM 1 2 3',
'a=ssrc:1 cname:localVideo',
'a=ssrc:1 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:1 mslabel:' + videoStream.id,
'a=ssrc:1 label:' + videoTracks[0].id,
'a=ssrc:2 cname:localVideo',
'a=ssrc:2 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:2 mslabel:' + videoStream.id,
'a=ssrc:2 label:' + videoTracks[0].id,
'a=ssrc:3 cname:localVideo',
'a=ssrc:3 msid:' + videoStream.id + ' ' + videoTracks[0].id,
'a=ssrc:3 mslabel:' + videoStream.id,
'a=ssrc:3 label:' + videoTracks[0].id
];
lines.push('');
return lines.join('\n');
}
/**
* Wrapper object of an RTCPeerConnection. This object is aimed to simplify the
* development of WebRTC-based applications.
*
* @constructor module:kurentoUtils.WebRtcPeer
*
* @param {String} mode Mode in which the PeerConnection will be configured.
* Valid values are: 'recv', 'send', and 'sendRecv'
* @param localVideo Video tag for the local stream
* @param remoteVideo Video tag for the remote stream
* @param {MediaStream} videoStream Stream to be used as primary source
* (typically video and audio, or only video if combined with audioStream) for
* localVideo and to be added as stream to the RTCPeerConnection
* @param {MediaStream} audioStream Stream to be used as second source
* (typically for audio) for localVideo and to be added as stream to the
* RTCPeerConnection
*/
function WebRtcPeer(mode, options, callback) {
if (!(this instanceof WebRtcPeer)) {
return new WebRtcPeer(mode, options, callback);
}
WebRtcPeer.super_.call(this);
if (options instanceof Function) {
callback = options;
options = undefined;
}
options = options || {};
callback = (callback || noop).bind(this);
var self = this;
var localVideo = options.localVideo;
var remoteVideo = options.remoteVideo;
var videoStream = options.videoStream;
var audioStream = options.audioStream;
var mediaConstraints = options.mediaConstraints;
var connectionConstraints = options.connectionConstraints;
var pc = options.peerConnection;
var sendSource = options.sendSource || 'webcam';
var dataChannelConfig = options.dataChannelConfig;
var useDataChannels = options.dataChannels || false;
var dataChannel;
var guid = uuid.v4();
var configuration = recursive({
iceServers: freeice()
}, options.configuration);
var onicecandidate = options.onicecandidate;
if (onicecandidate)
this.on('icecandidate', onicecandidate);
var oncandidategatheringdone = options.oncandidategatheringdone;
if (oncandidategatheringdone) {
this.on('candidategatheringdone', oncandidategatheringdone);
}
var simulcast = options.simulcast;
var multistream = options.multistream;
var interop = new sdpTranslator.Interop();
var candidatesQueueOut = [];
var candidategatheringdone = false;
Object.defineProperties(this, {
'peerConnection': {
get: function () {
return pc;
}
},
'id': {
value: options.id || guid,
writable: false
},
'remoteVideo': {
get: function () {
return remoteVideo;
}
},
'localVideo': {
get: function () {
return localVideo;
}
},
'dataChannel': {
get: function () {
return dataChannel;
}
},
/**
* @member {(external:ImageData|undefined)} currentFrame
*/
'currentFrame': {
get: function () {
// [ToDo] Find solution when we have a remote stream but we didn't set
// a remoteVideo tag
if (!remoteVideo)
return;
if (remoteVideo.readyState < remoteVideo.HAVE_CURRENT_DATA)
throw new Error('No video stream data available');
var canvas = document.createElement('canvas');
canvas.width = remoteVideo.videoWidth;
canvas.height = remoteVideo.videoHeight;
canvas.getContext('2d').drawImage(remoteVideo, 0, 0);
return canvas;
}
}
});
// Init PeerConnection
if (!pc) {
pc = new RTCPeerConnection(configuration);
if (useDataChannels && !dataChannel) {
var dcId = 'WebRtcPeer-' + self.id;
var dcOptions = undefined;
if (dataChannelConfig) {
dcId = dataChannelConfig.id || dcId;
dcOptions = dataChannelConfig.options;
}
dataChannel = pc.createDataChannel(dcId, dcOptions);
if (dataChannelConfig) {
dataChannel.onopen = dataChannelConfig.onopen;
dataChannel.onclose = dataChannelConfig.onclose;
dataChannel.onmessage = dataChannelConfig.onmessage;
dataChannel.onbufferedamountlow = dataChannelConfig.onbufferedamountlow;
dataChannel.onerror = dataChannelConfig.onerror || noop;
}
}
}
pc.addEventListener('icecandidate', function (event) {
var candidate = event.candidate;
if (EventEmitter.listenerCount(self, 'icecandidate') ||
EventEmitter.listenerCount(self, 'candidategatheringdone')) {
if (candidate) {
var cand;
if (multistream && usePlanB) {
cand = interop.candidateToUnifiedPlan(candidate);
}
else {
cand = candidate;
}
self.emit('icecandidate', cand);
candidategatheringdone = false;
}
else if (!candidategatheringdone) {
self.emit('candidategatheringdone');
candidategatheringdone = true;
}
}
else if (!candidategatheringdone) {
// Not listening to 'icecandidate' or 'candidategatheringdone' events, queue
// the candidate until one of them is listened
candidatesQueueOut.push(candidate);
if (!candidate)
candidategatheringdone = true;
}
});
pc.ontrack = options.onaddstream;
pc.onnegotiationneeded = options.onnegotiationneeded;
this.on('newListener', function (event, listener) {
if (event === 'icecandidate' || event === 'candidategatheringdone') {
while (candidatesQueueOut.length) {
var candidate = candidatesQueueOut.shift();
if (!candidate === (event === 'candidategatheringdone')) {
listener(candidate);
}
}
}
});
var addIceCandidate = bufferizeCandidates(pc);
/**
* Callback function invoked when an ICE candidate is received. Developers are
* expected to invoke this function in order to complete the SDP negotiation.
*
* @function module:kurentoUtils.WebRtcPeer.prototype.addIceCandidate
*
* @param iceCandidate - Literal object with the ICE candidate description
* @param callback - Called when the ICE candidate has been added.
*/
this.addIceCandidate = function (iceCandidate, callback) {
var candidate;
if (multistream && usePlanB) {
candidate = interop.candidateToPlanB(iceCandidate);
}
else {
candidate = new RTCIceCandidate(iceCandidate);
}
logger.debug('Remote ICE candidate received', iceCandidate);
callback = (callback || noop).bind(this);
addIceCandidate(candidate, callback);
};
this.generateOffer = function (callback) {
callback = callback.bind(this);
var offerAudio = true;
var offerVideo = true;
// Constraints must have both blocks
if (mediaConstraints) {
offerAudio = (typeof mediaConstraints.audio === 'boolean') ?
mediaConstraints.audio : true;
offerVideo = (typeof mediaConstraints.video === 'boolean') ?
mediaConstraints.video : true;
}
var browserDependantConstraints = {
offerToReceiveAudio: (mode !== 'sendonly' && offerAudio),
offerToReceiveVideo: (mode !== 'sendonly' && offerVideo)
};
//FIXME: clarify possible constraints passed to createOffer()
/*var constraints = recursive(browserDependantConstraints,
connectionConstraints)*/
var constraints = browserDependantConstraints;
logger.debug('constraints: ' + JSON.stringify(constraints));
pc.createOffer(constraints).then(function (offer) {
logger.debug('Created SDP offer');
offer = mangleSdpToAddSimulcast(offer);
return pc.setLocalDescription(offer);
}).then(function () {
var localDescription = pc.localDescription;
logger.debug('Local description set', localDescription.sdp);
if (multistream && usePlanB) {
localDescription = interop.toUnifiedPlan(localDescription);
logger.debug('offer::origPlanB->UnifiedPlan', dumpSDP(localDescription));
}
callback(null, localDescription.sdp, self.processAnswer.bind(self));
}).catch(callback);
};
this.getLocalSessionDescriptor = function () {
return pc.localDescription;
};
this.getRemoteSessionDescriptor = function () {
return pc.remoteDescription;
};
function setRemoteVideo() {
if (remoteVideo) {
var stream = pc.getRemoteStreams()[0];
var url = stream ? URL.createObjectURL(stream) : '';
remoteVideo.pause();
remoteVideo.src = url;
remoteVideo.load();
logger.debug('Remote URL:', url);
}
}
this.showLocalVideo = function () {
localVideo.src = URL.createObjectURL(videoStream);
localVideo.muted = true;
};
this.send = function (data) {
if (dataChannel && dataChannel.readyState === 'open') {
dataChannel.send(data);
}
else {
logger.warn('Trying to send data over a non-existing or closed data channel');
}
};
/**
* Callback function invoked when a SDP answer is received. Developers are
* expected to invoke this function in order to complete the SDP negotiation.
*
* @function module:kurentoUtils.WebRtcPeer.prototype.processAnswer
*
* @param sdpAnswer - Description of sdpAnswer
* @param callback -
* Invoked after the SDP answer is processed, or there is an error.
*/
this.processAnswer = function (sdpAnswer, callback) {
callback = (callback || noop).bind(this);
var answer = new RTCSessionDescription({
type: 'answer',
sdp: sdpAnswer
});
if (multistream && usePlanB) {
var planBAnswer = interop.toPlanB(answer);
logger.debug('asnwer::planB', dumpSDP(planBAnswer));
answer = planBAnswer;
}
logger.debug('SDP answer received, setting remote description');
if (pc.signalingState === 'closed') {
return callback('PeerConnection is closed');
}
pc.setRemoteDescription(answer, function () {
setRemoteVideo();
callback();
}, callback);
};
/**
* Callback function invoked when a SDP offer is received. Developers are
* expected to invoke this function in order to complete the SDP negotiation.
*
* @function module:kurentoUtils.WebRtcPeer.prototype.processOffer
*
* @param sdpOffer - Description of sdpOffer
* @param callback - Called when the remote description has been set
* successfully.
*/
this.processOffer = function (sdpOffer, callback) {
callback = callback.bind(this);
var offer = new RTCSessionDescription({
type: 'offer',
sdp: sdpOffer
});
if (multistream && usePlanB) {
var planBOffer = interop.toPlanB(offer);
logger.debug('offer::planB', dumpSDP(planBOffer));
offer = planBOffer;
}
logger.debug('SDP offer received, setting remote description');
if (pc.signalingState === 'closed') {
return callback('PeerConnection is closed');
}
pc.setRemoteDescription(offer).then(function () {
return setRemoteVideo();
}).then(function () {
return pc.createAnswer();
}).then(function (answer) {
answer = mangleSdpToAddSimulcast(answer);
logger.debug('Created SDP answer');
return pc.setLocalDescription(answer);
}).then(function () {
var localDescription = pc.localDescription;
if (multistream && usePlanB) {
localDescription = interop.toUnifiedPlan(localDescription);
logger.debug('answer::origPlanB->UnifiedPlan', dumpSDP(localDescription));
}
logger.debug('Local description set', localDescription.sdp);
callback(null, localDescription.sdp);
}).catch(callback);
};
function mangleSdpToAddSimulcast(answer) {
if (simulcast) {
if (browser.name === 'Chrome' || browser.name === 'Chromium') {
logger.debug('Adding multicast info');
answer = new RTCSessionDescription({
'type': answer.type,
'sdp': removeFIDFromOffer(answer.sdp) + getSimulcastInfo(videoStream)
});
}
else {
logger.warn('Simulcast is only available in Chrome browser.');
}
}
return answer;
}
/**
* This function creates the RTCPeerConnection object taking into account the
* properties received in the constructor. It starts the SDP negotiation
* process: generates the SDP offer and invokes the onsdpoffer callback. This
* callback is expected to send the SDP offer, in order to obtain an SDP
* answer from another peer.
*/
function start() {
if (pc.signalingState === 'closed') {
callback('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 (videoStream && localVideo) {
self.showLocalVideo();
}
if (videoStream) {
pc.addStream(videoStream);
}
if (audioStream) {
pc.addStream(audioStream);
}
// [Hack] https://code.google.com/p/chromium/issues/detail?id=443558
var browser = parser.getBrowser();
if (mode === 'sendonly' &&
(browser.name === 'Chrome' || browser.name === 'Chromium') &&
browser.major === 39) {
mode = 'sendrecv';
}
callback();
}
if (mode !== 'recvonly' && !videoStream && !audioStream) {
function getMedia(constraints) {
if (constraints === undefined) {
constraints = MEDIA_CONSTRAINTS;
}
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
videoStream = stream;
start();
}).catch(callback);
}
if (sendSource === 'webcam') {
getMedia(mediaConstraints);
}
else {
getScreenConstraints(sendSource, function (error, constraints_) {
if (error)
return callback(error);
constraints = [mediaConstraints];
constraints.unshift(constraints_);
getMedia(recursive.apply(undefined, constraints));
}, guid);
}
}
else {
setTimeout(start, 0);
}
this.on('_dispose', function () {
if (localVideo) {
localVideo.pause();
localVideo.src = '';
localVideo.load();
//Unmute local video in case the video tag is later used for remote video
localVideo.muted = false;
}
if (remoteVideo) {
remoteVideo.pause();
remoteVideo.src = '';
remoteVideo.load();
}
self.removeAllListeners();
if (window.cancelChooseDesktopMedia !== undefined) {
window.cancelChooseDesktopMedia(guid);
}
});
}
inherits(WebRtcPeer, EventEmitter);
function createEnableDescriptor(type) {
var method = 'get' + type + 'Tracks';
return {
enumerable: true,
get: function () {
// [ToDo] Should return undefined if not all tracks have the same value?
if (!this.peerConnection)
return;
var streams = this.peerConnection.getLocalStreams();
if (!streams.length)
return;
for (var i = 0, stream; stream = streams[i]; i++) {
var tracks = stream[method]();
for (var j = 0, track; track = tracks[j]; j++)
if (!track.enabled)
return false;
}
return true;
},
set: function (value) {
function trackSetEnable(track) {
track.enabled = value;
}
this.peerConnection.getLocalStreams().forEach(function (stream) {
stream[method]().forEach(trackSetEnable);
});
}
};
}
Object.defineProperties(WebRtcPeer.prototype, {
'enabled': {
enumerable: true,
get: function () {
return this.audioEnabled && this.videoEnabled;
},
set: function (value) {
this.audioEnabled = this.videoEnabled = value;
}
},
'audioEnabled': createEnableDescriptor('Audio'),
'videoEnabled': createEnableDescriptor('Video')
});
WebRtcPeer.prototype.getLocalStream = function (index) {
if (this.peerConnection) {
return this.peerConnection.getLocalStreams()[index || 0];
}
};
WebRtcPeer.prototype.getRemoteStream = function (index) {
if (this.peerConnection) {
return this.peerConnection.getRemoteStreams()[index || 0];
}
};
/**
* @description This method frees the resources used by WebRtcPeer.
*
* @function module:kurentoUtils.WebRtcPeer.prototype.dispose
*/
WebRtcPeer.prototype.dispose = function () {
logger.debug('Disposing WebRtcPeer');
var pc = this.peerConnection;
var dc = this.dataChannel;
try {
if (dc) {
if (dc.signalingState === 'closed')
return;
dc.close();
}
if (pc) {
if (pc.signalingState === 'closed')
return;
pc.getLocalStreams().forEach(streamStop);
// FIXME This is not yet implemented in firefox
// if(videoStream) pc.removeStream(videoStream);
// if(audioStream) pc.removeStream(audioStream);
pc.close();
}
}
catch (err) {
logger.warn('Exception disposing webrtc peer ' + err);
}
this.emit('_dispose');
};
//
// Specialized child classes
//
function WebRtcPeerRecvonly(options, callback) {
if (!(this instanceof WebRtcPeerRecvonly)) {
return new WebRtcPeerRecvonly(options, callback);
}
WebRtcPeerRecvonly.super_.call(this, 'recvonly', options, callback);
}
inherits(WebRtcPeerRecvonly, WebRtcPeer);
function WebRtcPeerSendonly(options, callback) {
if (!(this instanceof WebRtcPeerSendonly)) {
return new WebRtcPeerSendonly(options, callback);
}
WebRtcPeerSendonly.super_.call(this, 'sendonly', options, callback);
}
inherits(WebRtcPeerSendonly, WebRtcPeer);
function WebRtcPeerSendrecv(options, callback) {
if (!(this instanceof WebRtcPeerSendrecv)) {
return new WebRtcPeerSendrecv(options, callback);
}
WebRtcPeerSendrecv.super_.call(this, 'sendrecv', options, callback);
}
inherits(WebRtcPeerSendrecv, WebRtcPeer);
function harkUtils(stream, options) {
return hark(stream, options);
}
exports.bufferizeCandidates = bufferizeCandidates;
exports.WebRtcPeerRecvonly = WebRtcPeerRecvonly;
exports.WebRtcPeerSendonly = WebRtcPeerSendonly;
exports.WebRtcPeerSendrecv = WebRtcPeerSendrecv;
exports.hark = harkUtils;
/***/ }),
/***/ 306:
/***/ (function(module, exports, __webpack_require__) {
/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* 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.
*
*/
/**
* This module contains a set of reusable components that have been found useful
* during the development of the WebRTC applications with Kurento.
*
* @module kurentoUtils
*
* @copyright 2014 Kurento (http://kurento.org/)
* @license ALv2
*/
var WebRtcPeer = __webpack_require__(305);
exports.WebRtcPeer = WebRtcPeer;
/***/ }),
/***/ 307:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*
* (C) Copyright 2017 OpenVidu (http://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.
*
*/
var OpenViduInternal_1 = __webpack_require__(309);
var Session_1 = __webpack_require__(139);
var Publisher_1 = __webpack_require__(138);
var adapter = __webpack_require__(142);
if (window) {
window["adapter"] = adapter;
}
var OpenVidu = /** @class */ (function () {
function OpenVidu() {
this.openVidu = new OpenViduInternal_1.OpenViduInternal();
console.info("'OpenVidu' initialized");
}
;
OpenVidu.prototype.initSession = function (param1, param2) {
if (this.checkSystemRequirements()) {
if (typeof param2 == "string") {
return new Session_1.Session(this.openVidu.initSession(param2), this);
}
else {
return new Session_1.Session(this.openVidu.initSession(param1), this);
}
}
else {
alert("Browser not supported");
}
};
OpenVidu.prototype.initPublisher = function (parentId, cameraOptions, callback) {
if (this.checkSystemRequirements()) {
if (cameraOptions != null) {
var cameraOptionsAux = {
audio: cameraOptions.audio != null ? cameraOptions.audio : true,
video: cameraOptions.video != null ? cameraOptions.video : true,
data: true,
mediaConstraints: this.openVidu.generateMediaConstraints(cameraOptions.quality)
};
cameraOptions = cameraOptionsAux;
}
else {
cameraOptions = {
audio: true,
video: true,
data: true,
mediaConstraints: {
audio: true,
video: { width: { ideal: 1280 } }
}
};
}
var publisher = new Publisher_1.Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId);
console.info("'Publisher' initialized");
return publisher;
}
else {
alert("Browser not supported");
}
};
OpenVidu.prototype.checkSystemRequirements = function () {
var browser = adapter.browserDetails.browser;
var version = adapter.browserDetails.version;
//Bug fix: 'navigator.userAgent' in Firefox for Ubuntu 14.04 does not return "Firefox/[version]" in the string, so version returned is null
if ((browser == 'firefox') && (version == null)) {
return 1;
}
if (((browser == 'chrome') && (version >= 28)) || ((browser == 'edge') && (version >= 12)) || ((browser == 'firefox') && (version >= 22))) {
return 1;
}
else {
return 0;
}
};
OpenVidu.prototype.getDevices = function (callback) {
navigator.mediaDevices.enumerateDevices().then(function (deviceInfos) {
callback(null, deviceInfos);
}).catch(function (error) {
console.error("Error getting devices", error);
callback(error, null);
});
};
OpenVidu.prototype.enableProdMode = function () {
console.log = function () { };
console.debug = function () { };
console.info = function () { };
console.warn = function () { };
};
return OpenVidu;
}());
exports.OpenVidu = OpenVidu;
/***/ }),
/***/ 308:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(__webpack_require__(307));
__export(__webpack_require__(139));
__export(__webpack_require__(138));
__export(__webpack_require__(140));
__export(__webpack_require__(86));
__export(__webpack_require__(141));
/***/ }),
/***/ 309:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*
* (C) Copyright 2017 OpenVidu (http://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.
*
*/
var SessionInternal_1 = __webpack_require__(310);
var Stream_1 = __webpack_require__(86);
var RpcBuilder = __webpack_require__(137);
var OpenViduInternal = /** @class */ (function () {
function OpenViduInternal() {
this.remoteStreams = [];
}
;
/* NEW METHODS */
OpenViduInternal.prototype.initSession = function (sessionId) {
console.info("'Session' initialized with 'sessionId' [" + sessionId + "]");
this.session = new SessionInternal_1.SessionInternal(this, sessionId);
return this.session;
};
OpenViduInternal.prototype.initPublisherTagged = function (parentId, cameraOptions, callback) {
var _this = this;
this.getCamera(cameraOptions);
if (callback == null) {
this.camera.requestCameraAccess(function (error, camera) {
if (error) {
console.error("Error accessing the camera", error);
}
else {
_this.camera.setVideoElement(_this.cameraReady(camera, parentId));
}
});
return this.camera;
}
else {
this.camera.requestCameraAccess(function (error, camera) {
if (error) {
callback(error);
}
else {
_this.camera.setVideoElement(_this.cameraReady(camera, parentId));
callback(undefined);
}
});
return this.camera;
}
};
OpenViduInternal.prototype.cameraReady = function (camera, parentId) {
this.camera = camera;
var videoElement = this.camera.playOnlyVideo(parentId, null);
this.camera.emitStreamReadyEvent();
return videoElement;
};
OpenViduInternal.prototype.initPublisher = function (cameraOptions, callback) {
this.getCamera(cameraOptions);
this.camera.requestCameraAccess(function (error, camera) {
if (error)
callback(error);
else
callback(undefined);
});
};
OpenViduInternal.prototype.getLocalStream = function () {
return this.camera;
};
OpenViduInternal.prototype.getRemoteStreams = function () {
return this.remoteStreams;
};
/* NEW METHODS */
OpenViduInternal.prototype.getWsUri = function () {
return this.wsUri;
};
OpenViduInternal.prototype.setWsUri = function (wsUri) {
this.wsUri = wsUri;
};
OpenViduInternal.prototype.getSecret = function () {
return this.secret;
};
OpenViduInternal.prototype.setSecret = function (secret) {
this.secret = secret;
};
OpenViduInternal.prototype.getOpenViduServerURL = function () {
return 'https://' + this.wsUri.split("wss://")[1].split("/room")[0];
};
OpenViduInternal.prototype.getRoom = function () {
return this.session;
};
OpenViduInternal.prototype.connect = function (callback) {
this.callback = callback;
this.initJsonRpcClient(this.wsUri);
};
OpenViduInternal.prototype.initJsonRpcClient = function (wsUri) {
var config = {
heartbeat: 3000,
sendCloseMessage: false,
ws: {
uri: wsUri,
useSockJS: false,
onconnected: this.connectCallback.bind(this),
ondisconnect: this.disconnectCallback.bind(this),
onreconnecting: this.reconnectingCallback.bind(this),
onreconnected: this.reconnectedCallback.bind(this)
},
rpc: {
requestTimeout: 15000,
//notifications
participantJoined: this.onParticipantJoined.bind(this),
participantPublished: this.onParticipantPublished.bind(this),
participantUnpublished: this.onParticipantLeft.bind(this),
participantLeft: this.onParticipantLeft.bind(this),
participantEvicted: this.onParticipantEvicted.bind(this),
sendMessage: this.onNewMessage.bind(this),
iceCandidate: this.iceCandidateEvent.bind(this),
mediaError: this.onMediaError.bind(this),
custonNotification: this.customNotification.bind(this)
}
};
this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config);
};
OpenViduInternal.prototype.customNotification = function (params) {
if (this.isRoomAvailable()) {
this.session.emitEvent("custom-message-received", [{ params: params }]);
}
};
OpenViduInternal.prototype.connectCallback = function (error) {
if (error) {
this.callback(error);
}
else {
this.callback(null);
}
};
OpenViduInternal.prototype.isRoomAvailable = function () {
if (this.session !== undefined && this.session instanceof SessionInternal_1.SessionInternal) {
return true;
}
else {
console.warn('Room instance not found');
return false;
}
};
OpenViduInternal.prototype.disconnectCallback = function () {
console.warn('Websocket connection lost');
if (this.isRoomAvailable()) {
this.session.onLostConnection();
}
else {
alert('Connection error. Please reload page.');
}
};
OpenViduInternal.prototype.reconnectingCallback = function () {
console.warn('Websocket connection lost (reconnecting)');
if (this.isRoomAvailable()) {
this.session.onLostConnection();
}
else {
alert('Connection error. Please reload page.');
}
};
OpenViduInternal.prototype.reconnectedCallback = function () {
console.warn('Websocket reconnected');
};
OpenViduInternal.prototype.onParticipantJoined = function (params) {
if (this.isRoomAvailable()) {
this.session.onParticipantJoined(params);
}
};
OpenViduInternal.prototype.onParticipantPublished = function (params) {
if (this.isRoomAvailable()) {
this.session.onParticipantPublished(params);
}
};
OpenViduInternal.prototype.onParticipantLeft = function (params) {
if (this.isRoomAvailable()) {
this.session.onParticipantLeft(params);
}
};
OpenViduInternal.prototype.onParticipantEvicted = function (params) {
if (this.isRoomAvailable()) {
this.session.onParticipantEvicted(params);
}
};
OpenViduInternal.prototype.onNewMessage = function (params) {
if (this.isRoomAvailable()) {
this.session.onNewMessage(params);
}
};
OpenViduInternal.prototype.iceCandidateEvent = function (params) {
if (this.isRoomAvailable()) {
this.session.recvIceCandidate(params);
}
};
OpenViduInternal.prototype.onRoomClosed = function (params) {
if (this.isRoomAvailable()) {
this.session.onRoomClosed(params);
}
};
OpenViduInternal.prototype.onMediaError = function (params) {
if (this.isRoomAvailable()) {
this.session.onMediaError(params);
}
};
OpenViduInternal.prototype.setRpcParams = function (params) {
this.rpcParams = params;
};
OpenViduInternal.prototype.sendRequest = function (method, params, callback) {
if (params && params instanceof Function) {
callback = params;
params = undefined;
}
params = params || {};
if (this.rpcParams && this.rpcParams !== null && this.rpcParams !== undefined) {
for (var index in this.rpcParams) {
if (this.rpcParams.hasOwnProperty(index)) {
params[index] = this.rpcParams[index];
console.debug('RPC param added to request {' + index + ': ' + this.rpcParams[index] + '}');
}
}
}
console.debug('Sending request: {method:"' + method + '", params: ' + JSON.stringify(params) + '}');
this.jsonRpcClient.send(method, params, callback);
};
OpenViduInternal.prototype.close = function (forced) {
if (this.isRoomAvailable()) {
this.session.leave(forced, this.jsonRpcClient);
}
};
;
OpenViduInternal.prototype.disconnectParticipant = function (stream) {
if (this.isRoomAvailable()) {
this.session.disconnect(stream);
}
};
OpenViduInternal.prototype.getCamera = function (options) {
if (this.camera) {
return this.camera;
}
options = options || {
audio: true,
video: true,
data: true,
mediaConstraints: {
audio: true,
video: { width: { ideal: 1280 } }
}
};
options.connection = this.session.getLocalParticipant();
this.camera = new Stream_1.Stream(this, true, this.session, options);
return this.camera;
};
;
/*joinSession(options: SessionOptions, callback: Callback) {
this.session.configure(options);
this.session.connect2();
this.session.addEventListener('room-connected', roomEvent => callback(undefined,this.session));
this.session.addEventListener('error-room', error => callback(error));
return this.session;
};*/
//CHAT
OpenViduInternal.prototype.sendMessage = function (room, user, message) {
this.sendRequest('sendMessage', {
message: message,
userMessage: user,
roomMessage: room
}, function (error, response) {
if (error) {
console.error(error);
}
});
};
;
OpenViduInternal.prototype.sendCustomRequest = function (params, callback) {
this.sendRequest('customRequest', params, callback);
};
;
OpenViduInternal.prototype.toggleLocalVideoTrack = function (activate) {
this.getCamera().getWebRtcPeer().videoEnabled = activate;
};
OpenViduInternal.prototype.toggleLocalAudioTrack = function (activate) {
this.getCamera().getWebRtcPeer().audioEnabled = activate;
};
OpenViduInternal.prototype.publishLocalVideoAudio = function () {
this.toggleLocalVideoTrack(true);
this.toggleLocalAudioTrack(true);
};
OpenViduInternal.prototype.unpublishLocalVideoAudio = function () {
this.toggleLocalVideoTrack(false);
this.toggleLocalAudioTrack(false);
};
OpenViduInternal.prototype.generateMediaConstraints = function (quality) {
var mediaConstraints = {
audio: true,
video: {}
};
var w, h;
switch (quality) {
case 'LOW':
w = 320;
h = 240;
break;
case 'MEDIUM':
w = 640;
h = 480;
break;
case 'HIGH':
w = 1280;
h = 720;
break;
default:
w = 640;
h = 480;
}
mediaConstraints.video['width'] = { exact: w };
mediaConstraints.video['height'] = { exact: h };
//mediaConstraints.video['frameRate'] = { ideal: Number((document.getElementById('frameRate')).value) };
return mediaConstraints;
};
return OpenViduInternal;
}());
exports.OpenViduInternal = OpenViduInternal;
/***/ }),
/***/ 310:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Connection_1 = __webpack_require__(141);
var EventEmitter = __webpack_require__(40);
var SECRET_PARAM = '?secret=';
var SessionInternal = /** @class */ (function () {
function SessionInternal(openVidu, sessionId) {
this.openVidu = openVidu;
this.ee = new EventEmitter();
this.streams = {};
this.participants = {};
this.participantsSpeaking = [];
this.connected = false;
this.sessionId = this.getUrlWithoutSecret(sessionId);
this.localParticipant = new Connection_1.Connection(this.openVidu, true, this);
if (!this.openVidu.getWsUri()) {
this.processOpenViduUrl(sessionId);
}
}
SessionInternal.prototype.processOpenViduUrl = function (url) {
this.openVidu.setSecret(this.getSecretFromUrl(url));
this.openVidu.setWsUri(this.getFinalUrl(url));
};
SessionInternal.prototype.getSecretFromUrl = function (url) {
var secret = '';
if (url.indexOf(SECRET_PARAM) !== -1) {
secret = url.substring(url.lastIndexOf(SECRET_PARAM) + SECRET_PARAM.length, url.length);
}
return secret;
};
SessionInternal.prototype.getUrlWithoutSecret = function (url) {
if (url.indexOf(SECRET_PARAM) !== -1) {
url = url.substring(0, url.lastIndexOf(SECRET_PARAM));
}
return url;
};
SessionInternal.prototype.getFinalUrl = function (url) {
url = this.getUrlWithoutSecret(url).substring(0, url.lastIndexOf('/')) + '/room';
if (url.indexOf(".ngrok.io") !== -1) {
// OpenVidu server URL referes to a ngrok IP: secure wss protocol and delete port of URL
url = url.replace("ws://", "wss://");
var regex = /\.ngrok\.io:\d+/;
url = url.replace(regex, ".ngrok.io");
}
else if ((url.indexOf("localhost") !== -1) || (url.indexOf("127.0.0.1") != -1)) {
// OpenVidu server URL referes to localhost IP
}
return url;
};
/* NEW METHODS */
SessionInternal.prototype.connect = function (token, callback) {
var _this = this;
this.openVidu.connect(function (error) {
if (error) {
callback('ERROR CONNECTING TO OPENVIDU');
}
else {
if (!token) {
token = _this.randomToken();
}
var joinParams = {
token: token,
session: _this.sessionId,
metadata: _this.options.metadata,
secret: _this.openVidu.getSecret(),
dataChannels: false
};
if (_this.localParticipant) {
if (Object.keys(_this.localParticipant.getStreams()).some(function (streamId) {
return _this.streams[streamId].isDataChannelEnabled();
})) {
joinParams.dataChannels = true;
}
}
_this.openVidu.sendRequest('joinRoom', joinParams, function (error, response) {
if (error) {
callback(error);
}
else {
_this.connected = true;
var exParticipants = response.value;
// IMPORTANT: Update connectionId with value send by server
_this.localParticipant.connectionId = response.id;
_this.participants[response.id] = _this.localParticipant;
var roomEvent = {
participants: new Array(),
streams: new Array()
};
var length_1 = exParticipants.length;
for (var i = 0; i < length_1; i++) {
var connection = new Connection_1.Connection(_this.openVidu, false, _this, exParticipants[i]);
connection.creationTime = new Date().getTime();
_this.participants[connection.connectionId] = connection;
roomEvent.participants.push(connection);
var streams = connection.getStreams();
for (var key in streams) {
roomEvent.streams.push(streams[key]);
if (_this.subscribeToStreams) {
streams[key].subscribe();
}
}
}
// Update local Connection object properties with values returned by server
_this.localParticipant.data = response.metadata;
_this.localParticipant.creationTime = new Date().getTime();
// Updates the value of property 'connection' in Session object
_this.ee.emitEvent('update-connection-object', [{ connection: _this.localParticipant }]);
// Own connection created event
_this.ee.emitEvent('connectionCreated', [{ connection: _this.localParticipant }]);
// One connection created event for each existing connection in the session
for (var _i = 0, _a = roomEvent.participants; _i < _a.length; _i++) {
var part = _a[_i];
_this.ee.emitEvent('connectionCreated', [{ connection: part }]);
}
//if (this.subscribeToStreams) {
for (var _b = 0, _c = roomEvent.streams; _b < _c.length; _b++) {
var stream = _c[_b];
_this.ee.emitEvent('streamCreated', [{ stream: stream }]);
// Adding the remote stream to the OpenVidu object
_this.openVidu.getRemoteStreams().push(stream);
}
//}
callback(undefined);
}
});
}
});
};
SessionInternal.prototype.publish = function () {
this.openVidu.getCamera().publish();
};
/* NEW METHODS */
SessionInternal.prototype.configure = function (options) {
this.options = options;
this.id = options.sessionId;
this.subscribeToStreams = options.subscribeToStreams == null ? true : options.subscribeToStreams;
this.updateSpeakerInterval = options.updateSpeakerInterval || 1500;
this.thresholdSpeaker = options.thresholdSpeaker || -50;
this.activateUpdateMainSpeaker();
};
SessionInternal.prototype.getId = function () {
return this.id;
};
SessionInternal.prototype.getSessionId = function () {
return this.sessionId;
};
SessionInternal.prototype.activateUpdateMainSpeaker = function () {
var _this = this;
setInterval(function () {
if (_this.participantsSpeaking.length > 0) {
_this.ee.emitEvent('update-main-speaker', [{
participantId: _this.participantsSpeaking[_this.participantsSpeaking.length - 1]
}]);
}
}, this.updateSpeakerInterval);
};
SessionInternal.prototype.getLocalParticipant = function () {
return this.localParticipant;
};
SessionInternal.prototype.addEventListener = function (eventName, listener) {
this.ee.on(eventName, listener);
};
SessionInternal.prototype.addOnceEventListener = function (eventName, listener) {
this.ee.once(eventName, listener);
};
SessionInternal.prototype.removeListener = function (eventName, listener) {
this.ee.off(eventName, listener);
};
SessionInternal.prototype.removeEvent = function (eventName) {
this.ee.removeEvent(eventName);
};
SessionInternal.prototype.emitEvent = function (eventName, eventsArray) {
this.ee.emitEvent(eventName, eventsArray);
};
SessionInternal.prototype.subscribe = function (stream) {
stream.subscribe();
};
SessionInternal.prototype.unsuscribe = function (stream) {
console.info("Unsubscribing from " + stream.getId());
this.openVidu.sendRequest('unsubscribeFromVideo', {
sender: stream.getId()
}, function (error, response) {
if (error) {
console.error("Error unsubscribing from Subscriber", error);
}
else {
console.info("Unsubscribed correctly from " + stream.getId());
}
});
};
SessionInternal.prototype.onParticipantPublished = function (options) {
options.metadata = this.participants[options.id].data;
// Get the existing Connection created on 'onParticipantJoined' for
// existing participants or create a new one for new participants
var connection = this.participants[options.id];
if (connection) {
// Update existing Connection
connection.options = options;
connection.initStreams(options);
}
else {
// Create new Connection
connection = new Connection_1.Connection(this.openVidu, false, this, options);
}
var pid = connection.connectionId;
if (!(pid in this.participants)) {
console.debug("Remote Connection not found in connections list by its id [" + pid + "]");
}
else {
console.debug("Remote Connection found in connections list by its id [" + pid + "]");
}
connection.creationTime = this.participants[pid].creationTime;
this.participants[pid] = connection;
this.ee.emitEvent('participant-published', [{ connection: connection }]);
var streams = connection.getStreams();
for (var key in streams) {
var stream = streams[key];
if (this.subscribeToStreams) {
stream.subscribe();
}
this.ee.emitEvent('streamCreated', [{ stream: stream }]);
// Adding the remote stream to the OpenVidu object
this.openVidu.getRemoteStreams().push(stream);
}
};
SessionInternal.prototype.onParticipantJoined = function (msg) {
var connection = new Connection_1.Connection(this.openVidu, false, this, msg);
connection.creationTime = new Date().getTime();
var pid = connection.connectionId;
if (!(pid in this.participants)) {
this.participants[pid] = connection;
}
else {
//use existing so that we don't lose streams info
console.warn("Connection already exists in connections list with " +
"the same connectionId, old:", this.participants[pid], ", joined now:", connection);
connection = this.participants[pid];
}
this.ee.emitEvent('participant-joined', [{
connection: connection
}]);
this.ee.emitEvent('connectionCreated', [{
connection: connection
}]);
};
SessionInternal.prototype.onParticipantLeft = function (msg) {
var _this = this;
var connection = this.participants[msg.name];
if (connection !== undefined) {
delete this.participants[msg.name];
this.ee.emitEvent('participant-left', [{
connection: connection
}]);
var streams = connection.getStreams();
for (var key in streams) {
this.ee.emitEvent('streamDestroyed', [{
stream: streams[key],
preventDefault: function () { _this.ee.removeEvent('stream-destroyed-default'); }
}]);
this.ee.emitEvent('stream-destroyed-default', [{
stream: streams[key]
}]);
// Deleting the removed stream from the OpenVidu object
var index = this.openVidu.getRemoteStreams().indexOf(streams[key]);
this.openVidu.getRemoteStreams().splice(index, 1);
}
connection.dispose();
this.ee.emitEvent('connectionDestroyed', [{
connection: connection
}]);
}
else {
console.warn("Participant " + msg.name
+ " unknown. Participants: "
+ JSON.stringify(this.participants));
}
};
;
SessionInternal.prototype.onParticipantEvicted = function (msg) {
this.ee.emitEvent('participant-evicted', [{
localParticipant: this.localParticipant
}]);
};
;
SessionInternal.prototype.onNewMessage = function (msg) {
console.info("New message: " + JSON.stringify(msg));
var room = msg.room;
var user = msg.user;
var message = msg.message;
if (user !== undefined) {
this.ee.emitEvent('newMessage', [{
room: room,
user: user,
message: message
}]);
}
else {
console.warn("User undefined in new message:", msg);
}
};
SessionInternal.prototype.recvIceCandidate = function (msg) {
var candidate = {
candidate: msg.candidate,
sdpMid: msg.sdpMid,
sdpMLineIndex: msg.sdpMLineIndex
};
var connection = this.participants[msg.endpointName];
if (!connection) {
console.error("Participant not found for endpoint " +
msg.endpointName + ". Ice candidate will be ignored.", candidate);
return;
}
var streams = connection.getStreams();
var _loop_1 = function (key) {
var stream = streams[key];
stream.getWebRtcPeer().addIceCandidate(candidate, function (error) {
if (error) {
console.error("Error adding candidate for " + key
+ " stream of endpoint " + msg.endpointName
+ ": " + error);
}
});
};
for (var key in streams) {
_loop_1(key);
}
};
SessionInternal.prototype.onRoomClosed = function (msg) {
console.info("Room closed: " + JSON.stringify(msg));
var room = msg.room;
if (room !== undefined) {
this.ee.emitEvent('room-closed', [{
room: room
}]);
}
else {
console.warn("Room undefined in on room closed", msg);
}
};
SessionInternal.prototype.onLostConnection = function () {
if (!this.connected) {
console.warn('Not connected to room: if you are not debugging, this is probably a certificate error');
if (window.confirm('If you are not debugging, this is probably a certificate error at \"' + this.openVidu.getOpenViduServerURL() + '\"\n\nClick OK to navigate and accept it')) {
location.assign(this.openVidu.getOpenViduServerURL() + '/accept-certificate');
}
;
return;
}
console.warn('Lost connection in Session ' + this.id);
var room = this.id;
if (room !== undefined) {
this.ee.emitEvent('lost-connection', [{ room: room }]);
}
else {
console.warn('Room undefined when lost connection');
}
};
SessionInternal.prototype.onMediaError = function (params) {
console.error("Media error: " + JSON.stringify(params));
var error = params.error;
if (error) {
this.ee.emitEvent('error-media', [{
error: error
}]);
}
else {
console.warn("Received undefined media error. Params:", params);
}
};
/*
* forced means the user was evicted, no need to send the 'leaveRoom' request
*/
SessionInternal.prototype.leave = function (forced, jsonRpcClient) {
forced = !!forced;
console.info("Leaving Session (forced=" + forced + ")");
if (this.connected && !forced) {
this.openVidu.sendRequest('leaveRoom', function (error, response) {
if (error) {
console.error(error);
}
jsonRpcClient.close();
});
}
else {
jsonRpcClient.close();
}
this.connected = false;
if (this.participants) {
for (var pid in this.participants) {
this.participants[pid].dispose();
delete this.participants[pid];
}
}
};
SessionInternal.prototype.disconnect = function (stream) {
var connection = stream.getParticipant();
if (!connection) {
console.error("Stream to disconnect has no participant", stream);
return;
}
delete this.participants[connection.connectionId];
connection.dispose();
if (connection === this.localParticipant) {
console.info("Unpublishing my media (I'm " + connection.connectionId + ")");
delete this.localParticipant;
this.openVidu.sendRequest('unpublishVideo', function (error, response) {
if (error) {
console.error(error);
}
else {
console.info("Media unpublished correctly");
}
});
}
else {
this.unsuscribe(stream);
}
};
SessionInternal.prototype.unpublish = function (stream) {
var connection = stream.getParticipant();
if (!connection) {
console.error("Stream to disconnect has no participant", stream);
return;
}
if (connection === this.localParticipant) {
delete this.participants[connection.connectionId];
connection.dispose();
console.info("Unpublishing my media (I'm " + connection.connectionId + ")");
delete this.localParticipant;
this.openVidu.sendRequest('unpublishVideo', function (error, response) {
if (error) {
console.error(error);
}
else {
console.info("Media unpublished correctly");
}
});
}
};
SessionInternal.prototype.getStreams = function () {
return this.streams;
};
SessionInternal.prototype.addParticipantSpeaking = function (participantId) {
this.participantsSpeaking.push(participantId);
};
SessionInternal.prototype.removeParticipantSpeaking = function (participantId) {
var pos = -1;
for (var i = 0; i < this.participantsSpeaking.length; i++) {
if (this.participantsSpeaking[i] == participantId) {
pos = i;
break;
}
}
if (pos != -1) {
this.participantsSpeaking.splice(pos, 1);
}
};
SessionInternal.prototype.stringClientMetadata = function (metadata) {
if (!(typeof metadata === 'string')) {
return JSON.stringify(metadata);
}
else {
return metadata;
}
};
SessionInternal.prototype.randomToken = function () {
return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
};
return SessionInternal;
}());
exports.SessionInternal = SessionInternal;
/***/ }),
/***/ 327:
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(144);
/***/ }),
/***/ 55:
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_rxjs_Subject__ = __webpack_require__(24);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_rxjs_Subject___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_rxjs_Subject__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return InfoService; });
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var InfoService = (function () {
function InfoService() {
this.newInfo$ = new __WEBPACK_IMPORTED_MODULE_1_rxjs_Subject__["Subject"]();
}
InfoService.prototype.getInfo = function () {
return this.info;
};
InfoService.prototype.updateInfo = function (info) {
this.info = info;
this.newInfo$.next(info);
};
return InfoService;
}());
InfoService = __decorate([
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["c" /* Injectable */])(),
__metadata("design:paramtypes", [])
], InfoService);
//# sourceMappingURL=info.service.js.map
/***/ }),
/***/ 86:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var EventEmitter = __webpack_require__(40);
var kurentoUtils = __webpack_require__(306);
var adapter = __webpack_require__(142);
if (window) {
window["adapter"] = adapter;
}
function jq(id) {
return id.replace(/(@|:|\.|\[|\]|,)/g, "\\$1");
}
function show(id) {
document.getElementById(jq(id)).style.display = 'block';
}
function hide(id) {
document.getElementById(jq(id)).style.display = 'none';
}
var Stream = /** @class */ (function () {
function Stream(openVidu, local, room, options) {
var _this = this;
this.openVidu = openVidu;
this.local = local;
this.room = room;
this.ee = new EventEmitter();
this.videoElements = [];
this.elements = [];
this.showMyRemote = false;
this.localMirrored = false;
this.chanId = 0;
this.dataChannelOpened = false;
this.audioOnly = false;
this.isReady = false;
this.isVideoELementCreated = false;
this.accessIsAllowed = false;
this.accessIsDenied = false;
if (options.id) {
this.id = options.id;
}
else {
this.id = "webcam";
}
this.connection = options.connection;
this.recvVideo = options.recvVideo;
this.recvAudio = options.recvAudio;
this.dataChannel = options.data || false;
this.sendVideo = options.video;
this.sendAudio = options.audio;
this.mediaConstraints = options.mediaConstraints;
this.audioOnly = options.audioOnly || false;
this.addEventListener('src-added', function (srcEvent) {
_this.videoSrcObject = srcEvent.srcObject;
if (_this.video)
_this.video.srcObject = srcEvent.srcObject;
console.debug("Video srcObject [" + srcEvent.srcObject + "] added to stream [" + _this.getId() + "]");
});
}
Stream.prototype.emitSrcEvent = function (wrstream) {
this.ee.emitEvent('src-added', [{
srcObject: wrstream
}]);
};
Stream.prototype.emitStreamReadyEvent = function () {
this.ee.emitEvent('stream-ready'), [{}];
};
Stream.prototype.getVideoSrcObject = function () {
return this.videoSrcObject;
};
Stream.prototype.removeVideo = function (parentElement) {
if (typeof parentElement === "string") {
document.getElementById(parentElement).removeChild(this.video);
}
else if (parentElement instanceof Element) {
parentElement.removeChild(this.video);
}
else if (!parentElement) {
if (document.getElementById(this.parentId)) {
document.getElementById(this.parentId).removeChild(this.video);
}
}
};
Stream.prototype.getVideoElement = function () {
return this.video;
};
Stream.prototype.setVideoElement = function (video) {
this.video = video;
};
Stream.prototype.getRecvVideo = function () {
return this.recvVideo;
};
Stream.prototype.getRecvAudio = function () {
return this.recvAudio;
};
Stream.prototype.subscribeToMyRemote = function () {
this.showMyRemote = true;
};
Stream.prototype.displayMyRemote = function () {
return this.showMyRemote;
};
Stream.prototype.mirrorLocalStream = function (wr) {
this.showMyRemote = true;
this.localMirrored = true;
if (wr) {
this.wrStream = wr;
this.emitSrcEvent(this.wrStream);
}
};
Stream.prototype.isLocalMirrored = function () {
return this.localMirrored;
};
Stream.prototype.getChannelName = function () {
return this.getId() + '_' + this.chanId++;
};
Stream.prototype.isDataChannelEnabled = function () {
return this.dataChannel;
};
Stream.prototype.isDataChannelOpened = function () {
return this.dataChannelOpened;
};
Stream.prototype.onDataChannelOpen = function (event) {
console.debug('Data channel is opened');
this.dataChannelOpened = true;
};
Stream.prototype.onDataChannelClosed = function (event) {
console.debug('Data channel is closed');
this.dataChannelOpened = false;
};
Stream.prototype.sendData = function (data) {
if (this.wp === undefined) {
throw new Error('WebRTC peer has not been created yet');
}
if (!this.dataChannelOpened) {
throw new Error('Data channel is not opened');
}
console.info("Sending through data channel: " + data);
this.wp.send(data);
};
Stream.prototype.getWrStream = function () {
return this.wrStream;
};
Stream.prototype.getWebRtcPeer = function () {
return this.wp;
};
Stream.prototype.addEventListener = function (eventName, listener) {
this.ee.addListener(eventName, listener);
};
Stream.prototype.addOnceEventListener = function (eventName, listener) {
this.ee.addOnceListener(eventName, listener);
};
Stream.prototype.removeListener = function (eventName) {
this.ee.removeAllListeners(eventName);
};
Stream.prototype.showSpinner = function (spinnerParentId) {
var progress = document.createElement('div');
progress.id = 'progress-' + this.getId();
progress.style.background = "center transparent url('img/spinner.gif') no-repeat";
var spinnerParent = document.getElementById(spinnerParentId);
if (spinnerParent) {
spinnerParent.appendChild(progress);
}
};
Stream.prototype.hideSpinner = function (spinnerId) {
spinnerId = (spinnerId === undefined) ? this.getId() : spinnerId;
hide('progress-' + spinnerId);
};
Stream.prototype.playOnlyVideo = function (parentElement, thumbnailId) {
// TO-DO: check somehow if the stream is audio only, so the element created is