前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【开发日记】使用WebRTC实现类微信的实时音视频通话

【开发日记】使用WebRTC实现类微信的实时音视频通话

作者头像
全栈开发日记
发布2024-11-23 09:55:12
发布2024-11-23 09:55:12
31400
代码可运行
举报
文章被收录于专栏:全栈开发日记全栈开发日记
运行总次数:0
代码可运行

1、背景

需要使用uni-app技术开发一个类似微信一样的实时音视频通话功能,经过大量的调研和尝试,最终有存在两个方案:第一个方案是使用WebRTC技术实现P2P点对点实时通信;第二个方案是使用现成的阿里、腾讯、声网等平台相关产品。

第二种方案无疑是最稳定的,但价格太劝退了,所以退而求其次使用WebRTC技术实现,下面是在uni-app技术中实现WebRTC的记录。

完整代码请在公众号【全栈开发日记】后台回复“WebRTC”获取。

2、web-view与uniapp通信

webview中html必须引入uni.webview.js文件。uniapp有提供的官方下载地址,去官网找一下。

代码语言:javascript
代码运行次数:0
复制
<script type="text/javascript" src="js/webview.js"></script>

2.1、uniapp发消息给webview

uniapp发送代码如下:

代码语言:javascript
代码运行次数:0
复制
<template>
    <view class="container">
        <web-view :src="webSrc" ref="webview" @onPostMessage="handlePostMessage" @message="handlePostMessage"></web-view>
    </view>
</template>
<script>
    onLoad() {
        /* #ifdef APP-PLUS */
        this.webSrc = plus.io.convertLocalFileSystemURL('_www/hybrid/html/camera.html');
        var currentWebview = this.$scope.$getAppWebview()
        setTimeout(()=>{this.wv = currentWebview.children()[0];},1000)
        /* #endif */
    },
    methods: {
        sendWebViewMessage(event){
            this.wv.evalJS("receiveAppMessage('" + JSON.stringify(event) + "')")
        },
    }
</script>

这里省略data中的数据。需要注意的是必须延时一秒再设定this.wv

webview接收代码如下:

代码语言:javascript
代码运行次数:0
复制
function receiveAppMessage(event) {
    event = JSON.parse(event);
}

2.1、webview发消息给uniapp

webview发送代码如下:

代码语言:javascript
代码运行次数:0
复制
function sendAppMessage(event) {
    uni.postMessage({
        data: event
    });
}

uniapp接收代码如下:

代码语言:javascript
代码运行次数:0
复制
<template>
    <view class="container">
        <web-view :src="webSrc" ref="webview" @onPostMessage="handlePostMessage" @message="handlePostMessage"></web-view>
    </view>
</template>

handlePostMessage: function (event) {
    console.log('接收webview发送的消息:', JSON.stringify(event.detail.data));
},

3、建立RTC连接

为了形象的表达建立WebRTC连接的整个过程,可以结合下面的时序图对照着文字代码部分进行理解。

WebRTC时序图

3.1、呼叫方进入视频界面,并发送视频请求

发送视频请求使用的是HTTP请求,服务端接收到请求后再通过WS推送给被呼叫方,被呼叫方被动进入视频界面。同时呼叫方建立RTC中独有的WS连接,也就是说现在呼叫方除了软件建立的WS连接,还有RTC的WS连接,用于后续的音视频通话。

3.2、被呼叫方被动进入视频界面,接收视频请求

如果被呼叫方接收到了呼叫请求,则建立RTC中独有的WS连接。

3.3、被呼叫方接受呼叫

被呼叫方受到视频请求时,界面出现接通拒接两个选项,如果被呼叫方选择接通,则通过RTC中独有的WS连接发送给呼叫方告知被呼叫方接受了视频请求。

3.4、呼叫方接受呼叫

呼叫方收到了被呼叫方接受了视频请求的消息后,也向被呼叫方回复一条呼叫方知道了被呼叫方准备建立RTC连接的消息。

3.5、被呼叫方创建peer连接并发送offer

被呼叫方收到呼叫方的回复后,知道了呼叫方已经做好准备了,于是创建peer连接:

