背景
🎈在上篇文章中我介绍了一下WebRTC的基本概念。这篇我们来简单聊一聊WebRTC的基本用法、两个客户端之间的通讯,以及我在Chatterbox(话匣子)中的应用方式。
⚠️若基本概念不清晰的可以看我上篇文章介绍
先看一个简单的例子
// A
const connection = new RTCPeerConnection();
connection.onicecandidate = ({ candidate }) => {
if (!candidate) {
console.log(connection.localDescription)
}
}
const channel = connection.createDataChannel('channel');
channel.onopen = () => console.log('open');
channel.onclose = () => console.log('close');
channel.onmessage = (e) => console.log('message', e);
const offer = await connection.createOffer()
connection.setLocalDescription(offer);
// 执行完B在执行以下代码
let description = null // todo B 打印出来的 localDescription
connection.setRemoteDescription(description)
// B
const connection = new RTCPeerConnection();
connection.onicecandidate = ({ candidate }) => {
if (!candidate) {
console.log(connection.localDescription)
}
}
let channel = null
connection.ondatachannel = (e) => {
channel = e.channel
channel.onopen = () => console.log('open');
channel.onclose = () => console.log('close');
channel.onmessage = (e) => console.log('message', e);
}
let description = null // todo A 打印出来的 localDescription
connection.setRemoteDescription(description)
const answer = await connection.createAnswer()
connection.setLocalDescription(answer);
- 创建
RTCPeerConnection对象:1. 使用new RTCPeerConnection(configuration)创建一个RTCPeerConnection对象。其中,configuration是一个JSON对象,包含服务器配置信息,如STUN/TURN服务器地址等 (在本地是不需要填写服务器地址的,如果放到外网则需要填写)。 - 设置ICE候选者:ICE(Interactive Connectivity Establishment)是WebRTC中用于确定两个浏览器之间最佳连接路径的协议。当RTCPeerConnection对象收集到新的ICE候选者时,会触发
onicecandidate事件。你可以通过监听这个事件,并将候选者信息发送给远程的RTCPeerConnection对象,以建立连接。 - 创建并交换
SDP:SDP(Session Description Protocol)是WebRTC中用于描述媒体会话的协议。你需要使用pc.createOffer()或pc.createAnswer()方法创建SDP,并使用pc.setLocalDescription()和pc.setRemoteDescription()方法设置和交换SDP。创建offer的一方是呼叫的发起者,创建answer的一方是应答者。
在Chatterbox(话匣子)中SDP是通过 Websocket 进行传递交换的。
vue中实现语音/视频通讯
基本的通讯咱们已经介绍过,并通过简单地例子实现了。那接下来增加难度,写一个 Demo 实现语音/与视频的通讯功能。
客户端组件
先在VUE中写一个客户端组件实现连接的基本的通讯功能。
如上实现了客户端组件,并支持呼叫、接受呼叫实现了两个客户端的基本通讯的功能。接下来我们需要实现获取本地设备的摄像头、麦克风,并获取到其中捕捉到的数据流。那就要用到getUserMedia这个API了。它会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其他轨道类型。
const promise = navigator.mediaDevices.getUserMedia(constraints);
getUserMediaAPI具体用法请参考:developer.mozilla.org/zh-CN/docs/…
接下来基于上方客户端组件的基础上我们获取用户的本地设备。
// 获取媒体流 并添加加到连接
const getUserMediaStream = async () => {
if (navigator.mediaDevices.getUserMedia) {
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
if (mediaStream) {
mediaStream.getTracks().forEach(track => {
connection.value.addTrack(track, mediaStream)
});
}
}
}
既然获取到了数据流那我们还需要在媒体播放器中进行播放,就要用到RTCPeerConnection的ontrack事件。用于处理由 RTCPeerConnection 产生的 track 事件。当远程对等端(peer)添加、移除或替换媒体流中的轨道(track)时,会触发此事件。我们只要在这个事件中将数据流放到播放器中播放即可。
// 远程对等端添加一个新的或更改现有轨道 监听处理器。 将获取到的数据在播放器中播放
const ontrack = (event) => {
refVideo.value.srcObject = event.streams[0];
refVideo.value.play()
}
演示
以上就是本次分享的内容,完整的代码内容就不再此粘贴,附上客户端组件源码
🦀🦀感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!
- 基于 Vue3 + Element-plus 管理后台基础功能框架
- 预览:admin.gumingchen.icu
- Github:github.com/gmingchen/a…
- Gitee:gitee.com/shychen/agi…
- 基础版后端:github.com/gmingchen/j…
- 文档:admin.gumingchen.icu/doc/
- 基于 Vue3 + Element-plus + websocket 即时聊天系统
- 预览:chatterbox.gumingchen.icu/
- Github:github.com/gmingchen/c…
- Gitee:gitee.com/shychen/cha…
- 基于 node 开发的后端服务:github.com/gmingchen/n…