swoole+websocket+webrtc实现html视频通话聊天

<a href='/tag/swoole.html'>swoole</a>+websocket+webrtc实现html视频通话聊天

微信的视频通话我们都用过,那么如何用网页视频一个视频邀请通话功能呢,我们可以使用webrtc技术来实现。

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。也就是说现代浏览器都支持webrtc点对点通讯及时,不仅支持点对点音视频通话,还支持点对点文件共享传输功能。

今天我们就使用webrtc结合websocket信令实现视频邀请通话功能,输入好友的账号,点击呼叫,好友那边就会收到通话请求,当好友点击允许后,你与好友之间建立webrtc视频通话。

websocket服务的我们采用swoole实现,采用ssl证书服务

前端html我们自定义一套信令系统来进行邀请-》接受-》拒绝等功能。

html代码如下:

<!DOCTYPE html>

<head>
    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    <style>
        html,body{
            margin: 0;
            padding: 0;
        }
        #main{
            position: absolute;
            width: 370px;
            height: 550px;
        }
        #localVideo{
            position: absolute;
            background: #757474;
            top: 10px;
            right: 10px;
            width: 100px;
            height: 150px;
            z-index: 2;
        }
        #remoteVideo{
            position: absolute;
            top: 0px;
            left: 0px;
            width: 100%;
            height: 100%;
            background: #222;
        }
        #buttons{
            z-index: 3;
            bottom: 20px;
            left: 90px;
            position: absolute;
        }
        #toUser{
            border: 1px solid #ccc;
            padding: 7px 0px;
            border-radius: 5px;
            padding-left: 5px;
            margin-bottom: 5px;
        }
        #toUser:focus{
            border-color: #66afe9;
            outline: 0;
            -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
            box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
        }
        #call{
            width: 70px;
            height: 35px;
            background-color: #00BB00;
            border: none;
            margin-right: 25px;
            color: white;
            border-radius: 5px;
        }
        #yourno{
            color: WHITE;
        }
        #hangup{
            width:70px;
            height:35px;
            background-color:#FF5151;
            border:none;
            color:white;
            border-radius: 5px;
        }
    </style>
</head>