代码语言:javascript
代码运行次数:0
复制
this.createPeerConnection();
peer.createOffer(createOfferAndSendMessage, handleCreateOfferError);
// 创建RTCPeerConnection对象
function createPeerConnection() {
    const configuration = {
        iceServers: [
            {
                urls: ["stun:这里是stun服务地址:3478"]
            },
            {
                urls: "turn:这里是turn服务地址:3478",
                username: "turn服务账号",
                credential: "turn服务密码"
            }
        ]
    };
    peer = new RTCPeerConnection(configuration);
    // 下面两个方法在3.9中补充
    peer.onicecandidate = handleIceCandidate;
    peer.onaddstream = handleRemoteStreamAdded;
    for (const trac of localStream.getTracks()) {
        peer.addTrack(trac, localStream);
    }
}
// 被呼叫方创建offer并发送offer给呼叫方
function createOfferAndSendMessage(sessionDescription) {
    peer.setLocalDescription(sessionDescription).then(() => {
        ws.send(JSON.stringify(
            {
                type: 'TO_ONE',
                uid: this.getCurrentUid(),
                to: this.getCallUid(),
                content: {
                    type: "PASSIVE_OFFER",
                    callUid: this.getCurrentUid(),
                    offer: sessionDescription
                }
            }
        ));
    })
}

3.6、呼叫方接受offer

呼叫方收到被呼叫方的offer后先创建自己的RTCPeerConnection对象,然后根据被呼叫方发来的offer设置远程连接。

代码语言:javascript
代码运行次数:0
复制
// createPeerConnection方法和上面的一样
this.createPeerConnection();
// message.offer就是被呼叫方发送过来的
peer.setRemoteDescription(new RTCSessionDescription(message.offer));

3.7、呼叫方创建并发送应答

呼叫方接受了offer后需要发送一份应答给被呼叫方,以让被呼叫方也知道呼叫方的地址。

代码语言:javascript
代码运行次数:0
复制
peer.createAnswer().then(createAnswerAndSendMessage, handleCreateAnswerError);
// 呼叫方创建offer应答
function createAnswerAndSendMessage(sessionDescription) {
    peer.setLocalDescription(sessionDescription);
    ws.send(JSON.stringify(
        {
            type: 'TO_ONE',
            uid: this.getCurrentUid(),
            to: this.getCallUid(),
            content: {
                type: "ACTIVE_ANSWER",
                callUid: this.getCurrentUid(),
                answer: sessionDescription
            }
        }
    ))
}

3.8、被呼叫方接收应答

被呼叫方接收到呼叫方的应答后,根据呼叫方的应答创建RTCSessionDescription对象。

代码语言:javascript
代码运行次数:0
复制
// 这里的message.answer是呼叫方发送来的应答
peer.setRemoteDescription(new RTCSessionDescription(message.answer));

3.9、处理ICE候选

在步骤3.5中创建RTCPeerConnection对象是指定了handleIceCandidatehandleRemoteStreamAdded两个方法。一个是指定如果接收到了远程的视频流后如何处理,另一个是如何处理本地的视频流。

代码语言:javascript
代码运行次数:0
复制
// 处理远程视频流
const handleRemoteStreamAdded = (event) => {
    remoteStream= event.stream;
    smallVideo.srcObject = remoteStream;
    smallVideo.play()
}
// 处理ICE候选
const handleIceCandidate = (event) => {
    if (event.candidate) {
        ws.send(JSON.stringify(
            {
                type: 'TO_ONE',
                uid: this.getCurrentUid(),
                to: this.getCallUid(),
                content: {
                    type: "CANDIDATE",
                    callUid: this.getCurrentUid(),
                    candidate: event.candidate
                }
            }
        ))
    }
}

4、停止视频数据传输

即微信视频中时暂时停止视频画面的传输。

代码语言:javascript
代码运行次数:0
复制
localStream.getVideoTracks()[0].enabled = false;

重新开启摄像头视频的传输重新设置为true即可。

5、停止音频数据传输

即微信视频中时暂停麦克风的输入。

代码语言:javascript
代码运行次数:0
复制
localStream.getAudioTracks()[0].enabled = false;

重新开启麦克风的传输重新设置为true即可。

6、最终效果

WebRTC效果图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈开发日记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、背景
  • 2、web-view与uniapp通信
    • 2.1、uniapp发消息给webview
    • 2.1、webview发消息给uniapp
  • 3、建立RTC连接
    • 3.1、呼叫方进入视频界面,并发送视频请求
    • 3.2、被呼叫方被动进入视频界面,接收视频请求
    • 3.3、被呼叫方接受呼叫
    • 3.4、呼叫方接受呼叫
    • 3.5、被呼叫方创建peer连接并发送offer
    • 3.6、呼叫方接受offer
    • 3.7、呼叫方创建并发送应答
    • 3.8、被呼叫方接收应答
    • 3.9、处理ICE候选
  • 4、停止视频数据传输
  • 5、停止音频数据传输
  • 6、最终效果
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档