基于WebRTC实现音视频通话

客户端采用 WebRTC 技术(推流),通讯用 websocket。

WebRTC 像是一个面试过程:

第一步:发起方(拨打电话者)点击拨打电话时,获取本地媒体流并推流给接收方同时捕获接收方推过来的流,捕获到后把流设置到 dom 上,监听 ICE 候选确保能点对连接,生成 offer,通过 websocket 告知接收方并拉起等待接听界面。

复制代码
//获取媒体流
stream.value = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
});

// 初始化 PeerConnection
peerConnection.value = new RTCPeerConnection({
    iceServers: [
        {
            urls: 'stun:stun.l.google.com:19302'
        }
    ]
});

// 推流给接收方
stream.value.getTracks().forEach((track) => {
    peerConnection.value.addTrack(track, stream.value);
});

// 捕获接收方的流
peerConnection.value.ontrack = (event) => {
    remoteStream.value = event.streams[0];
    if (callType.value === TypeVideo) {
        remoteVideo.value.srcObject = remoteStream.value;
    } else {
        remoteAudio.value.srcObject = remoteStream.value;
    }
};

// 监听ICE候选,确保 WebRTC 的点对点连接能够成功建立
peerConnection.value.onicecandidate = (event) => {
    if (event.candidate) {
        //发送candidate
        ws.send(event.candidate);
    }
};
// 创建 offer
const offer = await peerConnection.value.createOffer();
await peerConnection.value.setLocalDescription(offer);

//发送offer,这里发送的offer可以理解成是接收方用来捕获发起方流的一个凭证,接收方通过peerConnection.value.ontrack可以捕获到。
ws.send(offer);
//拉起等待接听界面
showCall.value = true;
//状态等待接听
callStatus.value = 'wating';

第二步:接收方收到 offer 后,第一步是拉起来电界面,第二步是选择接听或者挂断。

1)拉起来电接听界面

复制代码
//拉起来电接听界面
showCall.vue = true;
//状态来电接听
callStatus.value = 'coming';
//初始化来电人信息等
....

2)挂断,就是告诉发起方我挂断了,发起方就把 RTC 关掉、停止推流,dom 置空就好了

复制代码
//接收方
showCall.value = false;
callStatus.value = 'closing';
ws.send('reject');

//发起方
if (peerConnection.value) {
    peerConnection.value.close();
    peerConnection.value = null;
}
if (stream.value) {
    const tracks = stream.value.getTracks();
    tracks.forEach((track) => track.stop());
}
if (localVideo.value)
    localVideo.value.srcObject = null;
if (remoteVideo.value)
    remoteVideo.value.srcObject = null;
if (remoteAudio.value)
    remoteAudio.value.srcObject = null;
showCall.value = false;
callStatus.value = 'closing';

3)接听,操作跟拨打流程差不多,需要设置远端 SDP(发起方的 offer),添加 ICE 候选(发起方的 ice,这里需要注意的是只有远端 SDP 初始化完毕状态下才能设置 ice)

复制代码
// 获取本地媒体流
...同发起方
// 初始化 PeerConnection
...同发起方
// 推流给发起方
...同发起方
// 捕获发起方的流
...同发起方
// 监听ICE候选
...同发起方

//设置远端SDP
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(caller.value.offer));

// 添加发起方发过来的ice
iceCandidateQueue.value.forEach(async (candidate) => {
await  peerConnection.value.addIceCandidate(candidate);
});
iceCandidateQueue.value  = [];

// 创建 answer
const  answer  =  await  peerConnection.value.createAnswer();
await  peerConnection.value.setLocalDescription(answer);

//发送answer给发起方
ws.send(answer);
//状态通话中
callStatus.value = 'calling';

关于 ice 的处理,就是远端 SDP 初始化完毕状态可以直接设置,未初始化完毕就存到 iceCandidateQueue 队列备用

复制代码
// 处理新的 ICE 候选
const handleNewICECandidate = async (candidate) => {
    const iceCandidate = new RTCIceCandidate(candidate);
    if (peerConnection.value?.signalingState === 'have-remote-offer' || peerConnection.value?.signalingState === 'stable') {
        peerConnection.value.addIceCandidate(iceCandidate);
    } else {
        iceCandidateQueue.value.push(iceCandidate);
    }
};

最后一步:发起方收到接收方的答复(接收方接听了),设置远端 SDP(接收方的 answer), 设置 ICE(接受方的 ice)

复制代码
//设置远端SDP
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(caller.value.answer));

//添加ICE
iceCandidateQueue.value.forEach(async (candidate) => {
    await peerConnection.value.addIceCandidate(candidate);
});
iceCandidateQueue.value = [];
//状态接听中
callStatus.value = 'calling';

这就是 WebRTC 视频通话的关键代码跟流程!

例图:

相关推荐
xcLeigh2 小时前
HTML5实现好看的视频播放器(三种风格,附源码)
前端·音视频·html5
骄傲的心别枯萎5 小时前
RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库
数据库·opencv·计算机视觉·sqlite·音视频·rv1126
好游科技6 小时前
IM即时通讯系统:安全可控、功能全面的社交解决方案全解析
安全·音视频·webrtc·im即时通讯·私有化部署im即时通讯·社交app
EasyDSS6 小时前
视频直播点播平台EasyDSS构建高并发、低延迟的远程教学直播新模式
音视频
GIOTTO情6 小时前
多模态舆情监测技术深度解析:Infoseek 如何实现 AI 造假与短视频舆情的精准捕捉?
人工智能·音视频
音视频牛哥7 小时前
C# 开发工业级 RTSP/RTMP 播放器实战:基于 SmartMediakit 的低延迟与高可靠性设计
音视频·rtsp播放器·rtmp播放器·windows rtsp播放器·windows rtmp播放器·c# rtsp播放器·c# rtmp播放器
JellyDDD7 小时前
【悬赏】Android WebRTC 数字人项目回声问题排查(AEC / AudioMode)
音视频·webrtc
于是我说7 小时前
如何判断一个视频到底是真实 MP4 直链,还是流媒体M3U8
网络·音视频
gf13211118 小时前
剪映草稿位置坐标换算
音视频
ACP广源盛139246256738 小时前
GSV1011@ACP#1011产品规格详解及产品应用分享
嵌入式硬件·计算机外设·音视频