FreeSWITCH学习笔记 第二场 第二个镜头 JsSIP视频通讯

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ErErFei/article/details/78912140

上一章JsSIP初识已经介绍了JsSIP的基本使用方法,这一章将使用FreeSWITCH+JsSIP实现视频通讯,截止本文FreeSWITCH使用1.6.18版本,JsSIP使用的3.0.15版本(经过测试使用3.1.x版本不适用本章的例子


FreeSWITCH配置

  • 修改FreeSWITCH安装路径下/conf/var.xml文件中,修改默认密码1
<X-PRE-PROCESS cmd="set" data="default_password=1234"/>
  • 修改FreeSWITCH安装路径下/conf/var.xml文件中,增加
<X-PRE-PROCESS cmd=="set" data="proxy_media=true"/>
  • 修改FreeSWITCH安装路径下/conf/sip_profiles/internal.xml文件,设置inbound-proxy-media和inbound-late-negotiation为true
    <!--Uncomment to set all inbound calls to proxy media mode-->
    <param name="inbound-proxy-media" value="true"/>
    <!-- Let calls hit the dialplan before selecting codec for the a-leg -->
    <param name="inbound-late-negotiation" value="true"/>
  • 修改配置之后重启FreeSWITCH或者打开FS_Cli输入reloadxml,然后打开两台机器上的eyeBeam测试视频通话。

如果一直报视频编解码问题的错误,可以尝试修改/conf/var.xml的配置项global_codec_prefsoutbound_codec_prefs如下(增加可用编解码器)

<X-PRE-PROCESS cmd="set" data="global_codec_prefs=OPUS,G722,PCMU,PCMA,GSM,H263,H264,VP8,H263-1998"/>
<X-PRE-PROCESS cmd="set" data="outbound_codec_prefs=OPUS,G722,PCMU,PCMA,GSM,H263,H264,VP8,H263-1998"/>

前端页面源码

<!DOCTYPE html>
<html>
<head>
  <title>JsSIP + freeSWITCH</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta name="Author" content="Fly" />
  <meta name="description" content="JsSIP Test DEMO" />
  <script src="js/jssip-3.0.15.js" type="text/javascript"></script>
  <style type="text/css">
  </style>
</head>

<body>
  <div style="padding-bottom:10px;font-weight:bold;">控制台</div>
  <div id="login-page" style="width: 500px; border: 1px solid #f0f0f0;">
    <table border="0">
      <tr>
        <td width="160px" align="left"><label for="sip_uri">自己的SIP URI:</label></td>
        <td width="300px"><input style="width:250px" id="sip_uri" type="text" value="sip:[email protected]"/></td>
      </tr>
      <tr>
        <td  align="left"><label for="sip_password">SIP Password:</label></td>
        <td><input style="width:250px" id="sip_password" type="password" value="0000"/></td>
      </tr>
      <tr>
        <td align="left"><label for="ws_uri">WSS URI:</label></td>
        <td><input style="width:250px" id="ws_uri" class="last unset" type="text" value="wss://192.168.17.96:7443"/></td>
      </tr>
      <tr>
        <td  align="left"><label class="input_label" for="sip_phone_number">拨打SIP URI:</label></td>
        <td><input style="width:250px" id="sip_phone_number" type="text" value="sip:[email protected]"></td>
      </tr>
      <tr>
        <td align="left"><input type="button" onclick="testStart()" value="注册"/></td>
        <td align="left"><input type="button" onclick="testCall()" value="拨打"/></td>
      </tr>
    </table>
  </div>

  <div style="padding-top:10px;padding-bottom:10px;font-weight:bold;">视频展示区</div>
  <div style="padding-top:10px;" align="left">
    <table border="0">
      <tr>
        <video id="meVideo" style="padding-right:10px"></video>
        <video id="youVideo"></video>
      </tr>
    </table>
  </div>

</body>
  <script type="text/javascript">
    var outgoingSession = null;
    var incomingSession = null;
    var currentSession = null;
    var meVideo = document.getElementById('meVideo');
    meVideo.setAttribute('autoplay', '');
    //meVideo.setAttribute('muted', '');
    meVideo.setAttribute('playsinline', '');
    meVideo.style.width = '360px';

    var youVideo = document.getElementById('youVideo');
    youVideo.setAttribute('autoplay', '');
    //meVideo.setAttribute('muted', '');
    youVideo.setAttribute('playsinline', '');
    youVideo.style.width = '360px';

    var constraints = {
      audio: true,
      video: {
        faceMode: 'user'
      }
    };

    var localStream = null;
    var userAgent = null;

    navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
      meVideo.srcObject = stream;
      document.body.addEventListener('click', function() {
        meVideo.play();
      });
      // wait until the video stream is ready
      var interval = setInterval(function(){
        if(!meVideo.videoWidth){
          return;
        }
        //stage.appendChild(videoView);
        clearInterval(interval);
      }, 1000 / 50);
    }).catch(function(error){
      onError({
        name: error.name,
        message: error.message
      });
    });

    function testStart(){
      var sip_uri = document.getElementById("sip_uri").value.toString();
      var sip_password = document.getElementById("sip_password").value.toString();
      var ws_uri = document.getElementById("ws_uri").value.toString();

      console.info("get input info: sip_uri = ", sip_uri, " sip_password = ", sip_password, " ws_uri = ", ws_uri);

      var socket = new JsSIP.WebSocketInterface(ws_uri);
      var configuration = {
        sockets: [ socket ],
        outbound_proxy_set: ws_uri,
        uri: sip_uri,
        password: sip_password,
        register: true,
        session_timers: false
      };

      userAgent = new JsSIP.UA(configuration);

      userAgent.on('registered', function(data) {
        console.info("registered: ", data.response.status_code, ",", data.response.reason_phrase);
      });

      userAgent.on('registrationFailed', function(data) {
        console.log("registrationFailed, ", data);
      });

      userAgent.on('registrationExpiring', function() {
        console.warn("registrationExpiring");
      });

      userAgent.on('newRTCSession', function(data) {
        console.info('onNewRTCSession: ', data);
        if(data.originator == 'remote') {
          console.info("incomingSession, answer the call");
          incomingSession = data.session;
          data.session.answer({'mediaConstraints' : constraints, 'mediaStream': null});
        } else {
          console.info("outgoingSession");
          outgoingSession = data.session;
          outgoingSession.on('connecting', function(data){
            console.info('onConnecting - ', data.request);
            currentSession = outgoingSession;
            outgoingSession = null;
          });
        }

        data.session.on('accepted', function(data){
          console.info('onAccepted - ', data);
          if(data.originator == 'remote' && currentSession == null){
            currentSession = incomingSession;
            incomingSession = null;
            console.info("setCurrentSession - ", currentSession);
          }
        });

        data.session.on('confirmed', function(data){
          console.info('onConfirmed - ', data);
          if(data.originator == 'remote' && currentSession == null){
            currentSession = incomingSession;
            incomingSession = null;
            console.info("setCurrentSession - ", currentSession);
          }          
        });

        data.session.on('sdp', function(data){
          console.info('onSDP, type - ', data.type, ' sdp - ', data.sdp);
          //data.sdp = data.sdp.replace('UDP/TLS/RTP/SAVPF', 'RTP/SAVPF');
          //console.info('onSDP, changed sdp - ', data.sdp);
        });

        data.session.on('progress', function(data){
          console.info('onProgress - ', data.originator);
          if(data.originator == 'remote'){
            console.info('onProgress, response - ', data.response);
          }
        });

        data.session.on('peerconnection', function(data){
          console.info('onPeerconnection - ', data.peerconnection);
          data.peerconnection.onaddstream = function(ev){
              console.info('onaddstream from remote - ', ev);
              youVideo.srcObject = ev.stream;

              document.body.addEventListener('click', function() {
                meVideo.play();
              });
              // wait until the video stream is ready
              var interval = setInterval(function(){
                if(!meVideo.videoWidth){
                  return;
                }
                //stage.appendChild(videoView);
                clearInterval(interval);
              }, 1000 / 50);

          };
        });

      });

      userAgent.on('newMessage', function(data){
        if(data.originator == 'local'){
          console.info('onNewMessage , OutgoingRequest - ', data.request);
        }else{
          console.info('onNewMessage , IncomingRequest - ', data.request);
        }
      });

      console.info("call register");
      userAgent.start();
    }

    // Register callbacks to desired call events
    var eventHandlers = {
      'progress': function(e) {
          console.log('call is in progress');
        },
      'failed': function(e) {
          console.log('call failed: ', e);
      alert('呼叫失败');
      },
      'ended': function(e) {
          console.log('call ended : ', e);
      },
      'confirmed': function(e) {
        console.log('call confirmed');
      }
    };

    function testCall(){
      var sip_phone_number = document.getElementById("sip_phone_number").value.toString();

      var options = {
        'eventHandlers'    : eventHandlers,
        'mediaConstraints' : constraints,
        'mediaStream': null
      };

      outgoingSession = userAgent.call(sip_phone_number, options);
    }
  </script>
</html>

服务配置

由于WebRTC要求HTTPS服务,所以我们的页面不能直接访问,而是要通过放入服务中去运行。并且要使用与FreeSWITCH相同的证书(FreeSWITCH证书在其安装目录下的cert文件夹下的wss.pem)。可以参考KOA2 提供HTTPS安全服务


效果图

这里写图片描述

由于此类文章不是很受欢迎,所以FreeSWITCH类文章截止此文章为止


  1. 如果使用默认密码,而且dailplan保留默认配置的话,会被路由走到一个拨号计划中,导致每次接通电话都需要等待10s

猜你喜欢

转载自blog.csdn.net/ErErFei/article/details/78912140