WebRTC-1V1音视频通话websocket 业务代码1(主要框架)

逻辑图

在这里插入图片描述

服务端代码

var ws = require("nodejs-websocket")
var prort = xxxx;

// join 主动加入房间
// leave 主动离开房间
// new-peer 有人加入房间,通知已经在房间的人
// peer-leave 有人离开房间,通知已经在房间的人
// offer 发送offer给对端peer
// answer发送offer给对端peer
// candidate 发送candidate给对端peer
const SIGNAL_TYPE_JOIN = "join";
const SIGNAL_TYPE_RESP_JOIN = "resp-join";  // 告知加入者对方是谁
const SIGNAL_TYPE_LEAVE = "leave";
const SIGNAL_TYPE_NEW_PEER = "new-peer";
const SIGNAL_TYPE_PEER_LEAVE = "peer-leave";
const SIGNAL_TYPE_OFFER = "offer";
const SIGNAL_TYPE_ANSWER = "answer";
const SIGNAL_TYPE_CANDIDATE = "candidate";

/** ----- ZeroRTCMap ----- */
var ZeroRTCMap = function () {
    
    
    this._entrys = new Array();

    this.put = function (key, value) {
    
    
        if (key == null || key == undefined) {
    
    
            return;
        }
        var index = this._getIndex(key);
        if (index == -1) {
    
    
            var entry = new Object();
            entry.key = key;
            entry.value = value;
            this._entrys[this._entrys.length] = entry;
        } else {
    
    
            this._entrys[index].value = value;
        }
    };
    this.get = function (key) {
    
    
        var index = this._getIndex(key);
        return (index != -1) ? this._entrys[index].value : null;
    };
    this.remove = function (key) {
    
    
        var index = this._getIndex(key);
        if (index != -1) {
    
    
            this._entrys.splice(index, 1);
        }
    };
    this.clear = function () {
    
    
        this._entrys.length = 0;
    };
    this.contains = function (key) {
    
    
        var index = this._getIndex(key);
        return (index != -1) ? true : false;
    };
    this.size = function () {
    
    
        return this._entrys.length;
    };
    this.getEntrys = function () {
    
    
        return this._entrys;
    };
    this._getIndex = function (key) {
    
    
        if (key == null || key == undefined) {
    
    
            return -1;
        }
        var _length = this._entrys.length;
        for (var i = 0; i < _length; i++) {
    
    
            var entry = this._entrys[i];
            if (entry == null || entry == undefined) {
    
    
                continue;
            }
            if (entry.key === key) {
    
    // equal
                return i;
            }
        }
        return -1;
    };
}

var roomTableMap = new ZeroRTCMap();

function Client(uid, conn, roomId) {
    
    
    this.uid = uid;     // 用户所属的id
    this.conn = conn;   // uid对应的websocket连接
    this.roomId = roomId;
}

function handleJoin(message, conn) {
    
    
    var roomId = message.roomId;
    var uid = message.uid;

    console.info("uid: " + uid + "try to join room " + roomId);

    var roomMap = roomTableMap.get(roomId);
    if (roomMap == null) {
    
    
        roomMap = new  ZeroRTCMap();
        roomTableMap.put(roomId, roomMap);
    }

    if(roomMap.size() >= 2) {
    
    
        console.error("roomId:" + roomId + " 已经有两人存在,请使用其他房间");
        // 加信令通知客户端,房间已满
        return;
    }

    var client = new Client(uid, conn, roomId);
    roomMap.put(uid, client);
    if(roomMap.size() > 1) {
    
    
        // 房间里面已经有人了,加上新进来的人,那就是>=2了,所以要通知对方
        var clients = roomMap.getEntrys();
        for(var i in clients) {
    
    
            var remoteUid = clients[i].key;
            if (remoteUid != uid) {
    
    
                var jsonMsg = {
    
    
                    'cmd': SIGNAL_TYPE_NEW_PEER,
                    'remoteUid': uid
                };
                var msg = JSON.stringify(jsonMsg);
                var remoteClient =roomMap.get(remoteUid);
                console.info("new-peer: " + msg);
                remoteClient.conn.sendText(msg);

                jsonMsg = {
    
    
                    'cmd':SIGNAL_TYPE_RESP_JOIN,
                    'remoteUid': remoteUid
                };
                msg = JSON.stringify(jsonMsg);
                console.info("resp-join: " + msg);
                conn.sendText(msg);
            }
        }
    }
}

