手把手教你使用WebRTC_webrtc教程-程序员宅基地

技术标签: webrtc  实时音视频  Android音视频开发  android  音视频开发  服务器  视频编解码  流媒体服务器  

WebRTC可以实现实时通信,他可以直接建立两个浏览器之间点对点的连接,在连接中实时传输媒体流和任何数据。这就非常适合进行屏幕共享。 WebRTC使用起来还是挺复杂的,具体的介绍MDN非常详细,不过网上各种,信令服务器,ICE,SDP,NAT的介绍弄得我晕头转向,所以我就找到一个简单的Demo,通过这个Demo来理解怎么使用。 一、创建RTCPeer 首先我们模拟创建两个pc端。直接通过RTCPeerConnection创建就好。

// 创建两个PeerConnection模拟两个客户端,pc1相当于本地,pc2相当于远端
const pc1 = new RTCPeerConnection();
const pc2 = new RTCPeerConnection();

二、交换ICE WebRTC使用了ICE(交互式连接设施)的框架协议,在建立连接之前两个客户端需要互相交换,简单的说就是交换网络信息,告知两个客户端互相的地址。 二、交换ICE

WebRTC使用了ICE(交互式连接设施)的框架协议,在建立连接之前两个客户端需要互相交换,简单的说就是交换网络信息,告知两个客户端互相的地址。

// 交换 ICE 候选
// 可以理解为通知pc2连接pc1的地址
pc1.onicecandidate = e => {
	pc2.addIceCandidate(e.candidate);
};
// 可以理解为通知pc1接pc2地址
pc2.onicecandidate = e => {
	pc1.addIceCandidate(e.candidate);
};

三、交换SDP

WebRTC使用了SDP(会话描述协议)去交换两端的媒体信息,比如说分辨率格式等信息,主要是交换双方的Offer和Answer,这两个信息叫做提议(Offer)和应答(Answer)非常的形象。

// 设置offer和answer,可理解为通知两边另一边的编解码等媒体信息
// 1.pc1创建offer
pc1.createOffer(displayMediaOptions)
  .then(desc => {
  // 2.pc1设置offer
  pc1.setLocalDescription(desc)
  // 3.pc2设置offer
  pc2.setRemoteDescription(desc)
  // 4.pc2创建answer
  pc2.createAnswer()
    .then(answerDesc => {
    // 5.pc2设置answer
    pc2.setLocalDescription(answerDesc)
    // 6.pc1设置answer
    pc1.setRemoteDescription(answerDesc)
  })
})

这里双方做的事就是存下自己的信息,然后发送和接收对方的Offer或Answer。步骤如下图所示。

免费分享】资料包括《Andoird音视频开发必备手册+音视频学习视频+学习文档资料包+大厂面试真题+2022最新学习路线图》等 

四、添加媒体

最后还有两件简单的事情需要处理,一个是添加需要传输的媒体,还有就是监听到媒体后使用video去播放。

//  将需要传输的流添加给PeerConnection
stream.getTracks().forEach(track => pc1.addTrack(track, stream));

//  远端接收到流,交给video去播放
pc2.ontrack = event => {
  if (videoTag.srcObject !== event.streams[0]) {
    videoTag.srcObject = event.streams[0];
  }
};

通过上面的这四个简单步骤我们实现了WebRTC最简单的一个实例。然后有的同学就会有质疑了,你这是在一个浏览器页面下进行的传输,作为端对端的传输能不能在两个页面下分别创建pc1和pc2?

五、信令服务器 经过了解,WebRTC只会负责端对端的连接,中间的数据传输,控制传输给谁,和谁建立连接都是他不管的,所以需要我们自己去传输。 通过WebSocket来把pc1和pc2之间的信息传递一下。然后就有了以下伪代码。这里只演示交换ICE候选,交换SDP同理。 PC1的代码:

const pc1 = new RTCPeerConnection();
const socket = 你创建的socket连接
// 交换 ICE 候选
pc1.onicecandidate = e => {
  socket.emit('ice的信息', e.candidate)
};

socket.on('ice的信息', data => {
  pc1.addIceCandidate(data);
})

PC2的代码:

const pc2 = new RTCPeerConnection();
const socket = 你创建的socket连接
// 交换 ICE 候选
pc2.onicecandidate = e => {
  socket.emit('ice的信息', e.candidate)
};

