var Janus = require('../externals/janus.nojquery');
var Promise = require('../../node_modules/bluebird/js/release/bluebird');
/**
* A SplitClient Usecase is started
* @class
* @classdesc SplitClient Use Case
* @param {object} onEvents Event handlers: onCalling, onRegisteredFailed, onHangup, onAcceptedAudio, onReadyLocalStream, onAcceptedVideo, onDataReceived, onStartRecording, onStopRecording, onScreensharingAccepted
* @param {object} domElements DOM elements: local, remote, screenRemote
* @param {object} streamOptions Stream options: audioEnabled, videoEnabled, dataEnabled, aDeviceId, vDeviceId, flavorName
* @return {Promise} SplitClient methods: call, getLicense, hangup, sendData, sendDtmf, toggleAudio, toggleVideo
* @example
* var onEvents = {
* onCalling: function() {
* // Calling
* },
* onRegisteredFailed: function(cause) {
* // Register failed
* console.log(cause);
* },
* onHangup: function(code, cause) {
* // HangUp
* },
* onAcceptedAudio: function(data) {
* // Accepted Audio
* console.log(data.userName);
* console.log(data.sessionId);
* },
* onReadyLocalStream: function() {
* // Ready Local Stream
* },
* onAcceptedVideo: function() {
* // Accepted Video
* },
* onDataReceived: function(type, data, filename) {
* // Data received
* if(type === 'application/x-chat') { }
* if(type === 'text/plain') { }
* if(type === 'application/pdf') { }
* if(type === 'application/zip') { }
* if(type === 'application/x-rar') { }
* if(type === 'image/jpeg') {}
* if(type === 'image/png') {}
* if(type === 'application/x-docx') {}
* if(type === 'application/x-pptx') {}
* if(type === 'application/x-xlsx') {}
* },
* onStartRecording: function() {
* // Start recording
* },
* onStopRecording: function() {
* // Stop recording
* },
* onScreensharingAccepted: function() {
* // ScreenSharing Accepted
* }
* };
*
* var domElements = {
* local: document.getElementById('localvideo'),
* remote: document.getElementById('remotevideo'),
* screenRemote: document.getElementById('remotescreen') // (Optional)
* };
*
* var streamOptions = {
* audioEnabled: true,
* videoEnabled: true,
* dataEnabled: true,
* aDeviceId: null,
* vDeviceId: null,
* flavorName: 'default'
* };
*
* usecases.splitClient(onEvents, domElements, streamOptions)
* .then(function(action) {
* // Use Case has been atacched succesfully
* ...
* })
* .catch(function(cause) {
* // Error attaching the Use Case
* console.log("Error Attach " + cause );
* })
*/
var splitClient = function(onEvents, domElements, streamOptions) {
if(!streamOptions || !domElements || !domElements.local || !domElements.remote || domElements.local.nodeType !== 1 || domElements.remote.nodeType !== 1) return null;
streamOptions = {
audioEnabled: streamOptions.audioEnabled || false,
videoEnabled: streamOptions.videoEnabled || false,
dataEnabled: streamOptions.dataEnabled || false,
aDeviceId: streamOptions.aDeviceId || undefined,
vDeviceId: streamOptions.vDeviceId || undefined,
flavorName: streamOptions.flavorName || 'default'
};
var audioHandle = null;
var videoHandle = null;
var userName = null;
var sessionId = null;
var feeds = [];
var bitrateTimer = [];
var datainfo = [];
/**
* Close the current UseCase. It's recommended combine with disconnect method
* @return {nothing}
* @example
* action.closeUsecase();
* myVideoApp.disconnect(); // Recommended
*/
var closeUsecase = function() {
if(domElements) {
for (var element in domElements) {
if (!domElements.hasOwnProperty(element)) continue;
var obj = domElements[element];
obj.innerHTML = '';
}
}
};
/**
* Send a DTMF tone
* @param {string} dtmf Digit
* @return {nothing}
* @example
* action.sendDtmf("5"); // Also "*" and "#"
*/
var sendDtmf = function(dtmf) {
audioHandle.dtmf({dtmf: { tones: dtmf }});
// You can also send DTMF tones using SIP INFO
//audioHandle.send({"message": {"request": "dtmf_info", "digit": tone }});
};
/**
* Sends a message (Chat or File) through the DataChannel
* @param {string} type MIME Type (e.g: 'application/x-chat', 'text/plain', 'application/pdf', 'application/zip', 'application/x-rar', 'image/jpeg', 'image/png', 'application/x-docx', 'application/x-pptx', 'application/x-xlsx')
* @param {string} data Data Content
* @param {function} cOk Callback success function
* @param {function} cKo Callback failed function
* @param {string} (Optional) filename File Name (e.g: file.zip)
* @return {nothing}
* @example
* action.sendData('application/x-chat', 'Hello Mike!',
* function(cOk) {
* // Success
* },
* function(error) {
* // Error
* console.log(error);
* }
* )
*/
var sendData = function(type, data, cOk, cKo, filename) {
// DataChannel MIME Types Allowed
if(type !== 'application/x-chat' && type !== 'text/plain' && type !== 'application/pdf' && type !== 'application/zip' && type !== 'application/x-rar' && type !== 'image/jpeg' && type !== 'image/png' && type !== 'application/x-docx' && type !== 'application/x-pptx' && type !== 'application/x-xlsx') return null;
// Max Size
var byteLength = parseInt((data.replace(/=/g,"").length * 0.75));
var mByteLength = byteLength/1000000;
if(mByteLength > 5) {
if(cKo) cKo('Sorry! The file is too big. Maximum file size is 5Mb');
}
else {
// Fragmentation
var fragments = data.match(/.{1,60}/g); // REVIEW: Data Fragments of 60 chars
var id = Date.now();
for (var i = 0; i < fragments.length; i++) {
var dataToSend = {
id: id,
type: type,
indexFragment: i,
numberFragments: fragments.length,
fragmentData: fragments[i]
};
if(filename) dataToSend["filename"] = filename;
videoHandle.data({
text: JSON.stringify(dataToSend),
success: function() { if(cOk) cOk(); },
error: function(reason) { if(cKo) cKo(reason); }
});
}
}
};
/**
* Toggle local Audio stream (Mute/Unmute)
* @return {boolean} Is audio muted?
* @example
* action.toggleAudio(); // true or false
*/
var toggleAudio = function() {
if (audioHandle.isAudioMuted()) audioHandle.unmuteAudio();
else audioHandle.muteAudio();
return audioHandle.isAudioMuted();
};
/**
* Toggle local Video stream (Mute/Unmute)
* @return {boolean} Is video muted?
* @example
* action.toggleVideo(); // true or false
*/
var toggleVideo = function() {
if (videoHandle.isVideoMuted()) videoHandle.unmuteVideo();
else videoHandle.muteVideo();
return videoHandle.isVideoMuted();
};
/**
* Join Video Session
* @return {nothing}
* @private
*/
var joinVideo = function() {
var register = { "request": "join", "room": sessionId, "ptype": "publisher", "display": userName };
videoHandle.send({"message": register});
};
/**
* Publish the local stream
* @return {nothing}
* @private
*/
var publishStream = function() {
videoHandle.createOffer(
{
media: { // Publishers are sendonly
audioRecv: false,
audioSend: streamOptions.audioEnabled,
videoRecv: false,
videoSend: streamOptions.videoEnabled,
data: streamOptions.dataEnabled,
audio: {
deviceId: {
exact: streamOptions.aDeviceId || undefined
}
},
video: {
deviceId: {
exact: streamOptions.vDeviceId || undefined
}
}
},
success: function(jsep) {
Janus.debug("Got publisher SDP!");
Janus.debug(jsep);
var publish = { "request": "configure", "audio": true, "video": true };
videoHandle.send({"message": publish, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
publishStream();
}
});
};
/**
* Unpublished a Video Stream
* @return {nothing}
* @private
*/
var unPublishStream = function() {
var unpublish = { "request": "unpublish" };
videoHandle.send({"message": unpublish});
};
/**
* Start Recording
* @param {integer} id Session Id
* @return {nothing}
* @example
* action.startRecording(1234);
* @private
*/
var startRecording = function(id) {
var req = {
"request": "configure",
"room": id,
"record": true,
"prefixtheme": "__"+streamOptions.flavorName+"__"
};
videoHandle.send({"message": req});
if(onEvents && onEvents.onStartRecording) onEvents.onStartRecording();
};
/**
* Stop Recording
* @param {integer} id Session Id
* @return {nothing}
* @example
* action.stopRecording(1234);
* @private
*/
var stopRecording = function(id) {
var req = {
"request": "configure",
"room": id,
"record": false
};
videoHandle.send({"message": req});
if(onEvents && onEvents.onStopRecording) onEvents.onStopRecording();
};
/**
* Client sends a request to start a call to an Agent
* @param {string} callerId Caller ID
* @param {integer} videoRate Video Bitrate (kbps) (optional)
* @param {integer} screenRate Screen Bitrate (kbps) (optional)
* @return {nothing}
* @example
* action.call('IVRPowers', 128000, 256000);
*/
var call = function(callerId, videoRate, screenRate) {
audioHandle.createOffer(
{
media: {
audioSend: streamOptions.audioEnabled,
audioRecv: streamOptions.audioEnabled,
videoSend: false,
videoRecv: false,
audio: {
deviceId: {
exact: streamOptions.aDeviceId || undefined
}
}
},
success: function(jsep) {
var body = {
request: "call_split",
username: callerId,
videorate: videoRate || undefined,
screenrate: screenRate || undefined
};
audioHandle.send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error...", error);
}
});
};
/**
* Client sends a request to hangup the call
* @return {nothing}
* @example
* action.hangup();
*/
var hangup = function() {
var hangup = { "request": "hangup" };
audioHandle.send({"message": hangup});
audioHandle.hangup();
};
/**
* The VideoGateway is requested about the features of the contracted license
* @return {Object} License Information (Screensharing, Livechat and VideoRecording )
* @example
* var myLicense = action.getLicense();
* console.log(myLicense);
*/
var getLicense = function() {
return window.VideoRTC.license;
};
/**
* New Remote Feed
* @param {integer} id Id
* @param {string} display Name
* @return {nothing}
* @private
*/
var newRemoteFeed = function(id, display) {
// A new feed has been published, create a new plugin handle and attach to it as a listener
var remoteFeed = null;
window.VideoRTC.connection.handle.attach(
{
plugin: "janus.plugin.split",
success: function(pluginHandle) {
remoteFeed = pluginHandle;
Janus.log("Plugin attached! (" + remoteFeed.getPlugin() + ", id=" + remoteFeed.getId() + ")");
Janus.log(" -- This is a subscriber");
// We wait for the plugin to send us an offer
var listen = { "request": "join", "room": sessionId, "ptype": "listener", "feed": id };
remoteFeed.send({"message": listen});
},
error: function(error) {
Janus.error(" -- Error attaching plugin...", error);
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message (listener) :::");
var event = msg["split"];
if(event !== undefined && event !== null) {
if(event === "attached") {
// Subscriber created and attached
for(var i=1;i<6;i++) {
if(feeds[i] === undefined || feeds[i] === null) {
feeds[i] = remoteFeed;
remoteFeed.rfindex = i;
break;
}
}
remoteFeed.rfid = msg["id"];
remoteFeed.rfdisplay = msg["display"];
Janus.log("Successfully attached to feed " + remoteFeed.rfid + " (" + remoteFeed.rfdisplay + ") in room " + msg["room"]);
} else if(msg["error"] !== undefined && msg["error"] !== null) {
Janus.error(msg["error"]);
} else {
// What has just happened?
}
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
// Answer and attach
remoteFeed.createAnswer(
{
jsep: jsep,
media: {
audioSend: false,
videoSend: false,
audioRecv: streamOptions.audioEnabled,
videoRecv: streamOptions.videoEnabled,
data: streamOptions.dataEnabled
}, // We want recvonly audio/video
success: function(jsep) {
Janus.debug("Got SDP!");
Janus.debug(jsep);
var body = { "request": "start", "room": sessionId };
remoteFeed.send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
});
}
},
onlocalstream: function(stream) {
// The subscriber stream is recvonly, we don't expect anything here
},
onremotestream: function(stream) {
Janus.debug("Remote feed #" + remoteFeed.rfindex);
var generateLabel = function(id, content, backgroundColor, position) {
var output = '';
output += '<span id="'+id+'" style="';
output += ' position:absolute;margin:10px;padding:3px 5px;color:white;font-weight:bold;border-radius:5px;';
output += 'background:'+backgroundColor+';';
output += position;
output += '">'+content+'</span>';
return output;
};
var container = domElements.remote;
var tpl = '';
tpl += '<div id="container-remote1">';
tpl += '<video autoplay poster="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" id="videoremote1"></video>';
tpl += generateLabel('remote-name', remoteFeed.rfdisplay, '#55D8D5', 'left:0; margin-top: 10px;');
tpl += generateLabel('remote-resolution', '', '#8DCC6D', 'left:0; margin-top: 40px;');
tpl += generateLabel('remote-bitrate', '', '#FF6E5F', 'left:0; margin-top: 70px;');
tpl += '</div>';
container.innerHTML += tpl;
var remoteContainer = document.getElementById('container-remote1');
var videoElem = document.getElementById('videoremote1');
videoElem.onplaying = function() {
var width = this.videoWidth;
var height = this.videoHeight;
document.getElementById('remote-resolution').innerHTML = width+'x'+height;
if(window.VideoRTC.getBrowser() === 'firefox') {
// Firefox Stable has a bug: width and height are not immediately available after a playing
setTimeout(function() {
var width = videoElem.videoWidth;
var height = videoElem.videoHeight;
document.getElementById('remote-resolution').innerHTML = width+'x'+height;
}, 2000);
}
};
Janus.attachMediaStream(videoElem, stream);
//videoElem.muted = true;
var videoTracks = stream.getVideoTracks();
if(videoTracks === null || videoTracks === undefined || videoTracks.length === 0 || videoTracks[0].muted) {
// No remote video
var nodeNoCamera = document.createElement('div');
nodeNoCamera.innerHTML = 'No camera available';
nodeNoCamera.style.position = "relative";
nodeNoCamera.style.height = "100%";
nodeNoCamera.style.width = "100%";
nodeNoCamera.style.top = "100%";
nodeNoCamera.style.left = "50%";
nodeNoCamera.style.transform = "translate(-50%,-50%)";
nodeNoCamera.className = "no-camera-available";
remoteContainer.insertBefore(nodeNoCamera, remoteContainer.firstChild);
// We Hide Bitrate and Resolution labels
for(var i = 0; i < remoteContainer.childNodes.length; i++) {
if(remoteContainer.childNodes[i].id && (remoteContainer.childNodes[i].id.indexOf('remote-resolution') >= 0 || remoteContainer.childNodes[i].id.indexOf('remote-bitrate') >= 0 )) {
remoteContainer.childNodes[i].style.display = 'none';
}
}
}
bitrateTimer[remoteFeed.rfindex] = setInterval(function() {
// Display updated bitrate, if supported
var bitrate = remoteFeed.getBitrate();
document.getElementById('remote-bitrate').innerHTML = bitrate;
}, 1000);
if(onEvents && onEvents.onAcceptedVideo) onEvents.onAcceptedVideo();
},
oncleanup: function() {
Janus.log(" ::: Got a cleanup notification (remote feed " + id + ") :::");
if(bitrateTimer[remoteFeed.rfindex] !== null && bitrateTimer[remoteFeed.rfindex] !== null)
clearInterval(bitrateTimer[remoteFeed.rfindex]);
bitrateTimer[remoteFeed.rfindex] = null;
},
ondataopen: function (data) {
Janus.log("The DataChannel is available!");
},
ondata: function (data) {
Janus.debug("We got data from the DataChannel! " + data);
var fragment = JSON.parse(data);
if(!datainfo[fragment.id]) datainfo[fragment.id] = [];
if(!datainfo[fragment.id][fragment.indexFragment]) datainfo[fragment.id][fragment.indexFragment] = [];
datainfo[fragment.id][fragment.indexFragment].push({
id: fragment.id,
data: fragment.fragmentData
})
//console.log("Received fragment " + datainfo[fragment.id].length + " of " + fragment.numberFragments);
if(datainfo[fragment.id].length >= fragment.numberFragments) {
// Ready to merge
var dataMerged = '';
for(var i = 0; i < datainfo[fragment.id].length; i++) {
//dataMerged += datainfo[fragment.id][i][0].data;
dataMerged += datainfo[fragment.id][i].data || datainfo[fragment.id][i][0].data;
}
var mergeData = {
type: fragment.type,
data: dataMerged
}
if(fragment.filename) mergeData["filename"] = fragment.filename;
if(onEvents && onEvents.onDataReceived) onEvents.onDataReceived(mergeData.type, mergeData.data, mergeData.filename);
// Libery datainfo...
datainfo[fragment.id] = [];
}
}
});
};
/**
* Join Screen Room
* @param {integer} screenRoom Screen Room ID
* @return {nothing}
* @private
*/
var joinScreenroom = function(screenRoom) {
var screenRoomHandle = null;
window.VideoRTC.connection.handle.attach({
plugin: "janus.plugin.split",
success: function(pluginHandle) {
// Plugin attached! 'pluginHandle' is our handle
screenRoomHandle = pluginHandle;
var register = { "request": "join", "room": screenRoom, "ptype": "publisher", "display": 'Screen' };
screenRoomHandle.send({"message": register});
},
error: function(cause) {
},
consentDialog: function(on) {
},
onmessage: function(msg, jsep) {
var event = msg.split;
if(event !== undefined && event !== null) {
if(event === "joined") {
if(msg["publishers"] !== undefined && msg["publishers"] !== null) {
var list = msg["publishers"];
Janus.debug("Got a list of available publishers/feeds:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
Janus.debug(" >> [" + id + "] " + display);
listenScreenSharing(screenRoom, id);
}
}
} else if(event === "destroyed") {
Janus.warn("The room has been destroyed!");
} else if(event === "event") {
if(msg["publishers"] !== undefined && msg["publishers"] !== null) {
var list = msg["publishers"];
Janus.debug("Got a list of available publishers/feeds:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
Janus.debug(" >> [" + id + "] " + display);
listenScreenSharing(screenRoom, id);
}
} else if(msg["leaving"] !== undefined && msg["leaving"] !== null) {
var leaving = msg["leaving"];
Janus.log("Publisher left: " + leaving);
var container = domElements.screenRemote;
container.innerHTML = '';
container.style = '';
//container.className = '';
} else if(msg["unpublished"] !== undefined && msg["unpublished"] !== null) {
var unpublished = msg["unpublished"];
Janus.log("Publisher left: " + unpublished);
var container = domElements.screenRemote;
container.innerHTML = '';
container.style = '';
//container.className = '';
} else if(msg["error"] !== undefined && msg["error"] !== null) {
Janus.error(msg["error"]);
}
}
}
},
onlocalstream: function(stream) {
},
onremotestream: function(stream) {
},
oncleanup: function() {
},
detached: function() {
}
});
};
/**
* Listen ScreenSharing
* @param {integer} screenRoom Screen Room ID
* @param {integer} peerId Peer ID
* @return {nothing}
* @private
*/
var listenScreenSharing = function(screenRoom, peerId) {
var screenFeed = null;
window.VideoRTC.connection.handle.attach(
{
plugin: "janus.plugin.split",
success: function(pluginHandle) {
screenFeed = pluginHandle;
var listen = { "request": "join", "room": screenRoom, "ptype": "listener", "feed": peerId };
screenFeed.send({"message": listen});
},
error: function(error) {
Janus.error(" -- Error attaching plugin...", error);
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message (listener) :::");
var event = msg["split"];
if(event !== undefined && event !== null) {
if(event === "attached") {
} else if(msg["error"] !== undefined && msg["error"] !== null) {
Janus.error(msg["error"]);
} else {
// What has just happened?
}
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
// Answer and attach
screenFeed.createAnswer(
{
jsep: jsep,
media: {
audioSend: false,
videoSend: false,
audioRecv: false,
videoRecv: true,
data: false
}, // We want recvonly audio/video
success: function(jsep) {
Janus.debug("Got SDP!");
Janus.debug(jsep);
var body = { "request": "start", "room": sessionId };
screenFeed.send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
});
}
},
onlocalstream: function(stream) {
// The subscriber stream is recvonly, we don't expect anything here
},
onremotestream: function(stream) {
var container = domElements.screenRemote;
var tpl = '';
tpl += '<div id="container-screenremote">';
tpl += '<video autoplay poster="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" id="screenremote"></video>';
tpl += '</div>';
container.innerHTML = tpl;
var videoElem = document.getElementById('screenremote');
Janus.attachMediaStream(videoElem, stream);
videoElem.muted = true;
if(onEvents && onEvents.onScreensharingAccepted) onEvents.onScreensharingAccepted();
},
oncleanup: function() {
}
});
};
var p1 = new Promise(function (resolve, reject) {
window.VideoRTC.connection.handle.attach({
plugin: "janus.plugin.split",
success: function(pluginHandle) {
// Plugin attached! 'pluginHandle' is our handle
audioHandle = pluginHandle;
resolve();
},
error: function(cause) {
// Couldn't attach to the plugin
if(cause && cause.indexOf('482') >= 0) cause = 'Sorry, all channels are busy';
if(cause && cause.indexOf('480') >= 0) cause = 'License has been expired. Please, contact with an Administrator';
reject(cause);
},
consentDialog: function(on) {
// e.g., Darken the screen if on=true (getUserMedia incoming), restore it otherwise
},
onmessage: function(msg, jsep) {
// We got a message/event (msg) from the plugin
// If jsep is not null, this involves a WebRTC negotiation
var error = msg["error"];
if(error != null && error != undefined) {
Janus.error(error);
return;
}
var result = msg["result"];
if(result !== null && result !== undefined && result["event"] !== undefined && result["event"] !== null) {
var event = result["event"];
if(event === 'registration_failed') {
Janus.warn("Registration failed: " + result["code"] + " " + result["reason"]);
if(onEvents && onEvents.onRegisteredFailed) onEvents.onRegisteredFailed(result["reason"]);
return;
}
else if(event === 'calling') {
Janus.log("Waiting for the peer to answer...");
if(onEvents && onEvents.onCalling) onEvents.onCalling();
}
else if(event === 'accepted') {
Janus.log("Accepted...");
if(jsep !== null && jsep !== undefined) {
audioHandle.handleRemoteJsep({jsep: jsep, error: hangup});
}
userName = result.caller_username;
sessionId = result.id_videoroom;
joinVideo();
if(onEvents && onEvents.onAcceptedAudio) onEvents.onAcceptedAudio({
userName: userName,
sessionId: sessionId
});
}
else if(event === 'hangup') {
Janus.log("Call hung up (" + result["code"] + " " + result["reason"] + ")!");
audioHandle.hangup();
if(onEvents && onEvents.onHangup) onEvents.onHangup(result["code"], result["reason"]);
}
}
},
onlocalstream: function(stream) {
// We have a local stream (getUserMedia worked!) to display
Janus.debug(" ::: Got a local stream :::");
},
onremotestream: function(stream) {
// We have a remote stream (working PeerConnection!) to display
Janus.debug(" ::: Got a remote stream :::");
var container = domElements.remote;
var newNode = document.createElement('div');
newNode.style.display = 'none';
newNode.innerHTML = '<video poster="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" style="display:none;" id="remote-audio" autoplay></video>';
container.parentNode.insertBefore(newNode, container.nextSibling);
Janus.attachMediaStream(document.getElementById('remote-audio'), stream);
},
oncleanup: function() {
// PeerConnection with the plugin closed, clean the UI
// The plugin handle is still valid so we can create a new one
},
detached: function() {
// Connection with the plugin closed, get rid of its features
// The plugin handle is not valid anymore
}
});
});
var p2 = new Promise(function (resolve, reject) {
window.VideoRTC.connection.handle.attach({
plugin: "janus.plugin.split",
success: function(pluginHandle) {
// Plugin attached! 'pluginHandle' is our handle
videoHandle = pluginHandle;
videoHandle.send({
message: { request: "license_info" },
"success": function(data) {
if(data && data["error_code"]){
reject(data["error"]);
}
else {
resolve();
}
}
});
},
error: function(cause) {
// Couldn't attach to the plugin
reject();
},
consentDialog: function(on) {
// e.g., Darken the screen if on=true (getUserMedia incoming), restore it otherwise
},
onmessage: function(msg, jsep) {
// We got a message/event (msg) from the plugin
// If jsep is not null, this involves a WebRTC negotiation
var event = msg.split;
if(event !== undefined && event !== null) {
if(event === "joined") {
Janus.log("Successfully joined room " + msg["room"] + " with ID " + msg["id"]);
publishStream();
// Any new feed to attach to?
if(msg["publishers"] !== undefined && msg["publishers"] !== null) {
var list = msg["publishers"];
Janus.debug("Got a list of available publishers/feeds:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
Janus.debug(" >> [" + id + "] " + display);
newRemoteFeed(id, display)
}
}
var screenRoom = msg["screenroom"];
if(screenRoom && screenRoom > 0 && domElements.screenRemote) joinScreenroom(screenRoom);
} else if(event === "destroyed") {
Janus.warn("The room has been destroyed!");
} else if(event === "event") {
if(msg["publishers"] !== undefined && msg["publishers"] !== null) {
var list = msg["publishers"];
Janus.debug("Got a list of available publishers/feeds:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
Janus.debug(" >> [" + id + "] " + display);
newRemoteFeed(id, display)
}
} else if(msg["leaving"] !== undefined && msg["leaving"] !== null) {
// One of the publishers has gone away?
var leaving = msg["leaving"];
Janus.log("Publisher left: " + leaving);
var remoteFeed = null;
for(var i=1; i<6; i++) {
if(feeds[i] != null && feeds[i] != undefined && feeds[i].rfid == leaving) {
remoteFeed = feeds[i];
break;
}
}
if(remoteFeed != null) {
Janus.debug("Feed " + remoteFeed.rfid + " (" + remoteFeed.rfdisplay + ") has left the room, detaching");
}
} else if(msg["unpublished"] !== undefined && msg["unpublished"] !== null) {
// One of the publishers has unpublished?
var unpublished = msg["unpublished"];
Janus.log("Publisher left: " + unpublished);
if(unpublished === 'ok') {
// That's us
videoHandle.hangup();
return;
}
var remoteFeed = null;
for(var i=1; i<6; i++) {
if(feeds[i] != null && feeds[i] != undefined && feeds[i].rfid == unpublished) {
remoteFeed = feeds[i];
break;
}
}
if(remoteFeed != null) {
Janus.debug("Feed " + remoteFeed.rfid + " (" + remoteFeed.rfdisplay + ") has left the room, detaching");
feeds[remoteFeed.rfindex] = null;
remoteFeed.detach();
}
} else if(msg["startedRec"] !== undefined && msg["startedRec"] !== null) {
startRecording(sessionId, streamOptions.flavorName);
} else if(msg["stoppedRec"] !== undefined && msg["stoppedRec"] !== null) {
stopRecording(sessionId);
} else if(msg["error"] !== undefined && msg["error"] !== null) {
Janus.error(msg["error"]);
} else if (msg['result'] !== undefined && msg['result'] !== null) {
var result = msg['result'];
if (result['event'] == 'license_info') {
window.VideoRTC.license = {
screensharing: (result['screensharing'] == 'true'),
livechat: (result['livechat'] == 'true'),
videorecording: (result['videorecording'] == 'true')
};
Janus.debug("License", window.VideoRTC.license);
}
}
}
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
videoHandle.handleRemoteJsep({jsep: jsep});
}
},
onlocalstream: function(stream) {
// We have a local stream (getUserMedia worked!) to display
var container = domElements.local;
container.innerHTML = '<video poster="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" autoplay id="videolocal1"></video>';
var videoElem = document.getElementById('videolocal1');
Janus.attachMediaStream(videoElem, stream);
videoElem.muted = true;
var videoTracks = stream.getVideoTracks();
if(videoTracks === null || videoTracks === undefined || videoTracks.length === 0) {
// No remote video
var nodeNoCamera = document.createElement('div');
nodeNoCamera.innerHTML = 'No camera available';
nodeNoCamera.style.position = "relative";
nodeNoCamera.style.height = "100%";
nodeNoCamera.style.width = "100%";
nodeNoCamera.style.top = "100%";
nodeNoCamera.style.left = "50%";
nodeNoCamera.style.transform = "translate(-50%,-50%)";
nodeNoCamera.className = "no-camera-available";
container.insertBefore(nodeNoCamera, container.firstChild);
}
if(onEvents && onEvents.onReadyLocalStream) onEvents.onReadyLocalStream();
},
onremotestream: function(stream) {
// We have a remote stream (working PeerConnection!) to display
},
oncleanup: function() {
// PeerConnection with the plugin closed, clean the UI
// The plugin handle is still valid so we can create a new one
},
detached: function() {
// Connection with the plugin closed, get rid of its features
// The plugin handle is not valid anymore
}
});
});
return Promise.all([ p1, p2 ])
.then(function() {
return {
call: call,
closeUsecase: closeUsecase,
getLicense: getLicense,
hangup: hangup,
sendData: sendData,
sendDtmf: sendDtmf,
toggleAudio: toggleAudio,
toggleVideo: toggleVideo
};
});
};
exports.splitClient = splitClient;