<body>
    <div id="main">
        <video id="remoteVideo" playsinline autoplay></video>
        <video id="localVideo" playsinline autoplay muted></video>

        <div id="buttons">
            <span id="yourno"></span>
            <input id="toUser" placeholder="输入在线好友账号" /><br/>
            <button id="call">视频通话</button>
            <button id="hangup">挂断</button>
        </div>
    </div>


    <script type="text/javascript" th:inline="javascript">
        let username = randomString(6);
        document.getElementById('yourno').innerHTML="您的账户名是:"+username;
        
        let localVideo = document.getElementById('localVideo');
        let remoteVideo = document.getElementById('remoteVideo');
        let websocket = null;
        let peer = null;
    
        WebSocketInit();
        ButtonFunInit();
    
    function randomString(len) {
      len = len || 32;
      var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
      var maxPos = $chars.length;
      var pwd = '';
      for (i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
      }
      return pwd;
    }
    
    
        /* WebSocket */
        function WebSocketInit(){
            //判断当前浏览器是否支持WebSocket
            if ('WebSocket' in window) {
                websocket = new WebSocket("wss:/web.debug.only.bfw.wiki:9502/?username="+username);
            } else {
                alert("当前浏览器不支持WebSocket!");
            }
    
            //连接发生错误的回调方法
            websocket.onerror = function (e) {
                alert("WebSocket连接发生错误!");
            };
    
            //连接关闭的回调方法
            websocket.onclose = function () {
                console.error("WebSocket连接关闭");
            };
    
            //连接成功建立的回调方法
            websocket.onopen = function () {
                console.log("WebSocket连接成功");
            };
    
            //接收到消息的回调方法
            websocket.onmessage = async function (event) {
                let { type, fromUser, msg, sdp, iceCandidate } = JSON.parse(event.data.replace(/\n/g,"\\n").replace(/\r/g,"\\r"));
    
                console.log(type);
    
                if (type === 'hangup') {
                    console.log(msg);
                    document.getElementById('hangup').click();
                    return;
                }
    
                if (type === 'call_start') {
                    let msg = "0"
                    if(confirm(fromUser + "发起视频通话,确定接听吗")==true){
                        document.getElementById('toUser').value = fromUser;
                        WebRTCInit();
                        msg = "1"
                    }
    
                    websocket.send(JSON.stringify({
                        type:"call_back",
                        toUser:fromUser,
                        fromUser:username,
                        msg:msg
                    }));
    
                    return;
                }
    
                if (type === 'call_back') {
                    if(msg === "1"){
                        console.log(document.getElementById('toUser').value + "同意视频通话");
    
                        //创建本地视频并发送offer
                        let stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
                        localVideo.srcObject = stream;
                        stream.getTracks().forEach(track => {
                            peer.addTrack(track, stream);
                        });
    
                        let offer = await peer.createOffer();
                        await peer.setLocalDescription(offer);
    
                        let newOffer = offer.toJSON();
                        newOffer["fromUser"] = username;
                        newOffer["toUser"] = document.getElementById('toUser').value;
                        websocket.send(JSON.stringify(newOffer));
                    }else if(msg === "0"){
                        alert(document.getElementById('toUser').value + "拒绝视频通话");
                        document.getElementById('hangup').click();
                    }else{
                        alert(msg);
                        document.getElementById('hangup').click();
                    }
    
                    return;
                }
    
                if (type === 'offer') {
                    let stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
                    localVideo.srcObject = stream;
                    stream.getTracks().forEach(track => {
                        peer.addTrack(track, stream);
                    });
    
                    await peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));
                    let answer = await peer.createAnswer();
                    let newAnswer = answer.toJSON();
    
                    newAnswer["fromUser"] = username;
                    newAnswer["toUser"] = document.getElementById('toUser').value;
                    websocket.send(JSON.stringify(newAnswer));
    
                    await peer.setLocalDescription(answer);
                    return;
                }
    
                if (type === 'answer') {
                    peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));
                    return;
                }
    
                if (type === '_ice') {
                    peer.addIceCandidate(iceCandidate);
                    return;
                }
    
            }
        }
    
        /* WebRTC */
        function WebRTCInit(){
            peer = new RTCPeerConnection();
    
            //ice
            peer.onicecandidate = function (e) {
                if (e.candidate) {
                    websocket.send(JSON.stringify({
                        type: '_ice',
                        toUser:document.getElementById('toUser').value,
                        fromUser:username,
                        iceCandidate: e.candidate
                    }));
                }
            };
    
            //track
            peer.ontrack = function (e) {
                if (e && e.streams) {
                    remoteVideo.srcObject = e.streams[0];
                }
            };
        }
    
        /* 按钮事件 */
        function ButtonFunInit(){
            //视频通话
            document.getElementById('call').onclick = function (e){
                document.getElementById('toUser').style.visibility = 'hidden';
    
                let toUser = document.getElementById('toUser').value;
                if(!toUser){
                    alert("请先指定好友账号,再发起视频通话!");
                    return;
                }
    
                if(peer == null){
                    WebRTCInit();
                }
    
                websocket.send(JSON.stringify({
                    type:"call_start",
                    fromUser:username,
                    toUser:toUser,
                }));
            }
    
            //挂断
            document.getElementById('hangup').onclick = function (e){
                document.getElementById('toUser').style.visibility = 'unset';
    
                if(localVideo.srcObject){
                    const videoTracks = localVideo.srcObject.getVideoTracks();
                    videoTracks.forEach(videoTrack => {
                        videoTrack.stop();
                        localVideo.srcObject.removeTrack(videoTrack);
                    });
                }
    
                if(remoteVideo.srcObject){
                    const videoTracks = remoteVideo.srcObject.getVideoTracks();
                    videoTracks.forEach(videoTrack => {
                        videoTrack.stop();
                        remoteVideo.srcObject.removeTrack(videoTrack);
                    });
    
                    //挂断同时,通知对方
                    websocket.send(JSON.stringify({
                        type:"hangup",
                        fromUser:username,
                        toUser:document.getElementById('toUser').value,
                    }));
                }
    
                if(peer){
                    peer.ontrack = null;
                    peer.onremovetrack = null;
                    peer.onremovestream = null;
                    peer.onicecandidate = null;
                    peer.oniceconnectionstatechange = null;
                    peer.onsignalingstatechange = null;
                    peer.onicegatheringstatechange = null;
                    peer.onnegotiationneeded = null;
    
                    peer.close();
                    peer = null;
                }
    
                localVideo.srcObject = null;
                remoteVideo.srcObject = null;
            }
        }
    </script>
</body>

</html>

简单地说一下这段html代码

1、首先建立一个websocket通讯,随机生成一个用户名username,初次链接websocket的时候要传给websocket服务器。

2、建立通讯后,用户输入好友的账号,点击视频通话,发送请求数据到websocket上,websocket服务器寻找好友是否在线,在线的话就发送邀请数据

3、好友接受视频聊天请求后双方建立webrct视频通话。

swoole+php建立的websocket服务端代码如下

支付一个金币查看服务端代码

{{collectdata}}

网友评论0