socket.on('ice的信息', data => {
  pc2.addIceCandidate(data);
})

看起来很简单不过经过测试后发现连不通,打印出传输后的消息发现传输后的消息都变成了普通对象。

然而在传输前他是一个RTCIceCandidate的对象

通过查阅API我们可以在传输后实例化这个对象就可以连接了

new RTCIceCandidate(data)

下图就是我们所需要进行的所有信息的传输步骤。

其实我们WebSocket做的事情在WebRTC中被叫做信令服务器,信令就是双方发送的所有信息,你可以通过任何形式传输这些信息,WebSocket也好Http请求也可以,因为信令服务器不需要理解这些中间信息,也不需要做额外的处理,唯一要做的就是把信息带到另外一方。 六、一对多实现 WebRTC只是一对一两端之间的通信,但是我们存在一对多的需求,不过这种需求量挺小的,所以我们采取了最简单的办法就是同一个客户端创建多个WebRTC。但是在业内也有更加优秀的解决方案,使用SFU Server 让服务器去模拟一个客户端与每个客户端之间建立联系,帮客户端分担压力,这样就把通讯压力放在了我们可控的服务端上了。效果如下图所示。

在继续优化你可以使用MCU Server 的方案,在服务器合并多路连接。

​七、NAT穿透 最后在项目提测前夕有发现一个大问题,之前开发两个浏览器端都是一台机测试,然后在两台设备上试了下发现一直连接不上,后来了解到是NAT和防火墙的原因导致双方无法通信。 WebRTC使用的ICE整合了STUN和TURN,STUN服务可以获取客户端的公网IP和端口,如果使用STUN依然无法建立连接就需要用到,TURN服务,可以中继所有的数据来绕过NAT。google提供了免费的STUN服务器,不过也可以自己搭建,搭建的话可以了解一下coturn。在WebRTC上配置对应的服务也非常简单。

const pc = new RTCPeerConnection({
  // 可以传入多个stun服务器或者turn服务器
  iceServers: [
    { url: 'stun:stun.l.google.com:19302' },
    { url: 'stun:stun1.l.google.com:19302' }
  ]
})

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yinshipin007/article/details/125825068

智能推荐

数据指标体系命名规范-程序员宅基地

文章浏览阅读3.8k次,点赞2次,收藏10次。原子指标定义原子指标 = 单一业务修饰词+基础指标词根,例如:支付金额-payment_amt命名规范派生指标定义派生指标 = 多业务修饰词+基础指标词根,派生指标继承原子指标的特性,例如:T+180体系课商品复购率,其中T+180是时间修饰词、体系课复购是业务修饰词、比率是基础指标词根命名规范日期类指标命名规范命名时要遵循:业务修饰词+基础指标词根+聚合修饰词(日期修饰词)。将日期后缀加到名称后面,如下图所示:聚合类型指标命名规范命名时要遵循:业务修饰词+基础指标词根+聚

怎样让一个div高度和浏览器高度一样_如何让div的高度等于浏览器可见区域的高度浏览器滚动div始终覆盖浏览器的整个-程序员宅基地

文章浏览阅读6.7k次,点赞2次,收藏2次。这个老生长谈的问题,不知困扰了多少前端开发人员,和后端程序员,其实很简单,这里写出来,让大家分享下,有很多人说,我已经设置div 100%了,怎么还没效果,我想说的是,有一个关键的东东,你没设置,html,body{height:100%;overflow:hidden;}哈哈,这回你会了吧,要同时设置。_如何让div的高度等于浏览器可见区域的高度浏览器滚动div始终覆盖浏览器的整个

cisco 2960 VLAN MAC_盘点Mac上的触控板(鼠标)增强工具-程序员宅基地

文章浏览阅读147次。今天小编给大家推荐几款Mac上好用的触控板/鼠标增强工具,拥有这些软件可以为触控板添加各种自定义的快捷键和手势动作,为鼠标的右键菜单添加功能,提高工作效率。一、BetterTouchTool触控板功能增强软件,一款专为Mac用户开发的Magic Mouse鼠标功能增强制作的软件。可以触发任意键盘快捷键和100多个预定义操作的组合,您几乎可以控制Mac的每个方面。BetterTouchTool fo...

cas 单点登录服务端客户端配置-程序员宅基地

