webrtc-做的网页视频聊天对话
node-websocket
const Koa = require('koa');
const Router = require('koa-router');
const http = require('http');
const socketIO = require('socket.io');
const fs = require('fs');
//node server.js
const app = new Koa();
const server = http.createServer(app.callback());
const io = socketIO(server, {
cors: true
});
// 首页路由
let router = new Router();
router.get('/', ctx => {
ctx.response.type = 'html';
ctx.response.body = fs.createReadStream('./index.html');
});
app.use(router.routes());
// socket连接
var sockets = {};
io.on('connection', (socket) => {
console.log('user connected['+socket.id+']');
sockets[socket.id] = socket;
//io.emit('message', '我次奥');
var i = 0;
console.log('有这些客户端:');
for (var socket_tmpid in sockets) {
console.log('['+(i+1)+']'+socket_tmpid);
i++;
}
console.log('');
socket.on('message', (data) => {
console.log(data);
io.emit('message', data);
});
socket.on('swap_candidate', (data) => {
//console.log('swap_candidate', data);
for (var socket_tmpid in sockets) {
if(socket_tmpid != socket.id){
//console.log('swap_candidate', socket_tmpid, data);
sockets[socket_tmpid].emit('swap_candidate', data);
}
}
});
socket.on('swap_offer', (data) => {
//console.log('swap_offer', data);
for (var socket_tmpid in sockets) {
if(socket_tmpid != socket.id){
console.log('swap_offer', socket_tmpid, data);
sockets[socket_tmpid].emit('swap_offer', data);
}
}
});
socket.on('swap_answer', (data) => {
//console.log('swap_answer', data);
for (var socket_tmpid in sockets) {
if(socket_tmpid != socket.id){
console.log('swap_answer', socket_tmpid, data);
sockets[socket_tmpid].emit('swap_answer', data);
}
}
});
socket.on('disconnect', () => {
console.log('user disconnected['+socket.id+']');
delete sockets[socket.id];
});
});
// 监听端口
server.listen(5544, () => {
console.log(`server run at: http://localhost:${5544}`)
});
前端界面模板:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WebRTC</title>
<style>
video {
width: 300px;
height: 180px;
background-color: #f1f1f1;
}
.center {
text-align: center;
}
.mt40 {
margin-top: 40px;
}
#btn-chat {
font-size: 18px;
}
#canvas{
border:2px solid red;
}
#local-video{
border:2px solid green;
}
#remote-video{
border:2px solid blue;
}
#remote-img{
border:2px solid yellow;
}
</style>
</head>
<body>
<div id="chat-container" style="display: block">
<h2>视频通话</h2>
<div class="center">
<table>
<tr>
<td>本地视频:</td>
<td><video id="local-video" autoplay></video></td>
<td></td>
</tr>
<tr>
<td>远程视频:</td>
<td><video id="remote-video" autoplay></video></td>
<td></td>
</tr>
</table>
</div>
</div>
<script src="/socket.io/socket.io.min.js"></script>
<script>
const configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
},
{
urls: 'turn:your-turn-server-url',
username: 'your-username',
credential: 'your-password'
}
]
};
let localPeerConnection = new RTCPeerConnection(configuration); // local peer
let localStream;
const isEmpty = (obj) => {
return Object.keys(obj).length === 0 && Object.getPrototypeOf(obj) === Object.prototype;
}
const createLocalMediaStream = async () => {
try{
await navigator.mediaDevices.getUserMedia({
video: true,
audio: false,
}).then(localStream => {
console.log('获取摄像头数据成功...');
conectOtherClient(localStream);
});
}
catch(err){
await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false,
}).then(localStream => {
console.log('获取共享桌面数据成功...');
conectOtherClient(localStream);
});
}
}
const conectOtherClient = async (localStream) => {
var local_video = document.getElementById("local-video");
local_video.srcObject = localStream;
// 监听 ice 候选项事件
localPeerConnection.onicecandidate = (event) => {
if (event.candidate) {
socket.emit('swap_candidate', JSON.stringify(event.candidate));
}
}
// 添加本地媒体流
localStream.getTracks().forEach((track) => {
localPeerConnection.addTrack(track, localStream)
})
//媒体协商(交换SDP)
const offer = await localPeerConnection.createOffer({offerToReceiveAudio: true, offerToReceiveVideo: true});
await localPeerConnection.setLocalDescription(offer);
socket.emit('swap_offer', JSON.stringify(offer));
};
const swap_offer = async (data) => {
await localPeerConnection.setRemoteDescription(data);
const answer = await localPeerConnection.createAnswer();
await localPeerConnection.setLocalDescription(answer);
socket.emit('swap_answer', JSON.stringify(answer));
}
const swap_answer = async (data) => {
await localPeerConnection.setRemoteDescription(data);
}
// 初始化socket事件
socket = io('ws://127.0.0.1:5544');
socket.on("connect", () => {
console.log('socket.on.connect: '+socket.id);
console.log('socket.on.connect: '+socket.connected);
});
socket.on("disconnect", () => {
console.log('socket.on.disconnect: '+socket.id); // undefined
console.log('socket.on.disconnect: '+socket.connected); // false
});
socket.on('message', (data) => {
console.log('socket.on.message: '+data);
});
socket.on('swap_candidate', (data) => {
data = JSON.parse(data);
//console.log('socket.on.swap_candidate: ');
//console.log(data);
localPeerConnection.addIceCandidate(data); // 设置 ice 候选项
// 监听获取媒体数据(前提是peerA已添加了媒体流数据)
localPeerConnection.ontrack = (event) => {
document.getElementById('remote-video').srcObject = event.streams[0]
}
});
socket.on('swap_offer', (data) => {
data = JSON.parse(data);
console.log('socket.on.swap_offer: ');
console.log(data);
swap_offer(data);
});
socket.on('swap_answer', (data) => {
data = JSON.parse(data);
console.log('socket.on.swap_answer: ');
console.log(data);
swap_answer(data);
});
createLocalMediaStream();
</script>
</body>
</html>
运行效果:
1、服务端

客户端a:

客户端b:

我这只有一个摄像头,所以我传输的流式数据一个是摄像头,一个是共享桌面,
穿透服务器配置的是公开的google服务器,没有https所以只能在本地跑,不过效果挺好的
本文来自博客园,作者:河北大学-徐小波,转载请注明原文链接:https://www.cnblogs.com/xuxiaobo/p/18966050

浙公网安备 33010602011771号