Source: lib/splitClient.js

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;