1、使用socket.io进行会话
2、为了方便,参数写死在前端了,前端界面1代码如下(由界面1发起视频):
html
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<meta charset="utf-8">
<meta name="description" content="WebRTC code samples">
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
<meta itemprop="description" content="Client-side WebRTC code samples">
<meta itemprop="name" content="WebRTC code samples">
<meta name="mobile-web-app-capable" content="yes">
<meta id="theme-color" name="theme-color" content="#ffffff">
<!-- 引入2.0版本的socket.io文件 -->
<script src="socket.io.js"></script>
<script src="webrtc.js"></script>
<script src="jquery-3.6.4.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="css/main.css" />
<link rel="stylesheet" href="css/c1/main.css" />
</head>
<body>
<div id="container">
<video id="localVideo" title="a" playsinline autoplay muted></video>
<video id="remoteVideo" title="b" playsinline autoplay></video>
<div>
<button id="prepareBtn" type="button" onclick="prepare()">准备</button>
<button id="callBtn" type="button" onclick="callVideo()">呼叫</button>
<button id="cancelBtn" type="button" onclick="cancelVideo()">挂断</button>
</div>
</div>
<script>
const prepareButton = document.getElementById('prepareBtn');
const callBtn = document.getElementById('callBtn');
const cancelBtn = document.getElementById('cancelBtn');
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');
let localStream;
let pc1;
let pc2;
let to = '2';
var iceServer = {
{
// urls: 'stun:stun.l.google.com:19302'
urls: 'stun:stun.services.mozilla.com'
}
]
};
const offerOptions = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 0
};
//建立socket连接
const socket = io("https://192.168.3.21", {
reconnectionDelayMax: 10000,
auth: {
token: "123"
},
query: {
"userId": "1"
}
});
socket.on("connect", () => {
console.log("通道已建立")
});
//监听服务端发送的 topic1 消息
socket.on("exchange", (msg) => {
console.log("收到新的数据了");
var data = JSON.parse(msg)
console.log(data);
var type = data.type
if (type === 'invite') {
to = data.from
} else if (type === 'recive') {
to = data.from
} else if (type === 'canditate') {
if (data.data != undefined) {
pc1.addIceCandidate(new RTCIceCandidate(data.data))
}
} else if (type === 'offer') {
//设置远程应答
pc1.setRemoteDescription(new RTCSessionDescription(data.data))
pc1.createAnswer().then(function (answer) {
send({
type: 'answer',
data: answer
})
return pc1.setLocalDescription(answer)
}).then(sdp => {
})
} else if (type === 'answer') {
if (data.data != undefined) {
pc1.setRemoteDescription(new RTCSessionDescription(data.data))
}
}
});
function gotStream(stream) {
localVideo.srcObject = stream;
localStream = stream;
}
async function init() {
navigator.mediaDevices
.getUserMedia({
audio: true,
video: false
})
.then(gotStream)
.catch(e => alert(`getUserMedia() error: ${e.name}`));
}
async function prepare() {
init();
var data = {
type: 'invite',
data: 'video',
from: '1',
toUserId: '2'
};
// send(data);
prepareButton.disabled = true;
}
function call() {
pc1 = new RTCPeerConnection(iceServer);
pc1.onicecandidate = e => onIceCandidate(pc1, e);
// 有远程视频流时,显示远程视频流
pc1.addEventListener('track', event => {
// remoteVideo.srcObject = event.streams[0]
// remoteVideo.onloadedmetadata = function (e) {
// remoteVideo.play()
// }
})
pc1.addEventListener('addstream', e => {
console.log("AAAAAAAAAAA")
console.log(e);
remoteVideo.srcObject = e.stream
})
//初始化本人的视频流
navigator.mediaDevices.getUserMedia({
audio: false,
video: true
}).then(stream => {
// 将视频流写入到video标签
localVideo.srcObject = stream;
localStream = stream;
stream.getTracks().forEach(track => {
pc1.addTrack(track, stream)
});
//向对方发送应答
pc1.createOffer().then(sdp => {
pc1.setLocalDescription(sdp)
send({
type: 'offer',
data: sdp
})
})
})
localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));
callBtn.disabled = true;
}
function onIceCandidate(pc, event) {
if (event.candidate) {
send({
type: 'canditate',
data: event.candidate
})
}
}
function send(data) {
data.toUserId = data.toUserId || to
console.log(data)
socket.emit("exchange", JSON.stringify(data))
}
function callVideo() {
call();
}
function cancelVideo() {
if (pc1 != null && pc1 != undefined) {
pc1.close();
}
}
</script>
<style>
#video {
background-color: black;
height: 30vh;
}
</style>
</body>
</html>
3、前端界面2代码如下(当界面1发起视频呼叫后,该界面被动应答):
html
<!DOCTYPE html>
<html lang="zh">
<head>
<title>Socket.IO chat</title>
<meta charset="utf-8">
<meta name="description" content="WebRTC code samples">
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
<meta itemprop="description" content="Client-side WebRTC code samples">
<meta itemprop="name" content="WebRTC code samples">
<meta name="mobile-web-app-capable" content="yes">
<meta id="theme-color" name="theme-color" content="#ffffff">
<!-- 引入2.0版本的socket.io文件 -->
<script src="socket.io.js"></script>
<script src="webrtc.js"></script>
<script src="jquery-3.6.4.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="css/main.css" />
<link rel="stylesheet" href="css/c1/main.css" />
</head>
<body>
<div id="container">
<video id="localVideo" title="a" playsinline autoplay muted></video>
<video id="remoteVideo" title="b" playsinline autoplay></video>
</div>
<script>
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');
let localStream;
let pc1;
let pc2;
let to = '1';
var iceServer = {
{
// urls: 'stun:stun.l.google.com:19302'
urls: 'stun:stun.services.mozilla.com'
}
]
};
//建立socket连接
const socket = io("https://192.168.3.21", {
reconnectionDelayMax: 10000,
auth: {
token: "123"
},
query: {
"userId": "2"
}
});
socket.on("connect", () => {
console.log("通道已建立")
});
//监听服务端发送的 topic1 消息
socket.on("exchange", (msg) => {
console.log("收到新的数据了");
var data = JSON.parse(msg)
var type = data.type
console.log({
"name": "接收方",
data
});
if (type === 'invite') {
to = data.from
//打开自己的摄像头
init();
} else if (type === 'recive') {
to = data.from
} else if (type === 'canditate') {
if (pc1 == null) {
init();
}
if (data.data != undefined) {
pc1.addIceCandidate(new RTCIceCandidate(data.data))
}
} else if (type === 'offer') {
if (pc1 == null) {
init();
}
pc1.setRemoteDescription(new RTCSessionDescription(data.data))
pc1.createAnswer().then(function (answer) {
send({
type: 'answer',
data: answer
})
return pc1.setLocalDescription(answer)
}).then(sdp => {
})
} else if (type === 'answer') {
if (data.data != undefined) {
pc1.setRemoteDescription(new RTCSessionDescription(data.data))
}
}
});
function gotStream(stream) {
localVideo.srcObject = stream;
localStream = stream;
}
function init() {
navigator.mediaDevices
.getUserMedia({
audio: true,
video: false
})
.then(gotStream)
.catch(e => alert(`getUserMedia() error: ${e.name}`));
call();
}
function onIceCandidate(pc, event) {
if (event.candidate) {
send({
type: 'canditate',
data: event.candidate
})
}
}
function call() {
pc1 = new RTCPeerConnection(iceServer);
//获取本地网络信息,并发送给通信方
pc1.onicecandidate = e => onIceCandidate(pc1, e);
// 有远程视频流时,显示远程视频流
// pc1.addEventListener('track', event => {
// console.log("BBBBBBBBBBBBBBBBBBBBBBBBB")
// console.log(event);
// console.log(localVideo.srcObject)
// console.log("BBBBBBBBBBBBBBBBBBBBBBBBB+")
// remoteVideo.srcObject = event.streams[0]
// remoteVideo.onloadedmetadata = function (e) {
// console.log("加载完毕")
// remoteVideo.play()
// }
// })
pc1.addEventListener('addstream', e => {
// 将对方的视频流写入到video标签中
remoteVideo.srcObject = e.stream
})
//本地视频流量,打开视频流
navigator.mediaDevices.getUserMedia({
audio: false,
video: true
}).then(stream => {
// 将视频流写入到video标签中
localVideo.srcObject = stream;
localStream = stream;
stream.getTracks().forEach(track => {
pc1.addTrack(track, stream)
})
pc1.createOffer().then(sdp => {
pc1.setLocalDescription(sdp)
send({
type: 'offer',
data: sdp
})
})
})
}
function send(data) {
data.toUserId = data.toUserId || to
console.log({
"name": "发送",
data
})
socket.emit("exchange", JSON.stringify(data))
}
</script>
<style>
#video {
background-color: black;
height: 30vh;
}
</style>
</body>
</html>
WebRTC学习(六)端对端传输_51CTO博客_webrtc学习
4、关于 coturn 信令服务的安装,参考以下文档:coturn安装以及报错"coturn/src/apps/relay/netengine.c:316:对'SSL_CTX_up_ref'未定义的引用"_coturn 启动报错_Mango酱的博客-CSDN博客
5、coturn 安装后的测试:Trickle ICE (webrtc.github.io)
6、代码中进行如下设置:
javascript
//该参数为了
var iceServer = {
// iceServers: [{
// urls: 'stun:stun.l.google.com:19302'
// }]
iceServers: [{
urls: 'stun:stun.services.mozilla.com'
},
{
urls: 'turn:ip:3478',
credential: '密码',
username: '账号'
}
]
};