|
@@ -48,13 +48,13 @@
|
|
<center>
|
|
<center>
|
|
<video id = "localVideo" autoplay></video>
|
|
<video id = "localVideo" autoplay></video>
|
|
<video id = "remoteVideo" autoplay></video>
|
|
<video id = "remoteVideo" autoplay></video>
|
|
- <div class = "row text-center">
|
|
|
|
- <div class = "col-md-12">
|
|
|
|
- <button id = "hangUpBtn" class="btn-danger btn">
|
|
|
|
- <svg t="1730296252524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4292" width="30" height="30"><path d="M115.2 115.2c19.2-32 44.8-64 76.8-83.2 32-19.2 70.4-32 115.2-32H320c70.4 0 134.4 76.8 153.6 198.4 12.8 57.6 6.4 121.6-19.2 160-12.8 32-38.4 51.2-70.4 51.2l-12.8 12.8v12.8c19.2 38.4 38.4 76.8 64 108.8 19.2 32 44.8 64 70.4 96 6.4 6.4 12.8 6.4 19.2 6.4h6.4c12.8-19.2 32-38.4 57.6-44.8 44.8-6.4 115.2 12.8 179.2 57.6 96 70.4 140.8 166.4 108.8 230.4l-6.4 6.4c-19.2 38.4-44.8 70.4-83.2 89.6-160 96-409.6-38.4-576-307.2-128-198.4-166.4-428.8-96-563.2z m288 217.6c12.8-32 19.2-76.8 12.8-128-12.8-83.2-64-147.2-96-147.2h-12.8c-32 0-64 6.4-89.6 25.6-19.2 12.8-38.4 32-51.2 57.6-64 115.2-25.6 326.4 89.6 512 147.2 230.4 371.2 364.8 499.2 288 25.6-12.8 44.8-38.4 57.6-70.4 0 0 0-6.4 6.4-6.4v-6.4c19.2-32-19.2-102.4-89.6-153.6-44.8-32-102.4-51.2-134.4-44.8-12.8 6.4-19.2 12.8-19.2 19.2 0 0-12.8 25.6-44.8 32-19.2 6.4-44.8-6.4-64-25.6l-6.4-6.4c-25.6-32-51.2-64-76.8-102.4-25.6-38.4-44.8-83.2-64-121.6V448c-6.4-19.2-6.4-38.4 0-57.6 12.8-25.6 44.8-38.4 44.8-38.4h6.4c19.2 0 25.6-12.8 32-19.2z m217.6 12.8c6.4-12.8 19.2-19.2 32-12.8 32 6.4 51.2 25.6 64 51.2 12.8 25.6 12.8 51.2 6.4 76.8-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 6.4-12.8 0-25.6 0-32-6.4-12.8-19.2-19.2-25.6-25.6-19.2 0-25.6-19.2-19.2-38.4zM672 256c6.4-12.8 19.2-19.2 32-12.8 96 32 147.2 134.4 115.2 230.4-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 19.2-64-12.8-134.4-76.8-153.6-12.8-6.4-19.2-25.6-12.8-44.8 0 6.4 0 0 0 0z m25.6-115.2c6.4-12.8 19.2-19.2 32-12.8 76.8 25.6 140.8 83.2 179.2 153.6 38.4 76.8 44.8 160 19.2 236.8-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 19.2-64 19.2-134.4-12.8-192-32-57.6-83.2-102.4-147.2-128-12.8 0-19.2-19.2-12.8-38.4 0 6.4 0 0 0 0z m0 0" p-id="4293" fill="#ffffff"></path></svg>
|
|
|
|
- </button>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <div class = "row text-center">
|
|
|
|
+ <div class = "col-md-12">
|
|
|
|
+ <button id = "hangUpBtn" class="btn-danger btn">
|
|
|
|
+ <svg t="1730296252524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4292" width="30" height="30"><path d="M115.2 115.2c19.2-32 44.8-64 76.8-83.2 32-19.2 70.4-32 115.2-32H320c70.4 0 134.4 76.8 153.6 198.4 12.8 57.6 6.4 121.6-19.2 160-12.8 32-38.4 51.2-70.4 51.2l-12.8 12.8v12.8c19.2 38.4 38.4 76.8 64 108.8 19.2 32 44.8 64 70.4 96 6.4 6.4 12.8 6.4 19.2 6.4h6.4c12.8-19.2 32-38.4 57.6-44.8 44.8-6.4 115.2 12.8 179.2 57.6 96 70.4 140.8 166.4 108.8 230.4l-6.4 6.4c-19.2 38.4-44.8 70.4-83.2 89.6-160 96-409.6-38.4-576-307.2-128-198.4-166.4-428.8-96-563.2z m288 217.6c12.8-32 19.2-76.8 12.8-128-12.8-83.2-64-147.2-96-147.2h-12.8c-32 0-64 6.4-89.6 25.6-19.2 12.8-38.4 32-51.2 57.6-64 115.2-25.6 326.4 89.6 512 147.2 230.4 371.2 364.8 499.2 288 25.6-12.8 44.8-38.4 57.6-70.4 0 0 0-6.4 6.4-6.4v-6.4c19.2-32-19.2-102.4-89.6-153.6-44.8-32-102.4-51.2-134.4-44.8-12.8 6.4-19.2 12.8-19.2 19.2 0 0-12.8 25.6-44.8 32-19.2 6.4-44.8-6.4-64-25.6l-6.4-6.4c-25.6-32-51.2-64-76.8-102.4-25.6-38.4-44.8-83.2-64-121.6V448c-6.4-19.2-6.4-38.4 0-57.6 12.8-25.6 44.8-38.4 44.8-38.4h6.4c19.2 0 25.6-12.8 32-19.2z m217.6 12.8c6.4-12.8 19.2-19.2 32-12.8 32 6.4 51.2 25.6 64 51.2 12.8 25.6 12.8 51.2 6.4 76.8-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 6.4-12.8 0-25.6 0-32-6.4-12.8-19.2-19.2-25.6-25.6-19.2 0-25.6-19.2-19.2-38.4zM672 256c6.4-12.8 19.2-19.2 32-12.8 96 32 147.2 134.4 115.2 230.4-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 19.2-64-12.8-134.4-76.8-153.6-12.8-6.4-19.2-25.6-12.8-44.8 0 6.4 0 0 0 0z m25.6-115.2c6.4-12.8 19.2-19.2 32-12.8 76.8 25.6 140.8 83.2 179.2 153.6 38.4 76.8 44.8 160 19.2 236.8-6.4 12.8-19.2 25.6-38.4 19.2-12.8-6.4-25.6-19.2-19.2-38.4 19.2-64 19.2-134.4-12.8-192-32-57.6-83.2-102.4-147.2-128-12.8 0-19.2-19.2-12.8-38.4 0 6.4 0 0 0 0z m0 0" p-id="4293" fill="#ffffff"></path></svg>
|
|
|
|
+ </button>
|
|
</div>
|
|
</div>
|
|
|
|
+ </div>
|
|
</center>
|
|
</center>
|
|
</body>
|
|
</body>
|
|
<script src="/js/client/video.chat.js" type="text/javascript"></script>
|
|
<script src="/js/client/video.chat.js" type="text/javascript"></script>
|
|
@@ -70,72 +70,61 @@
|
|
return result ? decodeURIComponent(result[2]) : "";
|
|
return result ? decodeURIComponent(result[2]) : "";
|
|
}
|
|
}
|
|
|
|
|
|
- // 从URL参数中获取当前用户ID和目标用户ID
|
|
|
|
var userId = getUserParamByName("userId");
|
|
var userId = getUserParamByName("userId");
|
|
var targetUserId = getUserParamByName("targetUserId");
|
|
var targetUserId = getUserParamByName("targetUserId");
|
|
- var connectedUser = targetUserId;
|
|
|
|
|
|
|
|
- // 初始化WebSocket连接对象,用于信令服务器通信
|
|
|
|
|
|
+ //initiating a call
|
|
|
|
+ //our username
|
|
|
|
+ var connectedUser = targetUserId;
|
|
|
|
+ //connecting to our signaling server
|
|
var conn = new WebSocket("ws://"+wsHost+":"+wsPort+"/ws/video-chat/"+userId);
|
|
var conn = new WebSocket("ws://"+wsHost+":"+wsPort+"/ws/video-chat/"+userId);
|
|
conn.onopen = function () {
|
|
conn.onopen = function () {
|
|
console.log("Connected to the signaling server");
|
|
console.log("Connected to the signaling server");
|
|
};
|
|
};
|
|
|
|
|
|
- // 处理从信令服务器接收到的消息
|
|
|
|
- // 当WebSocket接收到信令服务器发送的消息时,触发此事件处理函数
|
|
|
|
|
|
+ //when we got a message from a signaling server
|
|
conn.onmessage = function (msg) {
|
|
conn.onmessage = function (msg) {
|
|
- console.log("Got message", msg.data); // 打印接收到的消息内容到控制台,用于调试
|
|
|
|
|
|
|
|
- // 解析从服务器接收到的JSON格式的消息数据
|
|
|
|
|
|
+ console.log("Got message", msg.data);
|
|
|
|
+
|
|
var data = JSON.parse(msg.data);
|
|
var data = JSON.parse(msg.data);
|
|
- // 根据消息类型进行不同的处理
|
|
|
|
switch(data.type) {
|
|
switch(data.type) {
|
|
- // 当消息类型为"offer"时,表示远端用户希望建立连接,并发送了他们的SDP(会话描述协议)信息
|
|
|
|
case "offer":
|
|
case "offer":
|
|
- // 调用handleOffer函数处理offer,设置远端描述,并创建answer响应
|
|
|
|
handleOffer(data.offer);
|
|
handleOffer(data.offer);
|
|
break;
|
|
break;
|
|
- // 当消息类型为"answer"时,表示远端用户对我们之前发送的offer做出了响应,并发送了他们的SDP信息
|
|
|
|
case "answer":
|
|
case "answer":
|
|
- // 调用handleAnswer函数处理answer,设置远端描述
|
|
|
|
handleAnswer(data.answer);
|
|
handleAnswer(data.answer);
|
|
break;
|
|
break;
|
|
- // 当消息类型为"candidate"时,表示远端用户发送了ICE候选信息,用于NAT穿透和连接建立
|
|
|
|
|
|
+ //when a remote peer sends an ice candidate to us
|
|
case "candidate":
|
|
case "candidate":
|
|
- // 调用handleCandidate函数处理ICE候选信息,添加到RTCPeerConnection中
|
|
|
|
handleCandidate(data.candidate);
|
|
handleCandidate(data.candidate);
|
|
break;
|
|
break;
|
|
- // 当消息类型为"leave"时,表示远端用户希望结束通话
|
|
|
|
case "leave":
|
|
case "leave":
|
|
- // 调用handleLeave函数处理离开事件,关闭连接并清理资源
|
|
|
|
handleLeave();
|
|
handleLeave();
|
|
break;
|
|
break;
|
|
- // 默认情况,不进行任何操作
|
|
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- // 处理WebSocket连接错误
|
|
|
|
conn.onerror = function (err) {
|
|
conn.onerror = function (err) {
|
|
console.log("Got error", err);
|
|
console.log("Got error", err);
|
|
};
|
|
};
|
|
|
|
|
|
- // 发送消息到信令服务器
|
|
|
|
|
|
+ //alias for sending JSON encoded messages
|
|
function send(message) {
|
|
function send(message) {
|
|
|
|
+ //attach the other peer username to our messages
|
|
conn.send(JSON.stringify(message));
|
|
conn.send(JSON.stringify(message));
|
|
}
|
|
}
|
|
|
|
|
|
- // 获取页面上的按钮和视频元素
|
|
|
|
var hangUpBtn = document.querySelector("#hangUpBtn");
|
|
var hangUpBtn = document.querySelector("#hangUpBtn");
|
|
var localVideo = document.querySelector("#localVideo");
|
|
var localVideo = document.querySelector("#localVideo");
|
|
var remoteVideo = document.querySelector("#remoteVideo");
|
|
var remoteVideo = document.querySelector("#remoteVideo");
|
|
|
|
|
|
- // 声明RTCPeerConnection对象和流对象
|
|
|
|
- var peerConnection;
|
|
|
|
|
|
+ var yourConn;
|
|
var stream;
|
|
var stream;
|
|
|
|
|
|
- // 检测浏览器是否支持WebRTC API
|
|
|
|
|
|
+ // callPage.style.display = "none";
|
|
var PeerConnection = (window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.RTCPeerConnection || undefined);
|
|
var PeerConnection = (window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.RTCPeerConnection || undefined);
|
|
var RTCSessionDescription = (window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.RTCSessionDescription || undefined);
|
|
var RTCSessionDescription = (window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.RTCSessionDescription || undefined);
|
|
navigator.getUserMedia = (navigator.getUserMedia ||
|
|
navigator.getUserMedia = (navigator.getUserMedia ||
|
|
@@ -143,10 +132,13 @@
|
|
navigator.mozGetUserMedia ||
|
|
navigator.mozGetUserMedia ||
|
|
navigator.msGetUserMedia);
|
|
navigator.msGetUserMedia);
|
|
|
|
|
|
- // 请求用户的音视频流
|
|
|
|
|
|
+ //getting local video stream
|
|
navigator.getUserMedia({ video: true, audio: true }, function (myStream) {
|
|
navigator.getUserMedia({ video: true, audio: true }, function (myStream) {
|
|
stream = myStream;
|
|
stream = myStream;
|
|
- localVideo.srcObject = stream; // 将本地流绑定到本地视频元素
|
|
|
|
|
|
+ // displaying local video stream on the page
|
|
|
|
+ localVideo.srcObject = stream;
|
|
|
|
+
|
|
|
|
+ // using Google public stun server
|
|
var configuration = {
|
|
var configuration = {
|
|
"iceServers": [
|
|
"iceServers": [
|
|
{
|
|
{
|
|
@@ -154,12 +146,19 @@
|
|
}
|
|
}
|
|
]
|
|
]
|
|
};
|
|
};
|
|
- peerConnection = new PeerConnection(configuration); // 创建RTCPeerConnection对象
|
|
|
|
- peerConnection.addStream(stream); // 将本地流添加到连接中
|
|
|
|
- peerConnection.onaddstream = function (e) {
|
|
|
|
- remoteVideo.srcObject = e.stream; // 将远程流绑定到远程视频元素
|
|
|
|
|
|
+
|
|
|
|
+ yourConn = new PeerConnection(configuration);
|
|
|
|
+
|
|
|
|
+ // setup stream listening
|
|
|
|
+ yourConn.addStream(stream);
|
|
|
|
+
|
|
|
|
+ //when a remote user adds stream to the peer connection, we display it
|
|
|
|
+ yourConn.onaddstream = function (e) {
|
|
|
|
+ remoteVideo.srcObject = e.stream;
|
|
};
|
|
};
|
|
- peerConnection.onicecandidate = function (event) {
|
|
|
|
|
|
+
|
|
|
|
+ // Setup ice handling
|
|
|
|
+ yourConn.onicecandidate = function (event) {
|
|
if (event.candidate) {
|
|
if (event.candidate) {
|
|
send({
|
|
send({
|
|
type: "candidate",
|
|
type: "candidate",
|
|
@@ -169,27 +168,31 @@
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
};
|
|
- // 创建一个offer描述
|
|
|
|
- peerConnection.createOffer(function (offer) {
|
|
|
|
|
|
+ // create an offer
|
|
|
|
+ yourConn.createOffer(function (offer) {
|
|
send({
|
|
send({
|
|
type: "offer",
|
|
type: "offer",
|
|
offer: offer,
|
|
offer: offer,
|
|
userId: userId,
|
|
userId: userId,
|
|
targetUserId: targetUserId
|
|
targetUserId: targetUserId
|
|
});
|
|
});
|
|
- peerConnection.setLocalDescription(offer);
|
|
|
|
|
|
+ yourConn.setLocalDescription(offer);
|
|
}, function (error) {
|
|
}, function (error) {
|
|
alert("Error when creating an offer");
|
|
alert("Error when creating an offer");
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+
|
|
}, function (error) {
|
|
}, function (error) {
|
|
console.log(error);
|
|
console.log(error);
|
|
});
|
|
});
|
|
|
|
|
|
- // 处理收到的offer
|
|
|
|
|
|
+ //when somebody sends us an offer
|
|
function handleOffer(offer) {
|
|
function handleOffer(offer) {
|
|
- peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
|
|
|
|
- peerConnection.createAnswer(function (answer) {
|
|
|
|
- peerConnection.setLocalDescription(answer);
|
|
|
|
|
|
+ yourConn.setRemoteDescription(new RTCSessionDescription(offer));
|
|
|
|
+
|
|
|
|
+ //create an answer to an offer
|
|
|
|
+ yourConn.createAnswer(function (answer) {
|
|
|
|
+ yourConn.setLocalDescription(answer);
|
|
send({
|
|
send({
|
|
type: "answer",
|
|
type: "answer",
|
|
answer: answer,
|
|
answer: answer,
|
|
@@ -201,34 +204,39 @@
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- // 处理收到的answer
|
|
|
|
|
|
+ //when we got an answer from a remote user
|
|
function handleAnswer(answer) {
|
|
function handleAnswer(answer) {
|
|
- peerConnection.setRemoteDescription(new RTCSessionDescription(answer));
|
|
|
|
|
|
+ yourConn.setRemoteDescription(new RTCSessionDescription(answer));
|
|
}
|
|
}
|
|
|
|
|
|
- // 处理收到的ICE候选
|
|
|
|
|
|
+ //when we got an ice candidate from a remote user
|
|
function handleCandidate(candidate) {
|
|
function handleCandidate(candidate) {
|
|
- peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
|
|
|
|
|
|
+ yourConn.addIceCandidate(new RTCIceCandidate(candidate));
|
|
}
|
|
}
|
|
|
|
|
|
- // 挂断按钮事件监听器
|
|
|
|
|
|
+ //hang up
|
|
hangUpBtn.addEventListener("click", function () {
|
|
hangUpBtn.addEventListener("click", function () {
|
|
|
|
+
|
|
send({
|
|
send({
|
|
type: "leave",
|
|
type: "leave",
|
|
userId: userId,
|
|
userId: userId,
|
|
targetUserId: targetUserId
|
|
targetUserId: targetUserId
|
|
});
|
|
});
|
|
|
|
+
|
|
handleLeave();
|
|
handleLeave();
|
|
});
|
|
});
|
|
|
|
|
|
- // 处理离开事件
|
|
|
|
function handleLeave() {
|
|
function handleLeave() {
|
|
connectedUser = null;
|
|
connectedUser = null;
|
|
remoteVideo.src = null;
|
|
remoteVideo.src = null;
|
|
- peerConnection.close(); // 关闭RTCPeerConnection
|
|
|
|
- peerConnection.onicecandidate = null;
|
|
|
|
- peerConnection.onaddstream = null;
|
|
|
|
- layer.closeAll(); // 关闭所有层(可能是第三方库函数)
|
|
|
|
|
|
+
|
|
|
|
+ yourConn.close();
|
|
|
|
+ yourConn.onicecandidate = null;
|
|
|
|
+ yourConn.onaddstream = null;
|
|
|
|
+ layer.closeAll();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
</script>
|
|
</script>
|
|
</html>
|
|
</html>
|