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

WebRTC 的核心:RTCPeerConnection

WebRTC 的核心:RTCPeerConnection

  • WebRTC 的核心:RTCPeerConnection
    • 创建 RTCPeerConnection 对象
    • RTCPeerConnection 与本地音视频数据绑定
    • 媒体协商
    • ICE
      • 什么是 Candidate?
      • 收集 Candidate
      • 交换 Candidate
      • 尝试连接
    • SDP 与 Candidate 消息的互换
    • 远端音视频渲染
    • 参考

WebRTC 的核心:RTCPeerConnection

RTCPeerConnection 是 WebRTC API 中的一个对象,它提供了两个浏览器之间的实时通信。它使用音频、视频和数据流来进行点对点通讯,没有中介服务器的参与。这是一个极其有用的特性,使得实时通信变得更加高效和私密。

RTCPeerConnection的作用是在两个浏览器之间建立WebRTC通信通道。它使用ICE(Interactive Connectivity Establishment)协议决定浏览器之间的最佳路径来传输音频、视频和数据流。它让浏览器之间的网络连接变得简单、快捷和高效。
RTCPeerConnection API可以用于:

  1. 视频会议
  2. 实时游戏
  3. 文件共享
  4. 流媒体
  5. 实时语音聊天

创建 RTCPeerConnection 对象

语法:

new RTCPeerConnection()
new RTCPeerConnection(configuration)

参数 configuration 是一个 JSON 对象,用于提供配置新连接的选项。

在这里插入图片描述

  1. iceServers:一个由 RTCIceServer 对象组成的数组,每个对象描述一个可能被 ICE 代理使用的服务器。这些通常是 STUN 或 TURN 服务器。如果未指定,则将在没有可用的 STUN 或 TURN 服务器的情况下进行连接尝试,这将连接限制为本地对等点。
  2. iceTransportPolicy:当前的 ICE 传输策略。如果未指定策略,则默认使用 all 策略,允许考虑所有的候选。可能的值有:
    • “all”:所有的 ICE 候选都会被考虑。
    • “public”:只有拥有公共 IP 地址的 ICE 候选才会被考虑,已被移除。
    • “relay”:只有 IP 地址被中继的 ICE 候选,例如那些通过 STUN 或 TURN 服务器传递的,才会被考虑。
  3. bundlePolicy:指定当远程对等点与 SDP BUNDLE 标准不兼容时,应如何处理候选的协商。如果远程端点可以感知 BUNDLE,则在协商完成时,所有媒体轨道和数据通道都将捆绑到单个传输上,而不管使用何种策略,并且最初创建的任何多余传输都将在此时关闭。用技术术语来说,BUNDLE 允许两个对等点之间的所有媒体流流经单个 5 元组;也就是说,使用相同的传输协议从一个对等点的单个 IP 和端口到另一个对等点的单个 IP 和端口。如果假定为不平衡(balanced),这必须是以下字符串值之一:
    • “balanced”:ICE 代理最初为每一种内容类型(音频、视频、数据通道)创建一个 RTCDtlsTransport。如果远程端点无法感知 BUNDLE,那么每一个 DTLS 传输用于处理一种数据类型的通信。
    • “max-compat”:ICE 代理最初为每个媒体轨道创建一个 RTCDtlsTransport,对数据通道则创建一个单独的传输。如果远程端点无法感知 BUNDLE,那么对于所有的内容都会协商一个单独的 DTLS 传输。
    • “max-bundle”:ICE 代理最初仅创建一个 RTCDtlsTransport 来承载所有的 RTCPeerConnection 的数据。如果远程端点无法感知 BUNDLE,那么仅会协商一个轨道而忽略其余的轨道。
  4. rtcpMuxPolicy:收集 ICE 候选时使用的 RTCP mux 策略,以支持非复用的 RTCP。可能的值有:
    • “require”:告诉 ICE 代理仅收集 RTP 的 ICE 候选,并在它们之上多路复用 RTCP。如果远程对等点不支持 RTCP 多路复用,则会话协商失败。这是默认值。
    • “negotiate”:指示 ICE 代理收集 RTP 和 RTCP 候选。如果远程对等点支持 RTCP 复用,那么 RTCP 候选将在相应的 RTP 候选之上多路复用。否则,分别返回 RTP 和 RTCP 候选。
  5. peerIdentity:一个字符串,用于指定 RTCPeerConnection 目标对等点的标识。如果设置了该值(其默认为 null),则在成功验证远程对等点的身份为给定的名称之前,RTCPeerConnection 不会与其建立连接。
  6. certificates:一个由 RTCCertificate 对象组成的数组,用于连接的身份验证。如果未指定该属性,则会为每一个 RTCPeerConnection 实例自动创建一组证书。尽管一个给定的连接只使用一个证书,但提供多个证书可以支持多种算法,从而提高某些情况下的连接成功的机率。此配置选项在首次指定后便不能更改;一旦设置了证书,此属性将在之后调用 RTCPeerConnection.setConfiguration() 时被忽略。
  7. iceCandidatePoolSize:一个无符号 16 位整数,其指定了预获取的 ICE 候选池的大小。其默认值为 0(表示不会发生候选的预获取)。如果这个值发生变化了,那么会重新收集候选者。

