当前位置: 首页 > news >正文

前端WebRTC局域网1V1视频通话

基本概念

WebRTC(Web Real-Time Communications)

网络实时通讯,它允许网络应用或者站点,在不借助中间媒介的情况下,建立点对点(Peer-to-Peer)的连接,实现视频流和音频流或者其他任意数据的传输

NAT(Network Address Translation)

网络地址转换协议,用来给私网设备映射一个公网的 IP 地址

STUN(Session Traversal Utilities for NAT)

会话穿透,通过NAT找到公网地址进行P2P通信

TURN(Traversal Using Relay around NAT)

中继转发,当STUN不可用时,通过TURN转发音视频数据,显然这样是开销最大的
开源STUN&TURN服务器:coturn

ICE(Interactive Connectivity Establishment)

交互式连接建立,即网络信息
candidate:候选,优先级为:局域网、STUN、TURN

SDP(Session Description Protocol)

会话描述协议,即媒体信息,不是音视频流,在WebRTC中分为offer和answer

Signaling Server

信令服务器,用来交换ICE和SDP信息,WebRTC未做规定,自己选择实现技术,比如WebSocket

局域网视频通信

局域网不需要STUN/TURN服务器,只需信令服务器,这里使用Node.js ws库实现

效果

在这里插入图片描述

代码

客户端 index.html
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>WebRTC Demo</title><style>button {margin: 1rem;}video {width: 300px;}</style>
</head><body><div><div>信令服务器地址:<input id="inputServer" value="ws://192.168.205.165:8888" /><button onclick="start()">开始</button></div><video id="localVideo" autoplay muted></video><video id="remoteVideo" autoplay muted></video></div><script>const inputServer = document.querySelector("#inputServer");const remoteVideo = document.querySelector("#remoteVideo");const localVideo = document.querySelector("#localVideo");let peerConn;let webSocket;let localStream;// 打开本地摄像头navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((mediaStream) => {localStream = mediaStream;localVideo.srcObject = mediaStream;}).catch((err) => {console.error(err);});// 创建WebRTC连接peerConn = new RTCPeerConnection();peerConn.addEventListener('icecandidate', (event) => {if (event.candidate) {webSocket.send(JSON.stringify({type: "ice",candidate: event.candidate}));}});peerConn.addEventListener("track", (event) => {remoteVideo.srcObject = event.streams[0];});function start() {// 连接信令服务器webSocket = new WebSocket(inputServer.value);webSocket.addEventListener('open', () => {webSocket.send(JSON.stringify({type: "join"}));});// 收到服务端消息webSocket.addEventListener('message', (event) => {const msg = JSON.parse(event.data);console.log(msg);switch (msg.type) {case "sendOffer":peerConn.addTrack(localStream.getVideoTracks()[0], localStream);peerConn.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true }).then((offer) => {peerConn.setLocalDescription(offer).then(() => {webSocket.send(JSON.stringify(offer));})});break;case "offer":peerConn.addTrack(localStream.getVideoTracks()[0], localStream);peerConn.setRemoteDescription(msg).then(() => {peerConn.createAnswer().then((answer) => {peerConn.setLocalDescription(answer).then(() => {webSocket.send(JSON.stringify(answer));})})});break;case "answer":peerConn.setRemoteDescription(msg);break;case "ice":peerConn.addIceCandidate(msg.candidate);break;default:}});webSocket.addEventListener('close', () => {console.log("websocket close");});}</script>
</body></html>
服务端 server.mjs
import { WebSocketServer } from 'ws';const wss = new WebSocketServer({ port: 8888 });let clients = []; // 已连接的客户端wss.on('connection', function connection(ws) {ws.on('message', function message(rawData) {const data = rawData.toString();const obj = JSON.parse(data);console.log("type", obj.type);switch (obj.type) {case "join":if (clients.length < 2) {clients.push(ws);if (clients.length === 2) {clients[0].send(JSON.stringify({ type: "sendOffer" }));}} else {console.log("room is full");}break;case "offer":clients[1].send(data);break;case "answer":clients[0].send(data);break;case "ice":clients.forEach((item) => {if (item !== ws) {item.send(data);}})break;default:}});ws.on('error', (err) => console.error("error:", err));ws.on('close', (code) => {console.log("ws close", code);clients = clients.filter((item) => {if (item === ws) {item = null;return false;}return true;});});
});

