webrtc学习----前端推流拉流,局域网socket版,一对一

ops/2024/12/16 21:17:00/

提示:局域网socket版

文章目录

    • @[TOC](文章目录)
  • 前言
  • 一、教程
  • 二、webrtc工作流程
  • 三、推流端
  • 四、拉流
  • 五、socket服务
  • 六、效果
  • 七、备注
  • 总结

前言

‌‌‌‌‌WebRTC(Web Real-Time Communication)‌是一种实时通讯技术,允许网络应用或站点在不借助中间媒介的情况下,建立浏览器之间的点对点(Peer-to-Peer)连接,实现视频流、音频流或其他任意数据的传输。WebRTC的核心功能包括音视频的采集、编解码、网络传输和显示等‌

WebRTC的技术特点
‌1、实时通信‌:WebRTC专注于实时通信,包括音频、视频和其他数据传输‌。
‌2、点对点通信‌:WebRTC支持点对点通信,即两个浏览器之间直接建立连接,无需通过中间服务器‌。
‌3、多媒体引擎‌:WebRTC包含一个多媒体引擎,处理音频和视频流,并提供丰富的API和协议‌。
4‌、NAT穿越‌:WebRTC提供机制,使得在NAT(Network Address Translation)和防火墙等网络设备背后进行通信更为容易‌。
‌5、TURN服务器‌:当P2P连接无法建立时,WebRTC会利用TURN服务器进行数据中转,确保通信的稳定性‌

一、教程

webrtc文档

webrtc_22">二、webrtc工作流程

// 推流拉流过程
/*** 推流端获取视频stream* 推流端生成offer  * 推流端通过offer设置推流LocalDescription* 推流端发送offer给(拉)流端* (拉)流端接收offer* (拉)流端通过offer设置(拉)流端RemoteDescription* (拉)流端生成answer* (拉)流端通过answer设置(拉)流端LocalDescription* (拉)流端发送answer给推流端* 推流端接收answer设置推流端RemoteDescription* 推流端发送candidate(video,audio各一次)* (拉)流端接收candidate* (拉)流端发送candidate(video,audio各一次)* 推流端接收candidate* **/

三、推流端

push.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>推流</title>
</head>
<body><video id="webrtcVideo" autoplay></video><script>const video = document.getElementById('webrtcVideo');// webscoketconst ws = new WebSocket('ws://127.0.0.1:1990'); // 可换成局域网ip地址let videoStream;// rtc connectionconst pushRtcCon = new RTCPeerConnection();// 打开摄像头,video标签播放视频流const getStream = async () => {if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)console.log('不支持:getUserMedia');const stream = await navigator.mediaDevices.getUserMedia({video:true});video.srcObject = stream;videoStream = stream;}getStream();// 开始推流const startPush = () => {// rtc connection 添加trackvideoStream.getVideoTracks().forEach(track => {pushRtcCon.addTrack(track,videoStream);});// 监听icecandidatepushRtcCon.onicecandidate = (event)=>{if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,num:0}))}// 创建offerpushRtcCon.createOffer().then(offer=>{console.log(offer)// 设置推流LocalDescriptionpushRtcCon.setLocalDescription(offer).then(()=>{ console.log('推流设置LocalDescription成功');});// offer信息发送给拉流ws.send(JSON.stringify(offer))});}// 开启websocket服务ws.addEventListener('open',()=>{// 初始化推流通道ws.send(JSON.stringify({type:'push_init'}))console.log('websocket连接成功')});// 接收wenbscoket信息ws.addEventListener('message', (event) => {let data = JSON.parse(event.data);console.log(data)// 接收到拉流传来的answer 设置推流RemoteDescriptionif(data.type == 'answer')pushRtcCon.setRemoteDescription(data.answer).then(()=>{ console.log('推流设置RemoteDescription成功');});// 接收拉流candidate 推流rtc connection 添加IceCandidateif(data.type == 'candidate'&&data.candidate)pushRtcCon.addIceCandidate(data.candidate).then(()=>{ console.log('推流添加candidate成功');});// 接收拉流开启消息 开始推流if(data.type == 'pull_start')startPush();})</script>
</body>
</html>

四、拉流

pull.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>拉流</title>
</head>
<body><video id="pullVideo" autoplay></video><div id="pullBtn">拉流</div><script>const pullBtn = document.getElementById('pullBtn');// 开始拉流const startPll = () =>{let ws = new WebSocket('ws://127.0.0.1:1990'); // 可换成局域网ip地址const pullVideo = document.getElementById('pullVideo');let pullStrem;// 拉流rtc connectionconst pullRtcCon = new RTCPeerConnection();const pullID = new Date().getTime()+'io'+Math.round(Math.random()*10000);// 拉流监听icecandidatepullRtcCon.onicecandidate = (event)=>{// 接收到icecandidate  发送candidate给推流端if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,num:1,id:pullID}))}// 监听trackpullRtcCon.addEventListener('track' ,(event) => {pullStrem = event.streams[0];pullVideo.srcObject = event.streams[0];})// 打开webscoketws.addEventListener('open',async ()=>{await ws.send(JSON.stringify({type:'pull_init',id:pullID}));// 通知推流端,开始推流ws.send(JSON.stringify({type:'pull_start',id:pullID}));console.log('websocket连接成功')});// 监听webscoket消息ws.addEventListener('message',(event)=>{let data = JSON.parse(event.data);// 接收到推流端offerif(data.type == 'offer'){// 设置拉流端 RemoteDescriptionpullRtcCon.setRemoteDescription(data).then(()=>{console.log('拉流设置RemoteDescription成功')// 创建answerpullRtcCon.createAnswer(data.offer).then((answer)=>{// 设置拉流的LocalDescriptionpullRtcCon.setLocalDescription(answer).then(()=>{console.log('拉流设置LocalDescription成功')});// 发送answer到推流端ws.send(JSON.stringify({type:'answer',answer,id:pullID}))});});}// 接收推流端candidate  拉流端添加IceCandidateif(data.type == 'candidate')pullRtcCon.addIceCandidate(data.candidate).then(()=>{ console.log('拉流添加candidate成功');});})}// 拉流按钮点击事件pullBtn.addEventListener('click',startPll)</script>
</body>
</html>