RTCPeerConnection 与本地音视频数据绑定

RTCPeerConnection 提供2种方法进行数据绑定:addTrack() 和 addStream()。

其中 addStream() 已经被 WebRTC 标记为过时,因此建议使用 addTrack() 方法。

当客户端从服务端接收到 joined 消息后,它会创建 RTCPeerConnection 对象,然后调用 bindTrack() 函数将其与之前通过 getUserMedia() 采集到的音视频数据绑定:

function bindTrack() {...ls.getTracks().foreach((track) => {pc.addTrack(track, ls);...})...
}

其中,ls 是一个全局变量,当通过 getUserMedia() 采集到 MediaStream 后,需要将其交由 ls 管理;pc 是 RTCPeerConnection 的缩写,也是一个全局变量,当 RTCPeerConnection 创建好后,交由 pc 管理。

媒体协商

当 RTCPeerConnection 对象与音视频数据绑定后,紧接着需要进行媒体协商。看双方都支持那些编码方式,支持哪些分辨率等。协商的方法是通过信令服务器交换媒体能力信息,交换的内容是 SDP 格式的。

在 WebRTC 中,媒体协商是有严格的协商顺序的,如下图所示:

在这里插入图片描述

整个过程分为 8 步:

  1. Amy 调用 createOffer 方法创建 offer 消息。offer 消息中的内容是 Amy 的 SDP 信息。
  2. Amy 调用 setLocalDescription 方法,将本端的 SDP 信息保存起来。
  3. Amy 将 offer 消息通过信令服务器传给 Bob。
  4. Bob 收到 offer 消息后,调用 setRemoteDescription 方法将其存储起来。
  5. Bob 调用 createAnswer 方法创建 answer 消息, 同样,answer 消息中的内容是 Bob 的 SDP 信息。
  6. Bob 调用 setLocalDescription 方法,将本端的 SDP 信息保存起来。
  7. Bob 将 anwser 消息通过信令服务器传给 Amy。
  8. Amy 收到 anwser 消息后,调用 setRemoteDescription 方法,将其保存起来。

通过以上步骤就完成了通信双方媒体能力的交换。

ICE

当媒体协商完成后,WebRTC 就开始建立网络连接了,其过程叫 ICE(Interactive Connectivity Establishment,交互式连接建立)。更确切地说,ICE 是在各端调用 setRemoteDescription 方法后就开始了。其操作过程如下:

  1. 收集 Candidate
  2. 交换 Candidate
  3. 按优先级尝试连接

什么是 Candidate?

Candidate 是 WebRTC API 的接口之一,表示用于建立 RTCPeerConnection 的候选交互连接建立(ICE)的配置信息。它是至少包含 {address, port, protocol} 三元组的一个信息集。

RTCIceCandidate 实例属性:

  1. candidate:表示用于连接检查的候选者的传输地址的字符串。
    格式为:a=candidate:{foundation} {component} {protocol} {priority} {ip} {port} typ {type} generation {generation} ufrag {username} network_id {id} network_cost {cost}。
    以如下 candidate 为例说明其代表的含义:a=candidate:1221703924 1 udp 2122260223 192.168.0.105 51417 typ host generation 0 ufrag Q8Wv network-id 1 network-cost 10。
    typ host 表示本地候选者,使用的 IP 是 192.168.0.105,端口为 51417,使用 UDP 协议,其优先级为 2122260223,generation 表示代数,初始值为 0,用户名为 Q8Wv,如果更新 candidate 则 generation 值会递增,替换老的 candidate。
  2. sdpMid:表示候选者的媒体流标识标签的字符串,该标签在候选者关联的组件中唯一标识媒体流,如果不存在这样的关联,则为 null。
  3. sdpMLineIndex:如果值不为 null,sdpMLineIndex 表示 SDP 中候选者关联的从零开始的媒体描述索引编号。

其他更多属性见于:RTCIceCandidate

WebRTC 还将 Candidate 分为了四种类型:host、srflx、prflx、relay,它们的优先级依次递减。假如 WebRTC 收集到两个 Candidate,一个是 host 类型,另一个是 relay 类型,那么 WebRTC 会先尝试与 host 类型的 Candidate 建立连接,如果不成功,才会使用 relay 类型的 Candidate。

收集 Candidate

WebRTC 收集 Candidate 时有几种途径:

  1. host 类型的 Candidate 由主机的网卡个数决定。一般一个网卡对于一个 IP 地址,每个 IP 地址随机分配一个端口从而生成一个 host 类型的 Candidate;
  2. srflx 类型的 Candidate 由 STUN 服务器获得的 IP 地址和端口生成;
  3. relay 类型的 Candidate 由 TRUN 服务器获得的 IP 地址和端口生成。

收集到 Candidate 后,为了通知上层,WebRTC 还在 RTCPeerConnection 对象中提供了 onicecandidate 事件。为了将收集到的 Candidate 交换给对端,需要为 onicecandidate 事件设置一个回调函数:

pc.onicecandidate = (e) => {if (e.candidate) {...}
}

通过该回调函数就可以获得 WebRTC 底层收集到的所有 Candidate 了。同时,还可以在函数内实现发送给对端的操作。

交换 Candidate

WebRTC 收集 Candidate 后,会通过信令系统将它们发送给对端。对端接收后,会与本地的 Candidate 形成 CandidatePair(连接候选者对)。

有了 CandidatePair,WebRTC 就可以开始尝试建立连接了。

注意,Candidate 的交换不是等所有 Candidate 收集好了再进行的,而是边收集边交换。

尝试连接

当 WebRTC 形成 CandidatePair 后,便开始尝试进行连接。一旦发现一个可以连通的 CandidatePair 时,就不再进行其他的连接尝试了,但发现新的 Candidate 时仍然可以继续交换。

SDP 与 Candidate 消息的互换

媒体协商和 ICE 都需要通信双方做信息的交换,如交换 SDP 和 Candidate。这种信息交换使用的也是信令系统,只不过需要为这种需求专门设置一个新的信令,即 message。

信息交换的过程:

  1. 发起方向信令服务器发送 message;
  2. 服务器收到 message 后不做任何处理,直接转发给目标用户;
  3. 目标用户接收 message。

客户端发送消息:

function sendMsg(roomid, data) {...socket.emit('message', roomid, data);
}

服务器转发:

socket.on('message', (room, data) => {socket.to(room).emit('message', room, data);
});

客户端接收:

socket.on('message', (room, data) => {...if (data.hasOwnProperty('type') && data.type === 'offer') {...} else if (data.hasOwnProperty('type') && data.type === 'answer') {...} else if (data.hasOwnProperty('type') && data.type === 'candidate') {...} else {...}
});

远端音视频渲染

当各端将收集到的 Candidate 通过信令系统交换给对方后,WebRTC 内部就开始就开始尝试建立连接了。连接一旦建成,音视频数据就开始源源不断地由发送端发送给接收端。

每当有远端的音视频数据传过来时,RTCPeerConnection 对象的 ontrack() 事件就会被触发。因此只需要给 ontrack() 事件设置一个回调函数,就可以拿到远端的 MediaStream 了。再将远端音视频流赋值给本地 <video> 标签的 srcObject 属性,就可以播放音视频数据了。

具体代码如下所示:

function getRemoteStream(mediaStream) {...// 将远端音视频流赋值给本地 <video> 标签的 srcObject 属性videoElement.srcObject = mediaStream;
}
let pc = new RTCPeerConnection(...);
...
pc.ontrack = getRemoteStream;
...

参考

  1. https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection
  2. https://www.cnblogs.com/ssyfj/p/14811253.html
  3. https://webrtc.org.cn/webrtc-tutorial-2-signaling-stun-turn/

相关文章:

WebRTC 的核心:RTCPeerConnection

WebRTC 的核心&#xff1a;RTCPeerConnection WebRTC 的核心&#xff1a;RTCPeerConnection创建 RTCPeerConnection 对象RTCPeerConnection 与本地音视频数据绑定媒体协商ICE什么是 Candidate&#xff1f;收集 Candidate交换 Candidate尝试连接 SDP 与 Candidate 消息的互换远端…...

LeetCode hot100-39-N

101. 对称二叉树给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。做不出来哇&#xff0c;递归一生之敌 普通的对一棵树的递归遍历根本没办法只接比较左子树的左和右子树的右这样来比较&#xff0c;所以这题比较巧妙的是把这棵树当做两棵树一样去遍历比较。 官方…...

NumPy常用操作

目录 一:简介 二:NumPy 常用操作 三:总结 一:简介 是一个开源的Python库,它为Python提供了强大的多维数组对象和用于处理这些数组的函数。NumPy的核心是ndarray,它是一个高效的多维数组容器,用于存储和处理大规模的数据。NumPy还提供了许多数学函数,用于数组之间的操…...

学习笔记——字符串(单模+多模+练习题)

单模匹配 Brute Force算法&#xff08;暴力&#xff09; 算法思想 母串和模式串字符依次配对&#xff0c;如果配对成功则继续比较后面位置是否相同&#xff0c;如果出现匹配不成功的位置&#xff0c;则j&#xff08;模式串当前的位置&#xff09;从头开始&#xff0c;i&…...

DOT + graphviz 轻松画图

GraphViz&#xff1a;2 DOT语法和相关应用_graphviz dot-CSDN博客 图可视化之Graphviz - 知乎 Graphviz 是由AT&T Research、Lucent Bell实验室开源的可视化图形工具&#xff0c;可以很方便的用来绘制结构化的图形网络。具体地&#xff0c;其使用一种名为dot语言的DSL来编…...

使用Vue调用ColaAI Plus大模型,实现聊天(简陋版)

首先去百度文心注册申请自己的api 官网地址&#xff1a;LuckyCola 注册点开个人中心 查看这个文档自己申请一个ColaAI Plus定制增强大模型API | LuckyColahttps://luckycola.com.cn/public/docs/shares/api/colaAi.html来到vue的页面 写个样式 <template><Header …...

Unity使用sherpa-onnx实现离线语音合成

sherpa-onnx https://github.com/k2-fsa/sherpa-onnx 相关dll和lib库拷进Unity&#xff0c;官方示例代码稍作修改 using SherpaOnnx; using System; using System.IO; using System.Runtime.InteropServices; using UnityEngine;public class TTS : MonoBehaviour {public st…...

Elasticsearch入门基础和集群部署

Elasticsearch入门基础和集群部署 简介基础概念索引&#xff08;Index&#xff09;类型&#xff08;Type&#xff09;&#xff08;逐步弃用&#xff09;文档&#xff08;Document&#xff09;字段&#xff08;Field&#xff09;映射&#xff08;Mapping&#xff09;分片&#x…...

12、24年--信息系统治理——IT治理

主要考选择题,2分左右,案例、论文涉及概率不大,需要认证读课本原文。 1、IT治理基础 IT治理是描述组织采用有效的机制对信息技术和数据资源开发利用,平衡信息化发展和数字化转型过程中的风险,确保实现组织的战略目标的过程。 1.1 IT治理的驱动因素 1)存在很多问题: 信…...

Electron学习笔记(三)

文章目录 相关笔记笔记说明 五、界面1、获取 webContents 实例&#xff08;1&#xff09;通过窗口对象的 webContent 属性获取 webContent 实例&#xff1a;&#xff08;2&#xff09;获取当前激活窗口的 webContents 实例&#xff1a;&#xff08;3&#xff09;在渲染进程中获…...

【Redis】Redis键值存储

大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#xff0c;但是也想日更的人。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4aa;&#x1f4aa;&#x1f4aa…...

C++系统编程篇——Linux初识(系统安装、权限管理,权限设置)

(1)linux系统的安装 双系统---不推荐虚拟机centos镜像&#xff08;可以使用&#xff09;云服务器/轻量级云服务器&#xff08;强烈推荐&#xff09; ①云服务器&#xff08;用xshell连接&#xff09; ssh root公网IP 然后输入password ①添加用户&#xff1a; addus…...

No Cortex-M SW Device Found

将DIO和CLK管脚调换一下...

提升写作效率的秘密武器:一个资深编辑的AI写作体验

有句话说:“写作是一项你坐在打字机前流血的工作。”而如今,各类生成式软件的涌现似乎打破了写作这一古老的艺术形式壁垒。过去,作家们独自在书桌前冥思苦想,如今,一款名为“玲珑AI工具”的ai写作助手正悄然改变着文案写作行业的创作生态,成为提升写作效率的秘密武器。 在传统…...

Python sort() 和 sorted() 的区别应用实例详解

大家好&#xff0c;今天针对 Python 中 sort() 和 sorted() 之间的区别&#xff0c;来一个实例详细解读。sort — 顾名思义就是排序的意思&#xff0c;它可以接收的对象为可迭代的数据类型。今天以列表为例子演示两者的不同点、相同点&#xff0c;以及其中一些常用的高级参数使…...

七、Redis三种高级数据结构-HyperLogLog

Redis HyperLogLog是用来做基数统计的算法&#xff0c;HyperLogLog在优点是&#xff0c;在输入的元素的数量或者体积非常大时&#xff0c;计算基数占用的空间总是固定的、并且非常小。在Redis里每个HyperLogLog键只需花费12KB内存&#xff0c;就可以计算接近 264 个元素的基数。…...

2024年【金属非金属矿山(露天矿山)安全管理人员】模拟考试题库及金属非金属矿山(露天矿山)安全管理人员作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 金属非金属矿山&#xff08;露天矿山&#xff09;安全管理人员模拟考试题库参考答案及金属非金属矿山&#xff08;露天矿山&#xff09;安全管理人员考试试题解析是安全生产模拟考试一点通题库老师及金属非金属矿山&a…...

网站DDoS攻击应对策略:全面防护与恢复指南

随着互联网的发展&#xff0c;网络安全问题日益凸显&#xff0c;其中DDoS&#xff08;分布式拒绝服务&#xff09;攻击成为了网站安全的主要威胁之一。当网站遭受DDoS攻击时&#xff0c;可能会面临服务中断、性能下降、数据泄露等严重后果。因此&#xff0c;了解并掌握DDoS攻击…...

线性/非线性最小二乘 与 牛顿/高斯牛顿/LM 原理及算法

最小二乘分为线性最小二乘和非线性最小二乘 最小二乘目标函数都是min ||f(x)||2 若f(x) ax b&#xff0c;就是线性最小二乘&#xff1b;若f(x) ax2 b / ax2 bx 之类的&#xff0c;就是非线性最小二乘&#xff1b; 1. 求解线性最小二乘 【参考】 2. 求解非线性最小二乘…...

mysqldump: Error 2013 导致mysql停止运行

https://www.cnblogs.com/DataArt/p/10173957.html 1 查询表大小 SELECT table_name AS "表名", round(((data_length index_length) / 1024 / 1024), 2) AS "大小(MB)" FROM information_schema.tables WHERE table_schema your_database_name AND …...

2023年数维杯国际大学生数学建模挑战赛D题洗衣房清洁计算解题全过程论文及程序

2023年数维杯国际大学生数学建模挑战赛 D题 洗衣房清洁计算 原题再现&#xff1a; 洗衣房清洁是人们每天都要做的事情。洗衣粉的去污作用来源于一些表面活性剂。它们可以增加水的渗透性&#xff0c;并利用分子间静电排斥机制去除污垢颗粒。由于表面活性剂分子的存在&#xff…...

python 两种colorbar 最大最小和分类的绘制

1 colorbar 按照自定义的最值绘制 归一化方法使用Normalize(vmin0, vmax40.0) import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.cm as cm import matplotlib.colors as mcolors from matplotlib import rcParams from matplot…...

Linux-基础IO

&#x1f30e;Linux基础IO 文章目录&#xff1a; Linux基础IO C语言中IO交互       常用C接口         fopen         fputs         fwrite         fgets 当前路径       三个文件流 系统文件IO       open函数     …...

202006青少年软件编程(Python)等级考试试卷(二级)

第 1 题 【单选题】 以下程序的运行结果是&#xff1f;&#xff08; &#xff09; l ["兰溪","金华","武义","永康","磐安","东阳","义乌","浦江"]for s in l:if"义"in s:print(…...

【LeetCode】每日一题:2244.完成所有任务需要的最少轮数

给你一个下标从 0 开始的整数数组 tasks &#xff0c;其中 tasks[i] 表示任务的难度级别。在每一轮中&#xff0c;你可以完成 2 个或者 3 个 相同难度级别 的任务。 返回完成所有任务需要的 最少 轮数&#xff0c;如果无法完成所有任务&#xff0c;返回 -1 。 英文原题&#xf…...

百度文心一言 java 支持流式输出,Springboot+ sse的demo

参考&#xff1a;GitHub - mmciel/wenxin-api-java: 百度文心一言Java库&#xff0c;支持问答和对话&#xff0c;支持流式输出和同步输出。提供SpringBoot调用样例。提供拓展能力。 1、依赖 <dependency> <groupId>com.baidu.aip</groupId> <artifactId…...

59.基于SSM实现的网上花店系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;网上花店是在MySQL中建立数据表保存信息&#xff0c;运用SSMVue框架和Java语言编写。并按照软件设计开发流程进行设计实现充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SSM的网…...

什么是字节码?

字节码&#xff08;Bytecode&#xff09;是Java虚拟机&#xff08;JVM&#xff09;能够理解和执行的中间代码。Java源代码首先编译成字节码文件&#xff08;扩展名为 .class&#xff09;&#xff0c;而不是直接编译成特定机器的机器码。字节码具有以下特点&#xff1a; 平台无…...

C++ JWT的使用

接入sdk需要使用JWT加密参数&#xff0c;做个记录以备后查 #include <iostream> #include <jwt-cpp/jwt.h> int main() { // 设置JWT的密钥&#xff08;对于HS256&#xff09; std::string secret_key "your-256-bit-secret"; // 创建一个新的JW…...

SpringBoot内置插件的使用(jackson和lombok)

文章目录 引言I lombok(自动为属性生成构造器)II jacksonsee also引言 idea正式版2021.2.2 已经捆绑安装jackson和lombok插件 I lombok(自动为属性生成构造器) Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。 htt…...