乐趣区

关于webrtc:WebRTC-简单入门与实践

一、前言

WebRTC 技术曾经宽泛在各个行业及场景中被利用,但对少数开发者来说,实时音视频及相干技术却是比拟不常接触到的。

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

本篇文章以 0 教训音视频开发者 视角,类比罕用的 Web 技术,冀望帮忙您简略入门 WebRTC 技术,急躁看完本篇文章,你将:

  • 理解什么是 WebRTC
  • 把握 WebRTC 通话原理
  • 利用 Chrome debug WebRTC 利用

适宜浏览对象:Web 开发,有 js 根底,对 WebRTC 感兴趣的同学

二、应用示例

没有接触过 WebRTC 技术的同学,能够先体验下 ZEGO 的 GoEnjoy 产品,外面蕴含了 WebRTC 在浏览器中的规范应用计划,包含不限于:设施检测、兼容性检测、弱网断网应答策略等,利用是收费的,可戳 —> 示例 Demo 传送门

在进入注释之前,让咱们先对它有个根本的印象吧!

三、简略介绍

体验完 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 中的配置项。

联合下图类比会更容易了解:

四、前置思考问题

在解说代码前,还须要思考以下几个问题,否则会不分明为什么代码中须要替换 SDP,cadidate 等(您也能够先看完代码后,再回来看这个段落,加深了解)。

单方应用浏览器通信,浏览器能力,网络状况等不统一会对通信有很大影响,一起思考下上面 2 个问题:

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

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

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

显示状况如下图:

艰深一点比喻:阿宅往年 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 的处理过程

绿色局部:对应的是网络链接状况

4、持续下来,能够看到推流中实时数据变动:

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

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

更多字段了解,可戳这里进行深刻学习:https://www.w3.org/TR/webrtc-…

七、结尾

随着硬件网络的更新换代,咱们经验了由文字 -> 图片 -> 视频 载体变更的过程。随着 5G 的遍及,音视频技术融于有形正在成为事实,WebRTC 作为其中最重要框架之一,浏览器的反对成熟度也在疾速欠缺当中,继续学习 WebRTC 技术,关注 ZEGO 即构科技!

附下作者罕用的工具,举荐珍藏:
1 https://webrtc.github.io/samp… google 官网 demo,蕴含最新性能
2 https://developer.mozilla.org… 具体接口介绍
3 https://w3c.github.io/webrtc-…(W3C 规范介绍)

退出移动版