💥我在 Chatterbox(话匣子)中 WebRTC 的使用-下篇(实际应用-实现实时语音视频通话)

382 阅读3分钟

背景

🎈在上篇文章中我介绍了一下WebRTC的基本概念。这篇我们来简单聊一聊WebRTC的基本用法、两个客户端之间的通讯,以及我在Chatterbox(话匣子)中的应用方式。

⚠️若基本概念不清晰的可以看我上篇文章介绍

先看一个简单的例子

image.png

// 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中写一个客户端组件实现连接的基本的通讯功能。

1719812145452.jpg

image.png

如上实现了客户端组件,并支持呼叫、接受呼叫实现了两个客户端的基本通讯的功能。接下来我们需要实现获取本地设备的摄像头、麦克风,并获取到其中捕捉到的数据流。那就要用到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)
      });
    }
  }
}

既然获取到了数据流那我们还需要在媒体播放器中进行播放,就要用到RTCPeerConnectionontrack事件。用于处理由 RTCPeerConnection 产生的 track 事件。当远程对等端(peer)添加、移除或替换媒体流中的轨道(track)时,会触发此事件。我们只要在这个事件中将数据流放到播放器中播放即可。

// 远程对等端添加一个新的或更改现有轨道 监听处理器。 将获取到的数据在播放器中播放
const ontrack = (event) => {
  refVideo.value.srcObject = event.streams[0];
  refVideo.value.play()
}

演示

a3ef9c8121134a21b5745b3926bd4cc.png

以上就是本次分享的内容,完整的代码内容就不再此粘贴,附上客户端组件源码

🦀🦀感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!