function handleLeave(message) {
    
    
    var roomId = message.roomId;
    var uid = message.uid;

    console.info("uid: " + uid + "leave room " + roomId);

    var roomMap = roomTableMap.get(roomId);
    if (roomMap == null) {
    
    
        console.error("handleLeave can't find then roomId " + roomId);
        return;
    }
    roomMap.remove(uid);        // 删除发送者
    if(roomMap.size() >= 1) {
    
    
        var clients = roomMap.getEntrys();
        for(var i in clients) {
    
    
            var jsonMsg = {
    
    
                'cmd': 'peer-leave',
                'remoteUid': uid // 谁离开就填写谁
            };
            var msg = JSON.stringify(jsonMsg);
            var remoteUid = clients[i].key;
            var remoteClient = roomMap.get(remoteUid);
            if(remoteClient) {
    
    
                console.info("notify peer:" + remoteClient.uid + ", uid:" + uid + " leave");
                remoteClient.conn.sendText(msg);
            }
        }
    }
}

var server = ws.createServer(function(conn){
    
    
    console.log("创建一个新的连接--------")

    conn.sendText("我收到你的连接了....");
    conn.on("text", function(str) {
    
    
        console.info("recv msg:" + str);
        var jsonMsg = JSON.parse(str);

        switch (jsonMsg.cmd) {
    
    
            case SIGNAL_TYPE_JOIN:
                handleJoin(jsonMsg, conn);
            break;
            case SIGNAL_TYPE_LEAVE:
                handleLeave(jsonMsg);
                break;
        }

    });

    conn.on("close", function(code, reason) {
    
    
        console.info("连接关闭 code: " + code + ", reason: " + reason);
        
    });

    conn.on("error", function(err) {
    
    
        console.info("监听到错误:" + err);
    });
}).listen(prort);

客户端代码

这边代码主要是对于 基础业务进行的类的封装 封装如ZeroRTCEngine 对象中

将websocket url 和 websocket对象的基础操作做了进一步封装操作

比如 如果 首先 将websocket对象 变为ZeroRTCEngine中的一个基础变量 对应的websocket 的各项操作 加了一层封装 主要逻辑由ZeroRTCEngine的对应函数负责。