文章浏览阅读124次。首先,下载cas-server-3.5.2-releasehttp://pan.baidu.com/s/1GJ8Gscas-client-3.2.1-releasehttp://pan.baidu.com/s/1glKFB提供俩个下载地址:先从服务端配置:我是新建一个web工程cas-server将 建几个文件夹src/libssrc/loc...

CSS 设置文字间距_css字间距-程序员宅基地

文章浏览阅读4.7w次,点赞17次,收藏53次。一、css word-spacing属性设置字间距(单词的间距)word-spacing 属性增加或减少单词间的空白(即字间隔);在这个属性中,“字” 定义为由空白符包围的一个字符串。也就是说该属性是以空格为基准进行调节间距的,如果多个字母被连在一起,则会被word-spacing视为一个单词;如果汉字被空格分隔,则分隔的多个汉字就被视为不同的单词,word-spacing属性此时有效。语法:word-spacing:值;normal:定义单词间的标准空间,默认值。 length:定义单词间的固定空_css字间距

关于安卓蓝牙2.0的app开发原理-程序员宅基地

文章浏览阅读805次。最近时间比较宽裕,觉得自己可以写一些东西来总结一下工作,索性就写一篇关于安卓蓝牙的开发总结吧安卓蓝牙开发其实也就是socket的开发,同时分为服务端和客户端,下面我就按照我的开发流程来降整个的安卓蓝牙2.0开发叙述一下,蓝牙4.0BLE我也会在之后给大家更新首先,我们要注册蓝牙相关的广播并在manifest中给出相应的权限(安卓6.0之后由于相应的底层改变,注册权限的时候不仅要给蓝牙的权限

随便推点

matplotlib绘制多张图、多子图、多例图_matplotlib同时绘制8个图-程序员宅基地

文章浏览阅读1.7k次。绘制多图关键:fig = plt.figure(1) 表示新建第几个图import matplotlib.pyplot as pltfig = plt.figure(1)plt_rec_loss = [1,2,3,4,5,6]plt_rec_recall = [4,3,6,5,8,9]plt.xlabel("epoch")plt.ylabel("loss")plt.plot(r..._matplotlib同时绘制8个图

RHCSA第五天作业-程序员宅基地

文章浏览阅读208次。1、新建几个普通用户wukong,wuneng,wujing,他们都属于xiyouji组的成员,其中wujing没有和系统交互的shell。[root@localhost ~]# groupadd xiyouji[root@localhost ~]# useradd -g xiyouji wukong[root@localhost ~]# useradd -g xiyouji wuneng[root@localhost ~]# useradd -g xiyouji wujing[root@loc

一个好用的数据分析工具:Cftool-程序员宅基地

文章浏览阅读4.8k次。同事最近在做数据分析,计算完全依赖于计算器,然后一个小规模的矩阵,就是用计算器一个个算出来;程序员看不下去,给他写了个exe,cmd下输入要求的数据,就直接给输出了。今天他在做数据分析,给了x-y数据,让我找拟合关系。先前接触过cftool,于是直接拿来用了:将x\y按照同样维度格式输入;命令行输入cftool,会出现一个窗口;将x\y数据加载;选择权重关系(同样权重就忽略此项);...

OpenCL错误码转字符串_cl_exec_status_error_for_events_in_wait_list-程序员宅基地

文章浏览阅读638次。OpenCL错误码转字符串(以中文表示)错误代码位:0 ~ -19、-30 ~ -68const char* errorCodeToString(cl_int errCode) { const char* err = NULL; switch (errCode) { case CL_SUCCESS: err = "CL_SUCCESS:命令成功执行,没有出现错误!"; break..._cl_exec_status_error_for_events_in_wait_list

获取本年、本月、本周时间范围_js获取时间(本周、本季度、本月..)-程序员宅基地

文章浏览阅读1k次。Js代码/*** 获取本周、本季度、本月、上月的开端日期、停止日期*/var now = new Date(); //当前日期var nowDayOfWeek = now.getDay(); //今天本周的第几天var nowDay = now.getDate(); //当前日var nowMonth = now.getMonth(); //当前月var nowYear = now.getYear..._js 本周 本月 时间段

GD32三种低功耗例程-程序员宅基地

文章浏览阅读1.1w次,点赞5次,收藏25次。GD32F303ZET6低功耗例程,睡眠模式、深度睡眠模式、待机模式

推荐文章

热门文章

相关标签