使用

  1. 在文件目录运行命令:node server.mjs
  2. 修改信令服务器地址,浏览器打开 index.html
  3. 将 index.html 复制到另一台电脑上用浏览器打开
  4. 允许使用摄像头和麦克风,两边点击开始按钮即可

参考资料

WebRTC_API
前端使用WebRTC

相关文章:

前端WebRTC局域网1V1视频通话

基本概念 WebRTC&#xff08;Web Real-Time Communications&#xff09; 网络实时通讯&#xff0c;它允许网络应用或者站点&#xff0c;在不借助中间媒介的情况下&#xff0c;建立点对点&#xff08;Peer-to-Peer&#xff09;的连接&#xff0c;实现视频流和音频流或者其他任…...

设计模式之构建者模式

构建者模式&#xff08;Builder&#xff09; 定义 将一个复杂对象的构建与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示 使用场景 主要角色 产品 Product建造者接口 Builder具体的建造者 Concrete Builder指挥者 Director:组织构建过程 示例代码 Data p…...

【PCIe 链路训练】之均衡(equalization)

1、概述 这篇文章简单介绍一下PCIE phy的均衡原理和过程,USB phy,ethernet phy这些高速的串行serdes也有相同或者相似的结构。可以不用太关注其中的细节,等到debug的时候可以查询协议,但是需要了解这个故事讲的大概内容。整个equalization过程是controller和phy一起配合完成…...

P1059 [NOIP2006 普及组] 明明的随机数

题目描述 明明想在学校中请一些同学一起做一项问卷调查&#xff0c;为了实验的客观性&#xff0c;他先用计算机生成了 N 个 1 到 1000 之间的随机整数 (N≤100)&#xff0c;对于其中重复的数字&#xff0c;只保留一个&#xff0c;把其余相同的数去掉&#xff0c;不同的数对应着…...

【每日一问】Cookie、Session 和 Token 有什么区别?

Cookie、Session 和 Token 通常都是用来保存用户登录信息的技术&#xff0c;但三者有很大的区别&#xff0c;简单来说 Cookie 适用于简单的状态管理&#xff0c;Session 适用于需要保护用户敏感信息的场景&#xff0c;而 Token 适用于状态无关的身份验证和授权。 具体来说&…...

智能合约语言(eDSL)—— proc_macro实现合约init函数

我们通过属性宏来实现合约的init函数&#xff0c;call函数其实和init是类似的&#xff1b; GitHub - XuHugo/xwasm 构建属性宏&#xff0c;要在cargo.toml里面设置一些参数&#xff0c;这是必须的。一般来说&#xff0c;过程宏必须是一个库&#xff0c;或者作为工程的子库&…...

如何使用 ArcGIS Pro 制作三维地形图

伴随硬件性能的提高和软件算法的优化&#xff0c;三维地图的应用场景会越来越多&#xff0c;这里为大家介绍一下在ArcGIS Pro怎么制作三维地形图&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的DEM和影像数据&#xff0c;除了DEM和影像数据…...

服务器配置禁止IP直接访问,只允许域名访问

联网信息系统需设置只允许通过域名访问&#xff0c;禁止使用IP地址直接访问&#xff0c;建议同时采用云防护技术隐藏系统真实IP地址且只允许云防护节点IP访问服务器&#xff0c;提升网络安全防护能力。 一、Nginx 修改配置文件nginx.conf&#xff0c;在server段里插入正则表达式…...

#14vue3生成表单并跳转到外部地址的方式

1、背景 后端返回的json数据中包含一个json数组&#xff0c;此数组中是目标跳转地址所需要的form表单的数据。 2、跳转前的页面 const goto () > {finish.value true;request.post(/xxx/yyy,{zzz: zzz.value}).then(res > {const url res.data.submitUrlconst params…...

航测管家:智能化革新航测作业流程

在信息时代的浪潮中&#xff0c;倾斜摄影作为一种高效的航测技术&#xff0c;对于城市规划、土地管理、环境监测等领域的重要性日益凸显。然而&#xff0c;航测作业中的数据管理和设备操作复杂性一直是行业面临的挑战。深圳赛尔智控推出的赛尔航测管家&#xff0c;凭借其智能化…...

