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

打印 上一主题 下一主题

主题 821|帖子 821|积分 2463

提示:局域网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工作流程

  1. // 推流拉流过程
  2. /**
  3.   * 推流端获取视频stream
  4.   * 推流端生成offer  
  5.   * 推流端通过offer设置推流LocalDescription
  6.   * 推流端发送offer给(拉)流端
  7.   * (拉)流端接收offer
  8.   * (拉)流端通过offer设置(拉)流端RemoteDescription
  9.   * (拉)流端生成answer
  10.   * (拉)流端通过answer设置(拉)流端LocalDescription
  11.   * (拉)流端发送answer给推流端
  12.   * 推流端接收answer设置推流端RemoteDescription
  13.   * 推流端发送candidate(video,audio各一次)
  14.   * (拉)流端接收candidate
  15.   * (拉)流端发送candidate(video,audio各一次)
  16.   * 推流端接收candidate
  17.   * **/
复制代码
三、推流端

   一个拉流RTCPeerConnection,对应一个推流RTCPeerConnection
X 个拉流RTCPeerConnection,对应X 个推流RTCPeerConnection
  push.html
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.   <title>推流</title>
  7. </head>
  8. <body>
  9.   <video id="webrtcVideo" autoplay></video>
  10.   <script>
  11.     const video = document.getElementById('webrtcVideo');
  12.     // webscoket
  13.     const ws = new WebSocket('ws://127.0.0.1:1990'); // 可换成局域网ip地址
  14.     let videoStream;
  15.     // 一个拉流RTCPeerConnection对应一个推流RTCPeerConnection,xx个拉流RTCPeerConnection,对应xx个推流RTCPeerConnection
  16.     const pushPool = {};
  17.     // rtc connection
  18.     let pushRtcCon;
  19.     // 打开摄像头,video标签播放视频流
  20.     const getStream = async () => {
  21.       if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)console.log('不支持:getUserMedia');
  22.       const stream = await navigator.mediaDevices.getUserMedia({video:true});
  23.       video.srcObject = stream;
  24.       videoStream = stream;
  25.     }
  26.     getStream();
  27.     // 开始推流
  28.     const startPush = (pullId) => {
  29.       if(!pushPool[pullId])pushPool[pullId] = pushRtcCon = new RTCPeerConnection();
  30.       // rtc connection 添加track
  31.       videoStream.getVideoTracks().forEach(track => {
  32.         pushRtcCon.addTrack(track,videoStream);
  33.       });
  34.       // 监听icecandidate
  35.       pushRtcCon.onicecandidate = (event)=>{
  36.         if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,id:pullId}))
  37.       }
  38.       // 创建offer
  39.       pushRtcCon.createOffer().then(offer=>{
  40.         console.log(offer)
  41.         // 设置推流LocalDescription
  42.         pushRtcCon.setLocalDescription(offer).then(()=>{ console.log('推流设置LocalDescription成功');});
  43.         // offer信息发送给拉流
  44.         ws.send(JSON.stringify({type:'offer',id:pullId,offer}))
  45.       });
  46.     }
  47.     // 开启websocket服务
  48.     ws.addEventListener('open',()=>{
  49.       // 初始化推流通道
  50.       ws.send(JSON.stringify({type:'push_init'}))
  51.       console.log('websocket连接成功')
  52.     });
  53.     // 接收wenbscoket信息
  54.     ws.addEventListener('message', (event) => {
  55.       let data = JSON.parse(event.data);
  56.       console.log(data)
  57.       // 接收到拉流传来的answer 设置推流RemoteDescription
  58.       if(data.type == 'answer')pushRtcCon.setRemoteDescription(data.answer).then(()=>{ console.log('推流设置RemoteDescription成功');});
  59.       // 接收拉流candidate 推流rtc connection 添加IceCandidate
  60.       if(data.type == 'candidate'&&data.candidate)pushRtcCon.addIceCandidate(data.candidate).then(()=>{ console.log('推流添加candidate成功');});
  61.       // 接收拉流开启消息 开始推流
  62.       if(data.type == 'pull_start')startPush(data.id);
  63.     })
  64.   </script>
  65. </body>
  66. </html>
复制代码
四、拉流