zeroRTCEngine.signaling = new WebSocket(this.wsUrl);
zeroRTCEngine.signaling.onmessage = function(ev) {
    
    
    zeroRTCEngine.onMessage(ev);
}
ZeroRTCEngine.prototype.onMessage = function(event) {
    
    
console.log("onMessage: " + event.data);

var jsonMsg = JSON.parse(event.data);
switch(jsonMsg.cmd) {
    
    
    case SIGNAL_TYPE_NEW_PEER:
        handleRemoteNewPeer(jsonMsg);
        break;
    case SIGNAL_TYPE_RESP_JOIN:
        handleResponseJoin(jsonMsg);
        break;
    case SIGNAL_TYPE_PEER_LEAVE:
        handleRemotePeerLeave(jsonMsg);
        break;    
}

绑定本地流并且显示代码块

document.getElementById('joinBtn').onclick = function() {
    
    
    roomId = document.getElementById('zero-roomId').value;
    if( roomId == "" || roomId == "请输入房间ID") {
    
    
        alert("请输入房间ID");
        return;
    }
    console.log("加入按钮被点击, roomId: " + roomId);
    // 初始化本地码流
    initLocalStream();
}


function openLocalStream(stream) {
    
    
    console.log('Open local stream');
    doJoin(roomId);
    localVideo.srcObject = stream;
    localStream = stream;
}


function initLocalStream() {
    
    
    navigator.mediaDevices.getUserMedia({
    
    
        audio: true,
        video: true
    })
    .then(openLocalStream)
    .catch(function(e) {
    
    
        alert("getUserMedia() error: " + e.name);
    });
}

客户端逻辑代码

'use strict';

// join 主动加入房间
// leave 主动离开房间
// new-peer 有人加入房间,通知已经在房间的人
// peer-leave 有人离开房间,通知已经在房间的人
// offer 发送offer给对端peer
// answer发送offer给对端peer
// candidate 发送candidate给对端peer
const SIGNAL_TYPE_JOIN = "join";
const SIGNAL_TYPE_RESP_JOIN = "resp-join";  // 告知加入者对方是谁
const SIGNAL_TYPE_LEAVE = "leave";
const SIGNAL_TYPE_NEW_PEER = "new-peer";
const SIGNAL_TYPE_PEER_LEAVE = "peer-leave";
const SIGNAL_TYPE_OFFER = "offer";
const SIGNAL_TYPE_ANSWER = "answer";
const SIGNAL_TYPE_CANDIDATE = "candidate";


var localUserId = Math.random().toString(36).substr(2); // 本地uid
var remoteUserId = -1;      // 对端
var roomId = 0;

var localVideo = document.querySelector('#localVideo');
var remoteVideo = document.querySelector('#remoteVideo');
var localStream = null;

var zeroRTCEngine;

var ZeroRTCEngine = function(wsUrl) {
    
    
    this.init(wsUrl);
    zeroRTCEngine = this;
    return this;
}

ZeroRTCEngine.prototype.init = function(wsUrl) {
    
    
    // 设置websocket  url
    this.wsUrl = wsUrl;
    /** websocket对象 */
    this.signaling = null;
}

ZeroRTCEngine.prototype.createWebsocket = function() {
    
    
    zeroRTCEngine = this;
    zeroRTCEngine.signaling = new WebSocket(this.wsUrl);

    zeroRTCEngine.signaling.onopen = function() {
    
    
        zeroRTCEngine.onOpen();
    }

    zeroRTCEngine.signaling.onmessage = function(ev) {
    
    
        zeroRTCEngine.onMessage(ev);
    }

    zeroRTCEngine.signaling.onerror = function(ev) {
    
    
        zeroRTCEngine.onError(ev);
    }

    zeroRTCEngine.signaling.onclose = function(ev) {
    
    
        zeroRTCEngine.onClose(ev);
    }
}

ZeroRTCEngine.prototype.onOpen = function() {
    
    
    console.log("websocket open");
}
ZeroRTCEngine.prototype.onMessage = function(event) {
    
    
    console.log("onMessage: " + event.data);

    var jsonMsg = JSON.parse(event.data);
    switch(jsonMsg.cmd) {
    
    
        case SIGNAL_TYPE_NEW_PEER:
            handleRemoteNewPeer(jsonMsg);
            break;
        case SIGNAL_TYPE_RESP_JOIN:
            handleResponseJoin(jsonMsg);
            break;
        case SIGNAL_TYPE_PEER_LEAVE:
            handleRemotePeerLeave(jsonMsg);
            break;    
    }
}

ZeroRTCEngine.prototype.onError = function(event) {
    
    
    console.log("onError: " + event.data);
}

ZeroRTCEngine.prototype.onClose = function(event) {
    
    
    console.log("onClose -> code: " + event.code + ", reason:" + EventTarget.reason);
}

ZeroRTCEngine.prototype.sendMessage = function(message) {
    
    
    this.signaling.send(message);
}

function handleResponseJoin(message) {
    
    
    console.info("handleResponseJoin, remoteUid: " + message.remoteUid);
    remoteUserId = message.remoteUid;
    // doOffer();
}

function handleRemotePeerLeave(message) {
    
    
    console.info("handleRemotePeerLeave, remoteUid: " + message.remoteUid);
    remoteVideo.srcObject = null;
}

function handleRemoteNewPeer(message) {
    
    
    console.info("handleRemoteNewPeer, remoteUid: " + message.remoteUid);
    remoteUserId = message.remoteUid;
    // doOffer();
}

function doJoin(roomId) {
    
    
    var jsonMsg = {
    
    
        'cmd': 'join',
        'roomId': roomId,
        'uid': localUserId,
    }; 
    var message = JSON.stringify(jsonMsg);
    zeroRTCEngine.sendMessage(message);
    console.info("doJoin message: " + message);
}

function doLeave() {
    
    
    var jsonMsg = {
    
    
        'cmd': 'leave',
        'roomId': roomId,
        'uid': localUserId,
    };
    var message = JSON.stringify(jsonMsg);
    zeroRTCEngine.sendMessage(message);
    console.info("doLeave message: " + message);
}
function openLocalStream(stream) {
    
    
    console.log('Open local stream');
    doJoin(roomId);
    localVideo.srcObject = stream;
    localStream = stream;
}


function initLocalStream() {
    
    
    navigator.mediaDevices.getUserMedia({
    
    
        audio: true,
        video: true
    })
    .then(openLocalStream)
    .catch(function(e) {
    
    
        alert("getUserMedia() error: " + e.name);
    });
}

zeroRTCEngine = new ZeroRTCEngine("ws://192.168.221.134:8099");
zeroRTCEngine.createWebsocket();

document.getElementById('joinBtn').onclick = function() {
    
    
    roomId = document.getElementById('zero-roomId').value;
    if( roomId == "" || roomId == "请输入房间ID") {
    
    
        alert("请输入房间ID");
        return;
    }
    console.log("加入按钮被点击, roomId: " + roomId);
    // 初始化本地码流
    initLocalStream();
}

document.getElementById('leaveBtn').onclick = function() {
    
    
    console.log("离开按钮被点击");
    doLeave();
}

界面代码

#### 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> WebRTC_Review_实现11音视频 </title>
    <h1> WebRTC_Review_实现11音视频 </h1>


</head>

<body>

<div id="buttons">
    <input id="zero-RoomId" type="text" placeholder="请输入房间ID" maxlength="40"/>
    <button id="joinBtn" type="button">加入</button>
    <button id="leaveBtn" type="button">离开</button>
</div>
<div id="videos">
    <video id="localVideo" autoplay muted playsinline>本地窗口</video>
    <video id="remoteVideo" autoplay playsinline>远端窗口</video>
</div>
<script src="main.js"></script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_33329316/article/details/124741362