123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
- <title>webchat即时在线聊天室,视频通话</title>
- <link rel="stylesheet" href="/css/common/common.css">
- <link rel="stylesheet" href="/css/client/chat.css">
- <link href="/ref/layui-v2.6.8/layui/css/layui.css" rel="stylesheet" type="text/css" />
- <script src="/ref/jquery/jquery-3.4.1.js" type="text/javascript"></script>
- <script src="/ref/layui-v2.6.8/layui/layui.js" type="text/javascript"></script>
- <style>
- #remoteVideo {
- position: absolute;
- left: 0px;
- top: 0px;
- width: 450px;
- height: 620px;
- }
- #localVideo {
- position: absolute;
- right: 50px;
- top: 50px;
- width: 100px;
- border-radius: 10px;
- height: 75px;
- box-shadow: 0px 0px 10px #c8c7c7;
- }
- #hangUpBtn {
- position: absolute;
- bottom: 80px;
- left: 200px;
- width: 50px;
- height: 50px;
- border: none;
- border-radius: 100px;
- background-color: #fb5c5c;
- box-shadow: 0px 0px 10px #fb8d8d;
- }
- </style>
- </head>
- <body>
- <center>
- <video id = "localVideo" 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>
- </center>
- </body>
- <script src="/js/client/video.chat.js" type="text/javascript"></script>
- <script type="text/javascript">
- var wsHost = document.domain;
- // 如果你修改了application-dev.yml 中的端口号,这里的ws端口也要一块修改
- var wsPort = 8101;
- // 获取URL请求参数
- function getUserParamByName(key) {
- var url = window.location.search;
- var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
- var result = url.substr(1).match(reg);
- return result ? decodeURIComponent(result[2]) : "";
- }
- // 从URL参数中获取当前用户ID和目标用户ID
- var userId = getUserParamByName("userId");
- var targetUserId = getUserParamByName("targetUserId");
- var connectedUser = targetUserId;
- // 初始化WebSocket连接对象,用于信令服务器通信
- var conn = new WebSocket("ws://"+wsHost+":"+wsPort+"/ws/video-chat/"+userId);
- conn.onopen = function () {
- console.log("Connected to the signaling server");
- };
- // 处理从信令服务器接收到的消息
- // 当WebSocket接收到信令服务器发送的消息时,触发此事件处理函数
- conn.onmessage = function (msg) {
- console.log("Got message", msg.data); // 打印接收到的消息内容到控制台,用于调试
- // 解析从服务器接收到的JSON格式的消息数据
- var data = JSON.parse(msg.data);
- // 根据消息类型进行不同的处理
- switch(data.type) {
- // 当消息类型为"offer"时,表示远端用户希望建立连接,并发送了他们的SDP(会话描述协议)信息
- case "offer":
- // 调用handleOffer函数处理offer,设置远端描述,并创建answer响应
- handleOffer(data.offer);
- break;
- // 当消息类型为"answer"时,表示远端用户对我们之前发送的offer做出了响应,并发送了他们的SDP信息
- case "answer":
- // 调用handleAnswer函数处理answer,设置远端描述
- handleAnswer(data.answer);
- break;
- // 当消息类型为"candidate"时,表示远端用户发送了ICE候选信息,用于NAT穿透和连接建立
- case "candidate":
- // 调用handleCandidate函数处理ICE候选信息,添加到RTCPeerConnection中
- handleCandidate(data.candidate);
- break;
- // 当消息类型为"leave"时,表示远端用户希望结束通话
- case "leave":
- // 调用handleLeave函数处理离开事件,关闭连接并清理资源
- handleLeave();
- break;
- // 默认情况,不进行任何操作
- default:
- break;
- }
- };
- // 处理WebSocket连接错误
- conn.onerror = function (err) {
- console.log("Got error", err);
- };
- // 发送消息到信令服务器
- function send(message) {
- conn.send(JSON.stringify(message));
- }
- // 获取页面上的按钮和视频元素
- var hangUpBtn = document.querySelector("#hangUpBtn");
- var localVideo = document.querySelector("#localVideo");
- var remoteVideo = document.querySelector("#remoteVideo");
- // 声明RTCPeerConnection对象和流对象
- var peerConnection;
- var stream;
- // 检测浏览器是否支持WebRTC API
- var PeerConnection = (window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.RTCPeerConnection || undefined);
- var RTCSessionDescription = (window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.RTCSessionDescription || undefined);
- navigator.getUserMedia = (navigator.getUserMedia ||
- navigator.webkitGetUserMedia ||
- navigator.mozGetUserMedia ||
- navigator.msGetUserMedia);
- // 请求用户的音视频流
- navigator.getUserMedia({ video: true, audio: true }, function (myStream) {
- stream = myStream;
- localVideo.srcObject = stream; // 将本地流绑定到本地视频元素
- var configuration = {
- "iceServers": [
- {
- "urls": "stun:stun.l.google.com:19302"
- }
- ]
- };
- peerConnection = new PeerConnection(configuration); // 创建RTCPeerConnection对象
- peerConnection.addStream(stream); // 将本地流添加到连接中
- peerConnection.onaddstream = function (e) {
- remoteVideo.srcObject = e.stream; // 将远程流绑定到远程视频元素
- };
- peerConnection.onicecandidate = function (event) {
- if (event.candidate) {
- send({
- type: "candidate",
- candidate: event.candidate,
- userId: userId,
- targetUserId: targetUserId
- });
- }
- };
- // 创建一个offer描述
- peerConnection.createOffer(function (offer) {
- send({
- type: "offer",
- offer: offer,
- userId: userId,
- targetUserId: targetUserId
- });
- peerConnection.setLocalDescription(offer);
- }, function (error) {
- alert("Error when creating an offer");
- });
- }, function (error) {
- console.log(error);
- });
- // 处理收到的offer
- function handleOffer(offer) {
- peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
- peerConnection.createAnswer(function (answer) {
- peerConnection.setLocalDescription(answer);
- send({
- type: "answer",
- answer: answer,
- userId: userId,
- targetUserId: targetUserId
- });
- }, function (error) {
- alert("Error when creating an answer");
- });
- }
- // 处理收到的answer
- function handleAnswer(answer) {
- peerConnection.setRemoteDescription(new RTCSessionDescription(answer));
- }
- // 处理收到的ICE候选
- function handleCandidate(candidate) {
- peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
- }
- // 挂断按钮事件监听器
- hangUpBtn.addEventListener("click", function () {
- send({
- type: "leave",
- userId: userId,
- targetUserId: targetUserId
- });
- handleLeave();
- });
- // 处理离开事件
- function handleLeave() {
- connectedUser = null;
- remoteVideo.src = null;
- peerConnection.close(); // 关闭RTCPeerConnection
- peerConnection.onicecandidate = null;
- peerConnection.onaddstream = null;
- layer.closeAll(); // 关闭所有层(可能是第三方库函数)
- }
- </script>
- </html>
|