<!DOCTYPE html> 
 | 
<html lang="en"> 
 | 
<head> 
 | 
    <meta charset="utf-8"> 
 | 
    <title>JSDoc: Source: xmppvideoroom.js</title> 
 | 
  
 | 
    <script src="scripts/prettify/prettify.js"> </script> 
 | 
    <script src="scripts/prettify/lang-css.js"> </script> 
 | 
    <!--[if lt IE 9]> 
 | 
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> 
 | 
    <![endif]--> 
 | 
    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> 
 | 
    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> 
 | 
</head> 
 | 
  
 | 
<body> 
 | 
  
 | 
<div id="main"> 
 | 
  
 | 
    <h1 class="page-title">Source: xmppvideoroom.js</h1> 
 | 
  
 | 
     
 | 
  
 | 
  
 | 
  
 | 
     
 | 
    <section> 
 | 
        <article> 
 | 
            <pre class="prettyprint source linenums"><code>//var XMPPVideoRoom = (function() { 
 | 
  
 | 
     
 | 
    /**  
 | 
     * Interface with Jitsi Video Room and WebRTC-streamer API 
 | 
     * @constructor 
 | 
     * @param {string} xmppUrl - url of XMPP server 
 | 
     * @param {string} srvurl - url of WebRTC-streamer 
 | 
    */ 
 | 
    var XMPPVideoRoom = function XMPPVideoRoom (xmppUrl, srvurl, bus) {     
 | 
        this.xmppUrl     = xmppUrl; 
 | 
        this.srvurl      = srvurl || "//"+window.location.hostname+":"+window.location.port; 
 | 
        this.sessionList = {}; 
 | 
        this.bus = bus; 
 | 
    }; 
 | 
         
 | 
  
 | 
    /**  
 | 
    * Ask to publish a stream from WebRTC-streamer in a XMPP Video Room user 
 | 
    * @param {string} roomid - id of the XMPP Video Room to join 
 | 
    * @param {string} url - WebRTC stream to publish 
 | 
    * @param {string} name - name in Video Room 
 | 
    */ 
 | 
    XMPPVideoRoom.prototype.join = function(roomid, url, name) { 
 | 
        var connection = new Strophe.Connection("https://" + this.xmppUrl + "/http-bind"); 
 | 
        connection.addHandler(this.OnJingle.bind(this, connection, url), 'urn:xmpp:jingle:1', 'iq', 'set', null, null); 
 | 
        connection.roomid = roomid; 
 | 
        connection.name = name; 
 | 
        this.emit(connection.roomid + '/' + connection.name, "joining"); 
 | 
  
 | 
//        connection.rawInput = function (data) { console.log('RECV: ' + data); }; 
 | 
//        connection.rawOutput = function (data) { console.log('SEND: ' + data); }; 
 | 
        // disco stuff 
 | 
        if (connection.disco) { 
 | 
            connection.disco.addIdentity('client', 'http://jitsi.org/jitsimeet'); 
 | 
            connection.disco.addFeature("urn:xmpp:jingle:1");     
 | 
            connection.disco.addFeature("urn:xmpp:jingle:apps:rtp:1");     
 | 
            connection.disco.addFeature("urn:xmpp:jingle:transports:ice-udp:1");     
 | 
            connection.disco.addFeature("urn:xmpp:jingle:apps:dtls:0");     
 | 
            connection.disco.addFeature("urn:xmpp:jingle:apps:rtp:audio");     
 | 
            connection.disco.addFeature("urn:xmpp:jingle:apps:rtp:video");     
 | 
            connection.disco.addFeature("urn:ietf:rfc:5761") 
 | 
            connection.disco.addFeature("urn:ietf:rfc:5888"); // a=group, e.g. bundle 
 | 
             
 | 
        } 
 | 
        connection.connect(this.xmppUrl, null, this.onConnect.bind(this, connection, roomid, name)); 
 | 
    } 
 | 
  
 | 
    /**  
 | 
    * Ask to leave a XMPP Video Room user 
 | 
    * @param {string} roomid - id of the XMPP Video Room to leave 
 | 
    * @param {string} name - name in Video Room 
 | 
    */ 
 | 
    XMPPVideoRoom.prototype.leave = function (roomId, username) { 
 | 
        Object.entries(this.sessionList).forEach( ([sid, session]) => { 
 | 
            if ( (session.connection.roomid === roomId) && (session.connection.name === username) ) { 
 | 
                this.leaveSession(sid); 
 | 
            } 
 | 
        }); 
 | 
    } 
 | 
  
 | 
    /**  
 | 
    * Ask to leave all XMPP Video Room 
 | 
    */ 
 | 
    XMPPVideoRoom.prototype.leaveAll = function () { 
 | 
        Object.keys(this.sessionList).forEach( (sid) => { 
 | 
            this.leaveSession(sid); 
 | 
        }); 
 | 
        this.sessionList = {}; 
 | 
    } 
 | 
  
 | 
    /* 
 | 
    /* HTTP callback for /getIceCandidate  
 | 
    */ 
 | 
    XMPPVideoRoom.prototype.onReceiveCandidate = function(connection, answer, candidateList) { 
 | 
        console.log("============candidateList:" +  JSON.stringify(candidateList)); 
 | 
        var jingle = answer.querySelector("jingle"); 
 | 
        var sid = jingle.getAttribute("sid"); 
 | 
        var from = answer.getAttribute("to"); 
 | 
        var to = answer.getAttribute("from"); 
 | 
  
 | 
        candidateList.forEach(function (candidate) { 
 | 
            var jsoncandidate = SDPUtil.parse_icecandidate(candidate.candidate); 
 | 
            console.log("<=== webrtc candidate:" +  JSON.stringify(jsoncandidate)); 
 | 
            // get ufrag 
 | 
            var ufrag = ""; 
 | 
            var elems = candidate.candidate.split(' '); 
 | 
            for (var i = 8; i < elems.length; i += 2) { 
 | 
                switch (elems[i]) { 
 | 
                    case 'ufrag': 
 | 
                        ufrag = elems[i + 1]; 
 | 
                        break; 
 | 
                } 
 | 
            } 
 | 
            // get pwd 
 | 
            var pwd = ""; 
 | 
            var transports = $(jingle).find('>content>transport'); 
 | 
            transports.each( (idx,transport) => { 
 | 
                if (ufrag == transport.getAttribute('ufrag')) { 
 | 
                    pwd = transport.getAttribute('pwd'); 
 | 
                } 
 | 
            }); 
 | 
             
 | 
            // convert candidate from webrtc to jingle  
 | 
            var iq = $iq({ type: "set",  from, to }) 
 | 
                    .c('jingle', {xmlns: 'urn:xmpp:jingle:1'}) 
 | 
                        .attrs({ action: "transport-info",  sid, ufrag, pwd }) 
 | 
                        .c('candidate', jsoncandidate) 
 | 
                        .up() 
 | 
                    .up(); 
 | 
  
 | 
            var id = connection.sendIQ(iq, () => { 
 | 
                console.log("===> xmpp transport-info ok sid:" + sid);         
 | 
            },() => { 
 | 
                console.log("############transport-info error sid:" + sid); 
 | 
            }); 
 | 
        });     
 | 
  
 | 
        var id = connection.sendIQ(answer, () => { 
 | 
            console.log("===> xmpp session-accept ok sid:" + sid); 
 | 
            this.emit(connection.roomid + '/' + connection.name, "published");             
 | 
        },() => { 
 | 
            console.log("############session-accept error sid:" + sid); 
 | 
        }); 
 | 
    } 
 | 
  
 | 
    /* 
 | 
    /* HTTP callback for  /call  
 | 
    */     
 | 
    XMPPVideoRoom.prototype.onCall = function(connection, iq, data) {         
 | 
        var jingle = iq.querySelector("jingle"); 
 | 
        var sid = jingle.getAttribute("sid"); 
 | 
        console.log("<=== webrtc answer sid:" + sid);         
 | 
         
 | 
        this.sessionList[sid].state = "UP"; 
 | 
        var earlyCandidates = this.sessionList[sid].earlyCandidates; 
 | 
        while (earlyCandidates.length) { 
 | 
                var candidate = earlyCandidates.shift(); 
 | 
                var method = this.srvurl + "/api/addIceCandidate?peerid="+ sid; 
 | 
                request("POST" , method, { body: JSON.stringify(candidate) }).done( function (response) {  
 | 
                        if (response.statusCode === 200) { 
 | 
                            console.log("method:"+method+ " answer:" +response.body); 
 | 
                        } 
 | 
                        else { 
 | 
                            bind.onError(response.statusCode); 
 | 
                        } 
 | 
                    } 
 | 
                );     
 | 
        } 
 | 
                 
 | 
        var sdp = new SDP(data.sdp); 
 | 
        var iqAnswer = $iq({ type: "set",  from: iq.getAttribute("to"), to: iq.getAttribute("from") }) 
 | 
        var jingle = iqAnswer.c('jingle', {xmlns: 'urn:xmpp:jingle:1'}) 
 | 
                        .attrs({ action: "session-accept",  sid, responder:iq.getAttribute("to") }); 
 | 
  
 | 
        var answer = sdp.toJingle(jingle);  
 | 
        var bind = this; 
 | 
        var method = this.srvurl + "/api/getIceCandidate?peerid="+ sid; 
 | 
        request("GET" , method).done( function (response) {  
 | 
                if (response.statusCode === 200) { 
 | 
                    bind.onReceiveCandidate(connection, answer.node, JSON.parse(response.body)); 
 | 
                } 
 | 
                else { 
 | 
                    bind.onError(response.statusCode); 
 | 
                } 
 | 
            } 
 | 
        );             
 | 
    } 
 | 
     
 | 
    XMPPVideoRoom.prototype.emit = function(name, state) { 
 | 
        if (this.bus) { 
 | 
            this.bus.emit('state', name, state); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    XMPPVideoRoom.prototype.onError = function (error) { 
 | 
        console.log("############onError:" + error) 
 | 
    } 
 | 
     
 | 
    /* 
 | 
    /* XMPP callback for  jingle  
 | 
    */         
 | 
    XMPPVideoRoom.prototype.OnJingle = function(connection, url, iq) { 
 | 
        var jingle = iq.querySelector("jingle"); 
 | 
        var sid = jingle.getAttribute("sid"); 
 | 
        var action = jingle.getAttribute("action"); 
 | 
        const fromJid = iq.getAttribute('from'); 
 | 
        const toJid = iq.getAttribute('to'); 
 | 
        console.log("OnJingle from:" + fromJid + " to:" + toJid 
 | 
                                      + " sid:" + sid + " action:" + action); 
 | 
        var id = iq.getAttribute("id"); 
 | 
        var ack = $iq({ type: "result", to: fromJid, id }) 
 | 
  
 | 
        var bind = this; 
 | 
  
 | 
        if (action === "session-initiate")     { 
 | 
            connection.sendIQ(ack);     
 | 
  
 | 
            const resource = Strophe.getResourceFromJid(fromJid); 
 | 
            const isP2P = (resource !== 'focus'); 
 | 
            console.log("<=== xmpp offer sid:" + sid + " resource:" + resource + " initiator:" + jingle.getAttribute("initiator")); 
 | 
  
 | 
            if (!isP2P) { 
 | 
                this.emit(connection.roomid + '/' + connection.name, "publishing"); 
 | 
  
 | 
                var sdp = new SDP(''); 
 | 
                sdp.fromJingle($(jingle)); 
 | 
                 
 | 
                this.sessionList[sid] = { connection, state: "INIT", earlyCandidates:[] } ; 
 | 
  
 | 
                var method = this.srvurl + "/api/call?peerid="+ sid +"&url="+encodeURIComponent(url)+"&options="+encodeURIComponent("rtptransport=tcp&timeout=60"); 
 | 
                request("POST" , method, {body:JSON.stringify({type:"offer",sdp:sdp.raw})}).done( function (response) {  
 | 
                        if (response.statusCode === 200) { 
 | 
                            bind.onCall(connection, iq, JSON.parse(response.body)); 
 | 
                        } 
 | 
                        else { 
 | 
                            bind.onError(response.statusCode); 
 | 
                        } 
 | 
                    } 
 | 
                ); 
 | 
            } 
 | 
                 
 | 
        } else if (action === "transport-info") { 
 | 
            connection.sendIQ(ack);         
 | 
  
 | 
            console.log("<=== xmpp candidate sid:" + sid); 
 | 
             
 | 
            if (this.sessionList[sid]) { 
 | 
                var contents = $(jingle).find('>content'); 
 | 
                contents.each( (contentIdx,content) => { 
 | 
                    var transports = $(content).find('>transport'); 
 | 
                    transports.each( (idx,transport) => { 
 | 
                        var ufrag = transport.getAttribute('ufrag'); 
 | 
                        var candidates = $(transport).find('>candidate'); 
 | 
                        candidates.each ( (idx,candidate) => { 
 | 
                            var sdp = SDPUtil.candidateFromJingle(candidate); 
 | 
                            sdp = sdp.replace("a=candidate","candidate"); 
 | 
                            sdp = sdp.replace("\r\n"," ufrag " + ufrag); 
 | 
                            var candidate = { candidate:sdp, sdpMid:"", sdpMLineIndex:contentIdx } 
 | 
                            console.log("===> webrtc candidate :" + JSON.stringify(candidate)); 
 | 
                 
 | 
                            if (this.sessionList[sid].state == "INIT") { 
 | 
                                this.sessionList[sid].earlyCandidates.push(candidate); 
 | 
                            } else { 
 | 
                                var method = this.srvurl + "/api/addIceCandidate?peerid="+ sid; 
 | 
                                request("POST" , method, { body: JSON.stringify(candidate) }).done( function (response) {  
 | 
                                        if (response.statusCode === 200) { 
 | 
                                            console.log("method:"+method+ " answer:" +response.body); 
 | 
                                        } 
 | 
                                        else { 
 | 
                                            bind.onError(response.statusCode); 
 | 
                                        } 
 | 
                                    } 
 | 
                                );             
 | 
                            }                             
 | 
                        }); 
 | 
                    }); 
 | 
                });     
 | 
            } 
 | 
        } else if (action === "session-terminate") {             
 | 
            connection.sendIQ(ack);         
 | 
            console.log("<=== xmpp session-terminate sid:" + sid + " reason:" + jingle.querySelector("reason").textContent); 
 | 
            this.leaveSession(sid); 
 | 
        } 
 | 
                     
 | 
        return true;         
 | 
    } 
 | 
     
 | 
    /* 
 | 
    /* XMPP callback for  presence  
 | 
    */         
 | 
    XMPPVideoRoom.prototype.OnPresence = function(connection,pres) 
 | 
    { 
 | 
        const resource = Strophe.getResourceFromJid(pres.getAttribute('from')); 
 | 
        const xElement = pres.getElementsByTagNameNS('http://jabber.org/protocol/muc#user', 'x')[0]; 
 | 
        const mucUserItem = xElement && xElement.getElementsByTagName('item')[0]; 
 | 
        if (mucUserItem) { 
 | 
            var msg = " jid:" + mucUserItem.getAttribute('jid')  
 | 
                        + " role:" + mucUserItem.getAttribute('role') 
 | 
                        + " affiliation:" + mucUserItem.getAttribute('affiliation'); 
 | 
  
 | 
            const statusEl = pres.getElementsByTagName('status')[0]; 
 | 
            if (statusEl) { 
 | 
                msg += " status:" + statusEl.getAttribute('code');  
 | 
            } 
 | 
  
 | 
            const nickEl = pres.getElementsByTagName('nick')[0]; 
 | 
            if (nickEl) { 
 | 
                msg += "OnPresence nick:" + nickEl.textContent;  
 | 
            } 
 | 
            console.log ( "OnPresence " + msg);                              
 | 
        } 
 | 
        if (resource === connection.name) { 
 | 
            console.log ( "OnPresence " + connection.name + " connected");  
 | 
        } 
 | 
        return true;         
 | 
    } 
 | 
  
 | 
    /* 
 | 
    /* XMPP callback for  connect  
 | 
    */         
 | 
    XMPPVideoRoom.prototype.onConnect = function(connection, roomid, name, status) 
 | 
    {         
 | 
        if (status === Strophe.Status.CONNECTING) { 
 | 
            console.log('Strophe is connecting.'); 
 | 
        } else if (status === Strophe.Status.CONNFAIL) { 
 | 
            console.log('Strophe failed to connect.'); 
 | 
        } else if (status === Strophe.Status.DISCONNECTING) { 
 | 
            console.log('Strophe is disconnecting.'); 
 | 
        } else if (status === Strophe.Status.DISCONNECTED) { 
 | 
            console.log('Strophe is disconnected.'); 
 | 
        } else if (status === Strophe.Status.CONNECTED) { 
 | 
            console.log('Strophe is connected.'); 
 | 
             
 | 
  
 | 
            var roomUrl = roomid + "@" + "conference." + this.xmppUrl;             
 | 
            var extPresence = Strophe.xmlElement('nick', {xmlns:'http://jabber.org/protocol/nick'}, name); 
 | 
            connection.muc.join(roomUrl, name, null, this.OnPresence.bind(this,connection), null, null, null, extPresence);     
 | 
             
 | 
            this.emit(connection.roomid + '/' + connection.name, "joined"); 
 | 
        } 
 | 
    } 
 | 
         
 | 
  
 | 
    /* 
 | 
    /* leave a session 
 | 
    */     
 | 
    XMPPVideoRoom.prototype.leaveSession = function (sid) { 
 | 
        var session = this.sessionList[sid]; 
 | 
        if (session) { 
 | 
            this.emit(session.connection.roomid + '/' + session.connection.name, "leaving"); 
 | 
  
 | 
            var roomUrl = session.connection.roomid + "@" + "conference." + this.xmppUrl; 
 | 
            // close jingle session 
 | 
            var iq = $iq({ type: "set",  from: roomUrl +"/" + session.connection.name, to: roomUrl }) 
 | 
                            .c('jingle', {xmlns: 'urn:xmpp:jingle:1'}) 
 | 
                                .attrs({ action: "session-terminate",  sid}) 
 | 
                            .up(); 
 | 
            session.connection.sendIQ(iq); 
 | 
  
 | 
            // close WebRTC session 
 | 
            var bind = this; 
 | 
            var method = this.srvurl + "/api/hangup?peerid="+ sid; 
 | 
            request("GET" , method).done( function (response) {  
 | 
                    if (response.statusCode === 200) { 
 | 
                        console.log("method:"+method+ " answer:" +response.body); 
 | 
                    } 
 | 
                    else { 
 | 
                        bind.onError(response.statusCode); 
 | 
                    } 
 | 
                } 
 | 
            );                     
 | 
            session.connection.muc.leave(roomUrl, session.connection.name); 
 | 
            session.connection.flush(); 
 | 
            session.connection.disconnect();     
 | 
            this.emit(session.connection.roomid + '/' + session.connection.name, "leaved"); 
 | 
  
 | 
            delete this.sessionList[sid]; 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
//    return XMPPVideoRoom; 
 | 
//})(); 
 | 
  
 | 
//module.exports = XMPPVideoRoom; 
 | 
</code></pre> 
 | 
        </article> 
 | 
    </section> 
 | 
  
 | 
  
 | 
  
 | 
  
 | 
</div> 
 | 
  
 | 
<nav> 
 | 
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="JanusVideoRoom.html">JanusVideoRoom</a></li><li><a href="WebRtcStreamer.html">WebRtcStreamer</a></li><li><a href="XMPPVideoRoom.html">XMPPVideoRoom</a></li></ul> 
 | 
</nav> 
 | 
  
 | 
<br class="clear"> 
 | 
  
 | 
<footer> 
 | 
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sat Aug 25 2018 15:00:27 GMT+0200 (CEST) 
 | 
</footer> 
 | 
  
 | 
<script> prettyPrint(); </script> 
 | 
<script src="scripts/linenumber.js"> </script> 
 | 
</body> 
 | 
</html> 
 |