逻辑图

服务端代码

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();

}

界面代码

####

WebRTC_Review_实现1对1音视频

WebRTC_Review_实现1对1音视频

相关链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。