jssip介绍系列-分机注册与接听

虽不是专业前端,但基本完成了关于基于jssip的注册,接听,挂断 ,视频接听、屏幕分享、摄像头切换,实时拍照,视频录像、虚拟摄像头等功能。 一路踩了很多坑,虽然jssip官网对这些功能说了可以实现,但jssip本事主要专注于底层webrtc和sip协议等。 这些上层的应用文档确实写得不是很友好。 因此应qq群友邀请,我贡献一下自己对这些基础功能的实现

首先本系列jssip基于版本3.6.1, freeswitch 1.10.5-release~64bit, 浏览器最新chrome

 

第一步检测

浏览器系统音频、视频是否支持

navigator.getUserMedia(
    // constraints
    {
        video: true,
        audio: true
    },
    // successCallback
    function (localMediaStream) {
        // video.src = window.URL.createObjectURL(localMediaStream);
        // video.onloadedmetadata = function(e) {
        //    // Do something with the video here.
        // };
    },

    // errorCallback
    function (err) {
        console.log(err);
    }
);

 

第二步:jssip基本简介

jssip 使用webrtc形式与freeswitch进行连通,这里有个注意事项,webrtc必须使用https域名等才可以使用,否则浏览器不允许(细节重点)

jssip.UA 所谓UA即为一个连接客户端,而客户端需要注册分机到freeswitch,因此初始化UA十分关键,直接影响你是否能收到来电等信息。

注册成功的UA,将监听重点事件,由此完成电话的接听,挂断等事件。

很多网友虽然注册成功,仍无法接听电话等,是因为 UA注册信息缺失。

    var configuration = {
        sockets: [socket],
        uri: 'sip:' + username + '@**.com;transport=wss',
        password: password,
        contact_uri: 'sip:' + username + '@**.com;transport=wss',
        outbound_proxy_set: 'wss://**.com:7443',
        display_name: username
    };

contact_uri 非常重要

 

准备工作

我们使用创建一个全局变量来存储UA信息, 创建两个video标签用来展示来电视频、接听者视频信息。

<video width="300" height="200" id="my-video" autoplay> </video>

<video width="200" height="150" id="peer-video" autoplay> </video>

 

window.remoteView  = document.getElementById(remoteVideoTag);
window.selfView = document.getElementById(selfVideoTag);

window.sipSession = undefined;  // 当前电话session
window.ua = undefined;   // 当前注册UA
window.comingPhone = undefined;  // 来电号码

 

事件绑定

向freeswitch注册完成分机后,需要监听newRTCSession 事件,用来判断来电信息。通过来电的事件的‘accepte’,‘progress’, ‘end’ 来确定电话是来电,接听,和挂断

处理接听时候,判断e.session._connection的LocalStreams,和remoteStreams流,将流绑定到video标签中,从而在页面展示来电视频。

 

function sipEventBind(e, callbacks){
    e.session.on("accepted", function () {
        if (e.session._connection.getLocalStreams().length > 0) {
            // 接听后,判断localStream
            window.selfView.srcObject = e.session._connection.getLocalStreams()[0];
            window.selfView.volume = 0;
        }
        if (e.session._connection.getRemoteStreams().length > 0) {
            window.remoteView.srcObject = e.session._connection.getRemoteStreams()[0];
        }
    });

    //  来电 振铃
    e.session.on("progress", function(data){
        try{
            var player = document.createElement('audio');
        player.setAttribute("id", "ringId");
            player.setAttribute("src", "https://cdn-obs-question.aegis-info.com/mall/newspaper/20210220_467c8bfd-7474-447a-8028-2c198659da7e.mp3");
            player.setAttribute('autoplay', 'autoplay');
            player.play();
        }catch(err){
            console.log(err);
        } 
        if (callbacks != undefined) {
            if (typeof callbacks === "function") {
                window.comingPhone = e.session.remote_identity.display_name;
                callbacks(e.session.remote_identity.display_name);
            }
        }
    });
    // 挂断处理
    e.session.on("ended", function(data){
        var stream1 = window.selfView.srcObject;
        if(stream1 != undefined){
            var tracks = stream1.getTracks();
            if(tracks != undefined){
                tracks.forEach(track => {
                    track.stop();
                });
            }
        }
        console.log('call ended with cause: ' + e.cause);
    });
}

 

具体封装代码如下:

function login(account, password, callbacks, loginCallback) {
    var username = account;
    var socket = new JsSIP.WebSocketInterface('wss://**.com:7443');
    var configuration = {
        sockets: [socket],
        uri: 'sip:' + username + '@**.com;transport=wss',
        password: password,
        contact_uri: 'sip:' + username + '@**.com;transport=wss',
        outbound_proxy_set: 'wss://**.com:7443',
        display_name: username
    };

    var ua = new JsSIP.UA(configuration);
    ua.start();
    window.ua = ua;

    window.ua.on('registered', function(e){
    // 注册成功回调方法
        if (loginCallback != undefined) {
            if (typeof loginCallback === "function") {
                loginCallback();
            }
        }
    });

    window.ua.on('newRTCSession', function (e) {
        if (e.session._direction == "outgoing") {
            console.log("打电话");
        } else {
            console.log("来电话啦");
            // 绑定session
            window.sipSession = e.session;
            sipEventBind(e)
        }
        
    });


    window.ua.on('sipEvent', function (e) {
        console.log(e);
    });
}

 

调用时候,login(user, password, incommingCallback, loginCallback)

第三个参数为来电对调。

    login(username, "password", function(calledNumber){
      alert("来电话啦"+ calledNumber);
    },
    function(){
      alert("注册freeswitch成功");
    }
    );

由此我们完成了,电话的注册,来电振铃,接听等事件监听处理。

注意!!

a、chrome在使用振铃、视频接听等操作时候,需要用户主动触发。 因此注册操作login方法必须由用户主动点击页面进行!!

b、出现问题:handshake failure


解决方法: 升级chrome 对 dtls有要求,需要更新 openssl 版本,使得fs进行支持,dtls 版本

解决办法一:a、升级openssl,重新生成证书,7443端口指定的证书
b、删除 dtls-srtp.pem (fs自动生成的)
c、重新编译freeswitch

解决方法二: 升级freeswtich, 或者降低chrome版本

 

 

下一节我们继续jssip的其他应用处理。

posted @ 2023-05-10 14:02  阿风小子  阅读(727)  评论(0编辑  收藏  举报