五、socket服务

安装依赖

npm init
npm install nodejs-websocket -S

index.js

const ws = require('nodejs-websocket');
const port = '1990';// 推流通道  拉流通道
let wsPush,wsPull;
const server = ws.createServer((connection)=>{// websocket 连接接收数据connection.on('text',(msg)=>{let data = JSON.parse(msg);// 初始化推流websocketif(data.type == 'push_init')wsPush = connection;// 初始化拉流websocketif(data.type == 'pull_init')wsPull = connection;// 接收推流消息 发送给拉流if(connection == wsPush&&wsPull)wsPull.send(msg);// 接收拉流消息 发送给推流if(connection == wsPull&&wsPush)wsPush.send(msg);})// websocket 关闭connection.on('close',()=>{wsPush = null;wsPull = null;console.log('通道关闭')})// websocket 报错connection.on('err',(err)=>{wsPush = null;wsPull = null;console.log('通道报错:'+err)})
})
server.listen(port,console.log('ws启动成功,127.0.0.1:'+port));

六、效果

推流端
在这里插入图片描述
拉流端(点击拉流按钮)
在这里插入图片描述

七、备注

1、socket地址可换成局域网IP地址访问
2、pull来流请求地址可换成局域网IP地址访问

总结

踩坑路漫漫长@~@


http://www.ppmy.cn/ops/142463.html

相关文章

安全防御之备份恢复技术

随着计算机和网络的不断普及&#xff0c;人们更多的通过网络来传递大量信息。在网络环境下&#xff0c;还有各种各样的病毒感染、系统故障、线路故障等&#xff0c;使得数据信息的安全无法得到保障。由于安全风险的动态性&#xff0c;安全不是绝对的&#xff0c;信息系统不可能…

游戏引擎学习第41天

这一节就讨论了一些数学知识 讨论为什么要进行数学讨论 现在到了需要真正开始讨论数学的时候了&#xff0c;因为从这一步开始&#xff0c;几乎所有计划做的事情都将涉及比基本代数更复杂的数学内容。到目前为止所做的一切基本都可以用基础代数技能理解&#xff0c;但从现在开…

Linux更改远程默认SSL端口

1、登录Linux服务器 2、编辑ssh服务配置文件&#xff1a;vi /etc/ssh/sshd_config 光标移至“#Port 22”位置&#xff0c;按“i”进入编辑模式&#xff0c;然后键盘按一下回车键&#xff0c;新增一行 Port 2022 编辑好&#xff0c;先按ESC键&#xff0c;再输入:wq 保存退出.&…

git回退到指定提交版本

当把代码部署到服务器上后&#xff0c;发现有问题&#xff0c;代码跑不起来&#xff0c;要回退怎么办&#xff1f; 首先看git 日志 git log然后&#xff0c;找到具体要回退的commit号&#xff0c;使用git reset --hard xxx号 命令 git reset --hard aff2ebdb9c80ba7a5473152…

.net 8.0项目创建数据库链接

1 在项目的appsettings.json 文件中&#xff0c;添加 数据库链接字符串 "ConnectionStrings": {"DefaultConnection": "Server.;DatabaseDatabasename;User Idsa;Password123456;Encryptfalse;TrustServerCertificatetrue; " }, 注意 Encrypt…

初识行数据库与列数据库

在数据管理和处理领域&#xff0c;行数据库&#xff08;Row-oriented Database&#xff09;和列数据库&#xff08;Column-oriented Database&#xff09;是两种重要的数据组织方式。它们各自拥有独特的特性&#xff0c;适用于不同类型的应用场景。本文将深入探讨这两种数据库的…

读书|关于马斯克

于我而言&#xff0c;马斯克是一个有魅力的人&#xff0c;他张扬嚣张、却又一直做着惊世骇俗的事情。 关于健康 马斯克本身的工作就十分忙碌&#xff0c;但早年的他生活习惯也极其不规律&#xff0c;睡眠不足、饮食糊弄、懒得运动。健康三要素一个不占。另外&#xff0c; 42 …

代码随想录算法训练营第四十四天 | 583. 两个字符串的删除操作 | 72. 编辑距离

Day 44 总结 自己实现中遇到哪些困难今日收获&#xff0c;记录一下自己的学习时间 00:00 - 1:30 编辑距离总结篇 做一个总结吧 代码随想录 1035.不相交的线: 最长公共子序列 找二维dp数组里的 最大公共子序列长度, 2个选最大 if (nums1[i-1] nums2[j-1])dp[i][j] dp[i-1][j-1…