提示:局域网socket版,一对多
文章目次
- 媒介
- 一、教程
- 二、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工作流程
- // 推流拉流过程
- /**
- * 推流端获取视频stream
- * 推流端生成offer
- * 推流端通过offer设置推流LocalDescription
- * 推流端发送offer给(拉)流端
- * (拉)流端接收offer
- * (拉)流端通过offer设置(拉)流端RemoteDescription
- * (拉)流端生成answer
- * (拉)流端通过answer设置(拉)流端LocalDescription
- * (拉)流端发送answer给推流端
- * 推流端接收answer设置推流端RemoteDescription
- * 推流端发送candidate(video,audio各一次)
- * (拉)流端接收candidate
- * (拉)流端发送candidate(video,audio各一次)
- * 推流端接收candidate
- * **/
复制代码 三、推流端
一个拉流RTCPeerConnection,对应一个推流RTCPeerConnection
X 个拉流RTCPeerConnection,对应X 个推流RTCPeerConnection
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');
- // webscoket
- const ws = new WebSocket('ws://127.0.0.1:1990'); // 可换成局域网ip地址
- let videoStream;
- // 一个拉流RTCPeerConnection对应一个推流RTCPeerConnection,xx个拉流RTCPeerConnection,对应xx个推流RTCPeerConnection
- const pushPool = {};
- // rtc connection
- let pushRtcCon;
- // 打开摄像头,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 = (pullId) => {
- if(!pushPool[pullId])pushPool[pullId] = pushRtcCon = new RTCPeerConnection();
- // rtc connection 添加track
- videoStream.getVideoTracks().forEach(track => {
- pushRtcCon.addTrack(track,videoStream);
- });
- // 监听icecandidate
- pushRtcCon.onicecandidate = (event)=>{
- if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,id:pullId}))
- }
- // 创建offer
- pushRtcCon.createOffer().then(offer=>{
- console.log(offer)
- // 设置推流LocalDescription
- pushRtcCon.setLocalDescription(offer).then(()=>{ console.log('推流设置LocalDescription成功');});
- // offer信息发送给拉流
- ws.send(JSON.stringify({type:'offer',id:pullId,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 设置推流RemoteDescription
- if(data.type == 'answer')pushRtcCon.setRemoteDescription(data.answer).then(()=>{ console.log('推流设置RemoteDescription成功');});
- // 接收拉流candidate 推流rtc connection 添加IceCandidate
- if(data.type == 'candidate'&&data.candidate)pushRtcCon.addIceCandidate(data.candidate).then(()=>{ console.log('推流添加candidate成功');});
- // 接收拉流开启消息 开始推流
- if(data.type == 'pull_start')startPush(data.id);
- })
- </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>Document</title>
- </head>
- <body>
- <video id="pullVideo" autoplay preload muted></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 connection
- const pullRtcCon = new RTCPeerConnection();
- const pullID = new Date().getTime()+'io'+Math.round(Math.random()*10000);
- // 拉流监听icecandidate
- pullRtcCon.onicecandidate = (event)=>{
- // 接收到icecandidate 发送candidate给推流端
- if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,num:1,id:pullID}))
- }
- // 监听track
- pullRtcCon.addEventListener('track' ,(event) => {
- pullStrem = event.streams[0];
- pullVideo.srcObject = event.streams[0];
- })
- // 打开webscoket
- ws.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);
- // 接收到推流端offer
- console.log(data,'????')
- if(data.type == 'offer'){
- // 设置拉流端 RemoteDescription
- pullRtcCon.setRemoteDescription(data.offer).then(()=>{
- console.log('拉流设置RemoteDescription成功')
- // 创建answer
- pullRtcCon.createAnswer(data.offer).then((answer)=>{
- // 设置拉流的LocalDescription
- pullRtcCon.setLocalDescription(answer).then(()=>{
- console.log('拉流设置LocalDescription成功')
- });
- // 发送answer到推流端
- ws.send(JSON.stringify({type:'answer',answer,id:pullID}))
- });
- });
- }
- // 接收推流端candidate 拉流端添加IceCandidate
- if(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,pullPool={};
- const server = ws.createServer((connection)=>{
- // websocket 连接接收数据
- connection.on('text',(msg)=>{
- let data = JSON.parse(msg);
- // 初始化推流websocket
- if(data.type == 'push_init')wsPush = connection;
- // 初始化拉流websocket
- if(data.type == 'pull_init')if(!pullPool[data.id]) pullPool[data.id] = connection;
- // 接收推流消息 发送给拉流
- if(connection == wsPush&&pullPool[data.id])pullPool[data.id].send(msg);
- // 接收拉流消息 发送给推流
- for(let key in pullPool){
- if(connection == pullPool[key]&&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地址访问
总结
踩坑路漫漫长@~@
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |