首页 > 其他分享 >WebRTC 简单入门与实践

WebRTC 简单入门与实践

时间:2023-10-18 17:25:49浏览次数:47  
标签:await 浏览器 入门 pc2 pc1 实践 const WebRTC

 

一、前言

WebRTC 技术已经广泛在各个行业及场景中被应用,但对多数开发者来说,实时音视频及相关技术却是比较不常接触到的。

做为一名 Web 开发者,WebRTC 这块的概念着实花了不少时间才搞明白,一是 WebRTC 本身有较多的独有概念,二是虽然带“Web”字样,但依赖底层概念和网络却是 Web 开发很少接触到的;

本篇文章以 0 经验音视频开发者 视角,类比常用的 Web 技术,期望帮助您简单入门 WebRTC 技术,耐心看完本篇文章,你将:

  1. 了解什么是 WebRTC
  2. 掌握 WebRTC 通话原理
  3. 利用 Chrome debug WebRTC 应用

适合阅读对象:Web开发,有 js 基础,对 WebRTC 感兴趣的同学

二、使用示例

没有接触过 WebRTC 技术的同学,可以先体验下 ZEGO 的 GoEnjoy 产品,里面包含了 WebRTC 在浏览器中的标准使用方案,包括不限于:设备检测、兼容性检测、弱网断网应对策略等,应用是免费的,可戳--->示例 Demo 传送

在进入正文之前,让我们先对它有个基本的印象吧!

图 1

三、简单介绍

体验完 Demo 后,有必要再了解一下技术的发展历史、应用场景等,这些能让我们知道它为什么优秀,哪方面优秀,有哪些缺点等。

程序员经常用到 5W1H 分析法,那么本文就按照这个思路给大家做一下介绍:

What

WebRTC(Web Real-Time Communication),一个可以让用户用自己流量 实现音视频实时通信的框架(APIs),支持浏览器(Firefox、Chrome、safari)以及 iOS、Android 原生系统。

When

2017 年 12 月成为 W3C 草案,国内微信浏览器 19 年下半年才支持,国内手机自带浏览器目前还有不少兼容问题,2021 年 1 月 26 日,成为 W3C 正式标准。

Who

2011年 Google 收购多个子项目(GIPS,On2,VPx),成立了现在的 WebRTC 项目,目前是 Google 的一个开源项目。

Where

可应用在社交/娱乐/教育/工具 等需要实时音视频高效沟通的场景,例如:最近很火的元宇宙。

Why

W3C 标准,开源,插件化,整体效果佳。

How

也是本文重中之中,最终的目的也是让大家能知道如何使用。

在正式代码讲解之前,有一些概念需要先普及一下您也可以先看完代码后,再回来看这个段落,加深理解。):

  • MediaStream:流媒体对象,音/视频数据的一种封装格式,挂载到 video 或 audio 标签上播放;
  • RTCPeerConnection:会话控制,网络和媒体信息收发,作用类似 http 对象;
  • SDP :主要用于两个会话实体之间的媒体协商,作用类似 http 中的配置项。

结合下图类比会更容易理解:

图2

四、前置思考问题

在讲解代码前,还需要思考以下几个问题,否则会不清楚为什么代码中需要交换 SDP,cadidate等(您也可以先看完代码后,再回来看这个段落,加深理解)。

双方使用浏览器通信,浏览器能力,网络情况等不一致会对通信有很大影响,一起思考下下面 2 个问题:

1、视频编码能力不一样?

peer-A 和 peer-B 是视频互动的两边浏览器,他们通讯前必须在视频编码能力上先达成一致,如下图,最终协商出共同的H264,如果无法达成一致,则通讯失败。

图3

2 电脑之间,大多数是在某个局域网中,需要 NAT(Network Address Translation,网络地址转换),因此并不能直接通信 ;

显示情况如下图:

图4

通俗一点比喻: 阿宅今年 30 了(不是我,不要乱猜)被父母逼婚,他只能求助媒婆,才可能被另一个阿宅认识。

媒婆解决阿宅社恐问题,NAT 也需要一种方式绕过,双方才能建立通信,我们需要用到 STUN 和 TURN。

五、代码讲解

终于到我们的代码讲解部分了,下面的代码会按照推流段顺序,分阶段讲解每个步骤所需要用到的API(如果你是直接看代码,建议看完后再回去看第三、四 Part 的介绍,理解会更加深刻)。

步骤一:创建数据源

localStream 作为发送端本地预览画面:

// 创建数据源
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
// 显示数据源,localVideo 是 html 中的 video 标签
localVideo.srcObject = localStream;

 

步骤二:创建发送数据实例

用于发送步骤一中创建的数据:

// 本地实例
const pc1 = new RTCPeerConnection();
// 对端实例
const pc2 = new RTCPeerConnection();

 

步骤三:配置实例

做这一步的目的是为了交换两端的信息:icecandidate 和 SDP

  • icecandidate:包含通信协议(TCP/UDP)和通信IP,STUN和TURN协议中描述网络信息的格式规范,解决双方网络链接问题;
  • SDP:浏览器能力,包括不限于音视频编码格式,带宽,流控策略等;解决前置思考中,双方能力不匹配问题,通过交换双方 SDP 浏览器会自动选择双方都支持的视频编码格式。
// 告诉对端,本端地址
pc1.addEventListener('icecandidate', async (e) => {
// 发送给对端
// 对端添加本端地址
if (e.candidate) {
await pc2.addIceCandidate(e.candidate);
}
});


pc2.addEventListener('icecandidate', async (e) => {
// 发送给本端
// 本端添加对端地址
if (e.candidate) {
await pc1.addIceCandidate(e.candidate);
}
});


// 创建本端SDP,告诉本端浏览器支持哪些能力
const offer = await pc1.createOffer();
pc1.setLocalDescription(offer);
// 创建远端SDP,告诉远端浏览器支持哪些能力
const answer = await pc2.createAnswer();
pc2.setLocalDescription(answer);
// 。。。。发送远端SDP给本端
// 接收远端sdp,告诉远端浏览器支持哪些能力
pc1.setRemoteDescription(answer);
// 接收客户端sdp,告诉远端浏览器支持哪些能力
pc2.setRemoteDescription(offer);

 

步骤四:发送数据

localStream.getTracks().forEach(
(track) => pc1.addTrack(track, localStream)
);

 

步骤五:完整精简版Typescript代码

注意,这里使用的 typescript 编写,实际运行需要先转成 js。

const pc1 = new RTCPeerConnection();
pc1.addEventListener('icecandidate', async (e) => {
if (e.candidate) {
await pc2.addIceCandidate(e.candidate);
}
});
pc1.addEventListener('iceconnectionstatechange', (e) => {
console.log('pc1: iceconnectionstatechange', e);
});


const pc2 = new RTCPeerConnection();
pc2.addEventListener('icecandidate', async (e) => {
if (e.candidate) {
await pc1.addIceCandidate(e.candidate);
}
});


pc2.addEventListener('iceconnectionstatechange', (e) => {
console.log('pc2: iceconnectionstatechange', e);
});


pc2.addEventListener('track', (e) => {
if (e.streams.length > 0) {
remoteVideo.srcObject = e.streams[0];
}
});


const remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement;
const localVideo = document.querySelector('#localVideo') as HTMLVideoElement;

async function pushStream(answer: RTCSessionDescriptionInit) {
pc1.setRemoteDescription(answer);
}

async function pullStream(offer: RTCSessionDescriptionInit): Promise<void> {
pc2.setRemoteDescription(offer);
const answer = await pc2.createAnswer();
pc2.setLocalDescription(answer);
console.warn('answer', answer);
pushStream(answer);
}


window.onload = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});


localVideo.srcObject = localStream;
localStream.getTracks().forEach((track) => pc1.addTrack(track, localStream));


const offer = await pc1.createOffer();
pc1.setLocalDescription(offer);
console.warn('pc1 offer', offer);
pullStream(offer);
};

 

六、应用举例

学习完理论知识,接下来我们一起再实践下,加深对知识的理解 —— 通过 Chrome浏览器 debug WebRTC应用。学会 debug 既可以加深理解,也是后续写代码必不可少的技能,千万不少跳过这一步哦:

1、点击打开示例DEMO

2、另打开一个tab页面,输入: chrome://webrtc-internals/

3、DEMO 中输入相关信息开始直播, 切回到 2 中的 tab 页面,如下图:

蓝色部分:对应的是代码中SDP的处理过程

绿色部分:对应的是网络链接情况

图5

4、继续下来,可以看到推流中实时数据变化:

蓝色部分:拉流实时数据,包括分辨率,码率,丢包率等

绿色部分:推流实时数据,包括分辨率,码率,丢包率等

图6

七、结尾

随着硬件网络的更新换代,我们经历了由文字->图片->视频 载体变更的过程。随着 5G 的普及,音视频技术融于无形正在成为现实,WebRTC 作为其中最重要框架之一,浏览器的支持成熟度也在快速完善当中,持续学习 WebRTC 技术,关注 ZEGO 即构科技!

附下作者常用的工具,推荐收藏:

1 ​​WebRTC samples​​. google 官网 demo,包含最新功能

2 ​​MediaDevices - Web APIs | MDN​

3 ​​WebRTC 1.0: Real-Time Communication Between Browsers​​( W3C标准介绍)

 

标签:await,浏览器,入门,pc2,pc1,实践,const,WebRTC
From: https://www.cnblogs.com/zegoinfo/p/17772883.html

相关文章

  • 黄金眼PAAS化数据服务DIFF测试工具的建设实践
    一、背景介绍黄金眼PAAS化数据服务是一系列实现相同指标服务协议的数据服务,各个服务间按照所生产指标的主题作划分,比如交易实时服务提供实时交易指标的查询,财务离线服务提供离线财务指标的查询。黄金眼PAAS化数据服务支撑了黄金眼APP、黄金眼PC和内部各类大屏的数据查询需求。为......
  • 快速入门运维:成为一名高效运维工程师的关键步骤
    引言:运维(OperationsandMaintenance)是现代技术领域中至关重要的角色之一。而作为一名运维工程师,需要负责维护和管理软件系统、网络基础设施和服务器等关键组件。本篇博客将介绍如何快速入门运维,成为一名高效的运维工程师。学习基本概念和原理:在开始之前,了解运维的基本概念和原理......
  • 信创办公--基于WPS的Word最佳实践系列(图片批量居中对齐)
    项目背景当我们进行Word排版的时候,一次性插入过多图片后,每张进行居中设置需要的重复动作较多,花费的时间也较长,因此我们可以用到WPS软件自带的工具——“查找替换”。操作步骤1、操作步骤单击【开始】选项卡,找到【查找与替换】选项,如图1-1所示。图1-1打开查找替换2、操作步骤单击【......
  • 读书实践感悟-《暗时间》
    过早退出是失败的根源,从进入专注状态到完全专注,也就是心流状态,会遇到很多问题。首先是进入状态的这个决定时间段,当你意识到你在无所事事你该开始干一件事情的时候,会有很多干扰的小事积压,或者说,我们的大脑下意识来用这些来逃避痛苦的学习过程。及时享乐是大脑的天性,但当意识到的时......
  • 神经网络入门篇:为什么深度学习会兴起?
    为什么深度学习会兴起?这篇我们来讲故事,关于为什么深度学习会兴起的故事~深度学习和神经网络之前的基础技术理念已经存在大概几十年了,为什么它们现在才突然流行起来呢?因为多亏数字化社会的来临,现在的数据量都非常巨大,我们花了很多时间活动在这些数字的领域,比如在电脑网站上、......
  • 【Python入门教程】CV2报错:cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-p
    ​     OpenCV作为一个强大计算机视觉库被各个领域广泛应用,今天分享下自己编程遇到的报错信息以及解决办法。1报错信息​[WARN:[email protected]]globalgrfmt_tiff.cpp:716cv::TiffDecoder::readDataOpenCVTIFF:TIFFRGBAImageOK:Sorry,cannothandleimageswith6......
  • Istio 入门(六):版本控制
    目录VirtualService和DestinationRuleVirtualService与Service的关系VirtualService和DestinationRule的关系VirtualService的定义DestinationRule的定义完整系统教程电子书阅读地址:https://istio.whuanle.cn/VirtualService和DestinationRuleVirtualService与......
  • HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
    HTML中列表的作用HTML中的列表(List)用于呈现按照一定逻辑关系组织的信息,以便用户更好地理解和识别。列表可以分为有序列表、无序列表和定义列表三种类型。有序列表(OrderedList):用于表示按照一定顺序排列的项目,每个项目都有对应的标记。常见的例子包括步骤、流程等。无序列表(Unordere......
  • HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
    HTML中列表的作用HTML中的列表(List)用于呈现按照一定逻辑关系组织的信息,以便用户更好地理解和识别。列表可以分为有序列表、无序列表和定义列表三种类型。有序列表(OrderedList):用于表示按照一定顺序排列的项目,每个项目都有对应的标记。常见的例子包括步骤、流程等。无序列表(Unordere......
  • 前端打怪之旅=>Es6入门(运算符、Symbol)
    运算符...扩展运算符能将数组转换为逗号分隔的参数序列声明一个数组consttfboys=['易烊千玺','王源','王俊凯'];//声明一个函数functionaction(){console.log(arguments)}action(tfboys) 是一个数组元素,arguments里......