pull.html
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.   <title>Document</title>
  7. </head>
  8. <body>
  9.   <video id="pullVideo" autoplay preload muted></video>
  10.   <div id="pullBtn">拉流</div>
  11.   <script>
  12.     const pullBtn = document.getElementById('pullBtn');
  13.     // 开始拉流
  14.     const startPll = () =>{
  15.       let ws = new WebSocket('ws://127.0.0.1:1990'); // 可换成局域网ip地址
  16.       const pullVideo = document.getElementById('pullVideo');
  17.       let pullStrem;
  18.       // 拉流rtc connection
  19.       const pullRtcCon = new RTCPeerConnection();
  20.       const pullID = new Date().getTime()+'io'+Math.round(Math.random()*10000);
  21.       // 拉流监听icecandidate
  22.       pullRtcCon.onicecandidate = (event)=>{
  23.         // 接收到icecandidate  发送candidate给推流端
  24.         if(event.candidate)ws.send(JSON.stringify({type:'candidate',candidate:event.candidate,num:1,id:pullID}))
  25.       }
  26.       // 监听track
  27.       pullRtcCon.addEventListener('track' ,(event) => {
  28.         pullStrem = event.streams[0];
  29.         pullVideo.srcObject = event.streams[0];
  30.       })
  31.       // 打开webscoket
  32.       ws.addEventListener('open',async ()=>{
  33.         await ws.send(JSON.stringify({type:'pull_init',id:pullID}));
  34.         // 通知推流端,开始推流
  35.         ws.send(JSON.stringify({type:'pull_start',id:pullID}));
  36.         console.log('websocket连接成功')
  37.       });
  38.       // 监听webscoket消息
  39.       ws.addEventListener('message',(event)=>{
  40.         let data = JSON.parse(event.data);
  41.         // 接收到推流端offer
  42.         console.log(data,'????')
  43.         if(data.type == 'offer'){
  44.           // 设置拉流端 RemoteDescription
  45.           pullRtcCon.setRemoteDescription(data.offer).then(()=>{
  46.             console.log('拉流设置RemoteDescription成功')
  47.             // 创建answer
  48.             pullRtcCon.createAnswer(data.offer).then((answer)=>{
  49.               // 设置拉流的LocalDescription
  50.               pullRtcCon.setLocalDescription(answer).then(()=>{
  51.                 console.log('拉流设置LocalDescription成功')
  52.               });
  53.               // 发送answer到推流端
  54.               ws.send(JSON.stringify({type:'answer',answer,id:pullID}))
  55.             });
  56.           });
  57.         }
  58.         // 接收推流端candidate  拉流端添加IceCandidate
  59.         if(data.type == 'candidate')pullRtcCon.addIceCandidate(data.candidate).then(()=>{ console.log('拉流添加candidate成功');});
  60.       })
  61.     }
  62.     // 拉流按钮点击事件
  63.     pullBtn.addEventListener('click',startPll)
  64.   </script>
  65. </body>
  66. </html>
复制代码
五、socket服务

安装依靠
  1. npm init
  2. npm install nodejs-websocket -S
复制代码
index.js
  1. const ws = require('nodejs-websocket');
  2. const port = '1990';
  3. // 推流通道  拉流通道
  4. let wsPush,wsPull,pullPool={};
  5. const server = ws.createServer((connection)=>{
  6.   // websocket 连接接收数据
  7.   connection.on('text',(msg)=>{
  8.     let data = JSON.parse(msg);
  9.     // 初始化推流websocket
  10.     if(data.type == 'push_init')wsPush = connection;
  11.     // 初始化拉流websocket
  12.     if(data.type == 'pull_init')if(!pullPool[data.id]) pullPool[data.id] = connection;
  13.     // 接收推流消息 发送给拉流
  14.     if(connection == wsPush&&pullPool[data.id])pullPool[data.id].send(msg);
  15.     // 接收拉流消息 发送给推流
  16.     for(let key in pullPool){
  17.       if(connection == pullPool[key]&&wsPush)wsPush.send(msg);
  18.     }
  19.   })
  20.   // websocket 关闭
  21.   connection.on('close',()=>{
  22.     wsPush = null;wsPull = null;
  23.     console.log('通道关闭')
  24.   })
  25.   // websocket 报错
  26.   connection.on('err',(err)=>{
  27.     wsPush = null;wsPull = null;
  28.     console.log('通道报错:'+err)
  29.   })
  30. })
  31. server.listen(port,console.log('ws启动成功,127.0.0.1:'+port));
复制代码
六、效果

推流端

拉流端(点击拉流按钮)

七、备注

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

踩坑路漫漫长@~@

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

九天猎人

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表