XXE-XML实体注入漏洞

目录 1.xml基础 1.1什么是xml 1.2xml文档结构 1.3 什么是DTD 1.4 什么是实体 1.5 什么是外部实体 2.xxe漏洞 2.1xxe漏洞基本介绍 2.2xxe漏洞的危害 经典漏洞案例分析 3.xxe漏洞挖掘和利用 3.1. 识别潜在的XML入口 3.2. 检查XML处理逻辑 3.3. 构造试探Payload 常…...

数据结构从入门到精通——栈

栈 前言一、栈1.1栈的概念及结构1.2栈的实现1.3栈的面试题 二、栈的具体实现代码栈的初始化栈的销毁入栈出栈返回栈顶元素返回栈中的元素个数检测是否为空Stack.hStack.ctest.c 前言 栈&#xff0c;作为一种后进先出&#xff08;LIFO&#xff09;的数据结构&#xff0c;在计算…...

webhook详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 webhook简介 在当今高度连接的网络世界中,没有什么可以孤立地发挥最佳作用。完成一项任务(几乎)总是需要多个实体的参与。电子商务应用程序需要与支付系统通信,支付…...

用 ChatGPT 帮自己修英文简历 — UI/UX 设计师篇

用 ChatGPT 帮自己修英文简历 — UI/UX 设计师篇 之所以能写这篇文章&#xff0c;主要是我本身是 AI 工具的重度使用者&#xff0c;在工作上目前大量依赖 GitHub Copilot 与 ChatGPT 等工具&#xff0c;所以算是有一些心得可以分享。我自己觉得要能发挥这类工具最大的效用&…...

2402. 2-SAT 问题(tarjan,2-SAT模板题)

活动 - AcWing 给定 n 个还未赋值的布尔变量 x1∼xn。 现在有 m 个条件&#xff0c;每个条件的形式为 “xi 为 0/1 或 xj 为 0/1 至少有一项成立”&#xff0c;例如 “x1 为 1 或 x3 为 0”、“x8 为 0 或 x4 为 0” 等。 现在&#xff0c;请你对这 n 个布尔变量进行赋值&am…...

基于java+springboot+vue实现的宠物健康咨询系统(文末源码+Lw)23-206

摘 要 本宠物健康咨询系统分为管理员还有用户两个权限&#xff0c;管理员可以管理用户的基本信息内容&#xff0c;可以管理公告信息以及宠物健康知识信息&#xff0c;能够与用户进行相互交流等操作&#xff0c;用户可以查看宠物健康知识信息&#xff0c;可以查看公告以及查看…...

品牌如何玩转饥饿营销?媒介盒子分享

饥饿营销是许多品牌都会用的策略&#xff0c;从“限定发售”、“先到先得”、“季节限定”、“专属VIP”等都属于饥饿营销的范畴&#xff0c;为什么饥饿营销屡试不爽&#xff0c;原因就在于人们面对同等的收益和损失时&#xff0c;损失会令他们更加难以接受。今天媒介盒子就来和…...

Vue3:ref和reactive实现响应式数据

一、情景说明 在Vue2中&#xff0c;我们已经知道数据的响应式&#xff0c;是什么含义 就是&#xff0c;在data块中&#xff0c;定义的变量&#xff0c;在页面中引用后 任何地方修改了该变量&#xff0c;页面中引用的变量会立即显示最新数值。 这块&#xff0c;我们学习了 插值…...

二维码门楼牌管理系统应用场景:商业与零售业发展的助推器

文章目录 前言一、二维码门楼牌管理系统的基本功能二、商业和零售业中的应用场景三、二维码门楼牌管理系统的优势分析四、结论 前言 在数字化时代的浪潮中&#xff0c;二维码门楼牌管理系统凭借其独特的优势&#xff0c;正在逐步成为商业和零售业发展的新宠。它不仅能够为商家…...

【Linux进阶之路】网络 —— “?“ (下)

文章目录 前言一、概念铺垫1.TCP2.全双工 二、网络版本计算器1. 原理简要2. 实现框架&&代码2.1 封装socket2.2 客户端与服务端2.3 封装与解包2.4 请求与响应2.5 对数据进行处理2.6 主程序逻辑 3.Json的简单使用 总结尾序 前言 在上文我们学习使用套接字的相关接口进行了…...

【AIGC】Stable Diffusion的建模思想、训练预测方式快速

在这篇博客中&#xff0c;将会用机器学习入门级描述&#xff0c;来介绍Stable Diffusion的关键原理。目前&#xff0c;网络上的使用教程非常多&#xff0c;本篇中不会介绍如何部署、使用或者微调SD模型。也会尽量精简语言&#xff0c;无公式推导&#xff0c;旨在理解思想。让有…...

JVM(类加载机制)

类加载就是 .class 文件, 从文件(硬盘) 被加载到内存(元数据区)中的过程 类加载的过程 加载: 找 .class 文件的过程, 打开文件, 读文件, 把文件读到内存中 验证: 检查 .class 文件的格式是否正确 .class 是一个二进制文件, 其格式有严格的说明 准备: 给类对象分配内存空间 (先在…...

C++ 实战项目之 Boost 搜索引擎

项目地址&#xff1a;https://gitee.com/Vertas/boost-searcher-project 1. 项目背景 日常生活中我们使用过很多搜索引擎&#xff0c;比如百度&#xff0c;搜狗&#xff0c;360搜索等。我们今天是要实现一个像百度这样的搜索引擎嘛&#xff1f;那是不可能的&#xff0c;因为像…...

部署LVS+Keepalived高可用群集(抢占模式,非抢占模式,延迟模式)

目录 一、LVSKeepalived高可用群集 1、实验环境 2、 主和备keepalived的配置 2.1 yum安装ipvsadm和keepalived工具 2.2 添加ip_vs模块并开启ipvsadm 2.3 修改keepalived的配置文件 2.4 调整proc响应参数&#xff0c;关闭linux内核的重定向参数响应 2.5 将主服务器的kee…...

性别和年龄的视频实时监测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 性别和年龄检测 Python 项目 首先介绍性别和年龄检测的高级Python项目中使用的专业术语 什么是计算机视觉&#xff1f; 计算机视觉是使计算机能…...

【Spring面试题】

目录 前言 1.Spring框架中的单例bean是线程安全的吗? 2.什么是AOP? 3.你们项目中有没有使用到AOP&#xff1f; 4.Spring中的事务是如何实现的&#xff1f; 5.Spring中事务失效的场景有哪些&#xff1f; 6.Spring的bean的生命周期。 7.Spring中的循环引用 8.构造方法…...

打车代驾小程序开发 醉酒不用怕一键找代驾

近年来&#xff0c;随着我国私家车市场的不断扩大&#xff0c;驾驶员的安全驾驶意识不断提高&#xff0c;以及交通法规对酒后驾驶的严格把握&#xff0c;代驾市场的潜力也在迸发。代驾小程序开发平台成为了代驾人不可或缺的线上接单平台。那么代驾小程序开发需要实现哪些功能呢…...

蓝桥集训之统计子矩阵

统计子矩阵 核心思想&#xff1a;矩阵前缀和 双指针 用i和j双指针 遍历所有子矩阵的列用s和t双指针 遍历所有子矩阵的行求其子矩阵的和 若>k 将s向下移动 矩阵和必定减小(元素个数减少)直到满足<k 因为列一定 行数即为方案数(从t行往上数到s行 共t-s1个区间[t,t][t-1,t]…...

架构师十项全能 你会几个?

架构设计导论 架构师核心能力 架构设计原则 架构设计模式 架构设计核心维度 架构图绘制 企业架构设计 分布式架构理论 微服务架构设计 响应式架构设计 架构设计评估 单元化架构设计 服务网络架构设计 DDD领域驱动设计 技术选型 服务治理设计 安全架构设计 云架构设计 数据库架构…...

数据库(mysql)-新手笔记(主外键,视图)

主外键 主键(唯一性,非空性) 主键是数据库表中的一个或多个字段&#xff0c;其值唯一标识表中的每一行/记录。 唯一性: 主键字段中的每个值都必须是唯一的&#xff0c;不能有两个或更多的记录具有相同的主键值 非空性&#xff1a;主键字段不能包含NULL值。 外键(引用完整 …...