XMPP instant messaging protocol use (12) -- building a simple LAN WebRTC based on XMPP

Create HTML and JS

ofwebrtc.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>HTML5 GetUserMedia Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<script src='jquery-1.9.1.min.js'></script>
    <script src='strophe.min.js'></script>
    <script src='ofwebrtc.js'></script>
</head>
<body>

    <p id="info"></p>
    <p>----------------------------------------------------------------</p>

    JID: <input type="text" id="input-jid" value="">
    <br>
    Password:<input type="password" id="input-pwd" value="">
    <br>
    <button id="btn-login">Sign in</button><br>

    <br>
    target JID: 
    <input type="text" id="input-contacts" value="mytest1@pc-20170308pkrs">
    <button id="btn-call">Call</button>
    <p>----------------------------------------------------------------</p>

    Local: <br>
    <video id="localVideo" autoplay></video><br>
    Remote: <br>
    <video id="remoteVideo" autoplay></video>
</body>
</html>

ofwebrtc.js

// XMPP help class
// boshService: XMPP server BOSH address
function XMPPHelper(boshService) {
    var _this = this;

    // XMPP server BOSH address
    _this.boshService = boshService;

    // XMPP connection
    _this.connection = null;

    // Whether the current state is connected
    _this.connected = false;

    // Currently logged in JID
    _this.jid = "";

    // Business callback method after receiving the message
    _this.messageCallback = null;
    _this.setMessageCallback = function (messageCallback) {
        _this.messageCallback = messageCallback;
    }

    // Received < message >
    var onMessage = function (msg) {
        console.log('--- msg ---', msg);

        // Parse out the from and type attributes of < message > and the body sub elements
        var from = msg.getAttribute('from');
        var type = msg.getAttribute('type');
        var elems = msg.getElementsByTagName('body');
        var json = JSON.parse(HtmlUtil.htmlDecodeByRegExp(elems[0].innerHTML));
		console.log('--- json ---', json);
        json.fromjid = from;

        if (type === 'chat') {
            _this.messageCallback(json);
        }

        return true;
    }

    // Event of connection state change
    var onConnect = function (status) {
        console.log('status: ' + status)
        if (status == Strophe.Status.CONNFAIL) {
            $('#info').html("connection failed! "";
        } else if (status == Strophe.Status.AUTHFAIL) {
            $('#info').html("login failed! "";
        } else if (status == Strophe.Status.DISCONNECTED) {
            $('#info').html("disconnected! "";
            _this.connected = false;
        } else if (status == Strophe.Status.CONNECTED) {
            $('#info').html("connection succeeded! "";
            _this.connected = true;

            // When the < message > section is received, the onMessage callback function is called
            _this.connection.addHandler(onMessage, null, 'message', null, null, null);

            // First, send a < presence > to the server (initial presence)
            _this.connection.send($pres().tree());
        }
    };

    // Sign in
    _this.login = function (jid, password) {
        _this.connection = new Strophe.Connection(_this.boshService);
        _this.connection.connect(jid, password, onConnect);
        _this.jid = jid;
    };

    _this.sendMessage = function (tojid, type, data) {
        if (_this.connected === false) {
            alert("Please login first!!!");
            return;
        }

        var msg = $msg({
            to: tojid,
            from: _this.jid,
            type: 'chat'
        }).c("body", null, JSON.stringify({
            type: type,
            data: data
        }));
        _this.connection.send(msg.tree());
    };
}

// WebRTC help class
// xmppHelper: XMPP help instance
// Local video: DOM of local video display
// Remote video: DOM of remote video display
function WebRTCHelper(xmppHelper, localVideo, remoteVideo) {
    var _this = this;

    // Opposite party users
    _this.tojid = null;

    // Create a PeerConnection instance (if the parameter is null, there is no iceserver. Even if there is no stunserver and turnserver, you can still communicate under the local area network)
    _this.pc = new webkitRTCPeerConnection(null);

    _this.hasBindLocalVideo = false;

    // Send ICE candidates to other clients
    _this.pc.onicecandidate = function(event){
        if (event.candidate !== null && _this.tojid !== null) {
            console.log('----------- onicecandidate ------------');
            console.log('candidate', event.candidate);

			xmppHelper.sendMessage(_this.tojid, 'candidate', event.candidate);
        }
    };

    // If a media stream is detected to be connected locally, bind it to a video label for output
    _this.pc.onaddstream = function(event){
		console.log('----------- onaddstream ------------');
        remoteVideo.src = URL.createObjectURL(event.stream);
    };

    // Send the functions of offer and answer, and send the local session description
    var sendOfferFn = function(desc){
        console.log('----------- sendOfferFn ------------');
        console.log('desc', desc);
        _this.pc.setLocalDescription(desc);
        
        xmppHelper.sendMessage(_this.tojid, 'offer', desc);
    };
    var sendAnswerFn = function(desc){
        console.log('----------- sendAnswerFn ------------');
        console.log('desc', desc);
        _this.pc.setLocalDescription(desc);

        xmppHelper.sendMessage(_this.tojid, 'answer', desc);
    };
	var mediaConfig =  { video: true };
    // Bind local video stream
    var bindLocalVideo = function (callback) {
        if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
			navigator.mediaDevices.getUserMedia(mediaConfig).then(function(stream) {
				//Bind local media stream to video label for output
				localVideo.src = window.URL.createObjectURL(stream);
				//Join the stream to be sent to PeerConnection
				_this.pc.addStream(stream);
				callback();
			});
		}
		
    };

	
    // Start video communication
    _this.start = function (tojid) {
        _this.tojid = tojid;

        if (_this.hasBindLocalVideo === false) {
            bindLocalVideo(function () {
                // Send an offer signal
                _this.pc.createOffer(sendOfferFn, function (error) {
                    console.log('Failure callback: ' + error);
                });
            });
            _this.hasBindLocalVideo = true;
        } else {
            // Send an offer signal
            _this.pc.createOffer(sendOfferFn, function (error) {
                console.log('Failure callback: ' + error);
            });
        }
    };

    // Processing after receiving the other party's information
    _this.onMessage = function (json) {
        console.log('onMessage: ', json);
		console.log('json.data: ', json.data);

        if (_this.tojid === null) {
            _this.tojid = json.fromjid;
        }

        if (json.type === 'candidate') {
            _this.pc.addIceCandidate(new RTCIceCandidate(json.data));
        } else {
            _this.pc.setRemoteDescription(new RTCSessionDescription(json.data));
            if (json.type === 'offer') {
                if (_this.hasBindLocalVideo === false) {
                    bindLocalVideo(function () {
                        _this.pc.createAnswer(sendAnswerFn, function (error) {
                            console.log('Failure callback: ' + error);
                        });
                    });
                    _this.hasBindLocalVideo = true;
                } else {
                    _this.pc.createAnswer(sendAnswerFn, function (error) {
                        console.log('Failure callback: ' + error);
                    });
                }
            }
        }
    }
}

$(document).ready(function() {
    // Instantiate XMPP and WebRTC help classes
    var xmppHelper = new XMPPHelper('http://localhost:7070/http-bind/');
    var webRTCHelper = new WebRTCHelper(xmppHelper, document.getElementById('localVideo'), document.getElementById('remoteVideo'));

    // XMPP receives the message and transfers it to WebRTC
    xmppHelper.setMessageCallback(webRTCHelper.onMessage);

    $('#btn-login').click(function() {
        console.log('jid: ' + $("#input-jid").val());
        console.log('pwd: ' + $("#input-pwd").val());
        xmppHelper.login($("#input-jid").val(), $("#input-pwd").val());
    });

    $('#btn-call').click(function() {
        if($("#input-contacts").val() == '') {
            alert("Please enter the target user!");
            return;
        }
        tojid = $("#input-contacts").val();

        webRTCHelper.start(tojid);
    });
});

var HtmlUtil = {
        /*1.html transcoding with browser internal converter*/
        htmlEncode:function (html){
            //1. First create a container label element dynamically, such as DIV
            var temp = document.createElement ("div");
            //2. Then set the string to be converted to innerText(ie support) or textcontent (Firefox, google support) of this element
            (temp.textContent != undefined ) ? (temp.textContent = html) : (temp.innerText = html);
            //3. Finally, return the innerHTML of this element, i.e. get the string that has been HTML encoded and transformed
            var output = temp.innerHTML;
            temp = null;
            return output;
        },
        /*2.html decoding with browser internal converter*/
        htmlDecode:function (text){
            //1. First create a container label element dynamically, such as DIV
            var temp = document.createElement("div");
            //2. Then set the string to be converted to the innerHTML of this element (supported by ie, Firefox and google)
            temp.innerHTML = text;
            //3. Finally, return the innerText(ie support) or textcontent (Firefox, google support) of this element to get the HTML decoded string.
            var output = temp.innerText || temp.textContent;
            temp = null;
            return output;
        },
        /*3.html transcoding with regular expression*/
        htmlEncodeByRegExp:function (str){  
             var s = "";
             if(str.length == 0) return "";
             s = str.replace(/&/g,"&amp;");
             s = s.replace(/</g,"&lt;");
             s = s.replace(/>/g,"&gt;");
             s = s.replace(/ /g,"&nbsp;");
             s = s.replace(/\'/g,"&#39;");
             s = s.replace(/\"/g,"&quot;");
             return s;  
       },
       /*4.html decoding with regular expression*/
       htmlDecodeByRegExp:function (str){  
             var s = "";
             if(str.length == 0) return "";
             s = str.replace(/&amp;/g,"&");
             s = s.replace(/&lt;/g,"<");
             s = s.replace(/&gt;/g,">");
             s = s.replace(/&nbsp;/g," ");
             s = s.replace(/&#39;/g,"\'");
             s = s.replace(/&quot;/g,"\"");
             return s;  
       }
    };

test

1. Open Chrome, visit the page of ofwebrtc.html, enter JID (such as admin@pc-20170308pkrs), password, and click log in to prompt that the connection is successful.

2. Open another Chrome page to visit ofwebrtc.html, enter JID (such as mytest1@pc-20170308pkrs), password, click login, and you will be prompted that the connection is successful.

Then input the JID (admin@pc-20170308pkrs) on the previous page in the target JID and click Call. You will be prompted to use the camera and select allow.

3. The last page will also pop up the use of camera prompt, click allow

4, effect

There will be time for further optimization

Tags: JSON IE Firefox Google

Posted on Mon, 06 Jan 2020 05:10:46 -0800 by freakuency