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

1、背景

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

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

2、web-view与uniapp通信

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

<script type="text/javascript" src="js/webview.js"></script>

2.1、uniapp发消息给webview

uniapp发送代码如下:

<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接收代码如下:

function receiveAppMessage(event) {
    event = JSON.parse(event);
}

2.1、webview发消息给uniapp

webview发送代码如下:

function sendAppMessage(event) {
    uni.postMessage({
        data: event
    });
}

uniapp接收代码如下:

<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连接:

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设置远程连接。

// createPeerConnection方法和上面的一样
this.createPeerConnection();
// message.offer就是被呼叫方发送过来的
peer.setRemoteDescription(new RTCSessionDescription(message.offer));

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

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

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对象。

// 这里的message.answer是呼叫方发送来的应答
peer.setRemoteDescription(new RTCSessionDescription(message.answer));

3.9、处理ICE候选

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

// 处理远程视频流
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、停止视频数据传输

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

localStream.getVideoTracks()[0].enabled = false;

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

5、停止音频数据传输

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

localStream.getAudioTracks()[0].enabled = false;

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

6、最终效果

"WebRTC实现效果图" style="zoom: 25%;" />![
在这里插入图片描述](https://i-blog.csdnimg.cn/direct/06548629c81d47b9b9d315a5c148f6e1.png)

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

C站直链下载地址:https://download.csdn.net/download/Stand_Fast/89978217

WebRTC 简介 WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音通话或视频聊天的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。 WebRTC提供了实时音视频的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。 虽然WebRTC的目标是实现跨平台的Web端实时音视频通讯,但因为核心层代码的Native、高品质和内聚性,开发者很容易进行除Web平台外的移殖和应用。很长一段时间内WebRTC是业界能免费得到的唯一高品质实时音视频通讯技术。 为什么需要 WebRTC 开发者教程? 虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的codec,且包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透等众多门槛并不低的技术。抛开音视频技术本身的复杂性外,要想找到合适的资料、完整的代码和库、配合合适的IDE和辅助工具能正常地实现编译和安装都非常的不容易,而这还只是个开始。没有靠谱的教程,你该怎么开始?那么地坑等在那,难道你打算一个一个趟过去? 本《WebRTC 零基础开发者教程》主要讲了什么 本文中提供下载的《WebRTC 零基础开发者教程》将以一个初学者的角度,从0开始逐步引导你掌握WebRTC开发的方方面面(当然,教程中更多的是操作性的内容,具体到技术原理和实现,显然不是本教程的讨论范畴)。 《WebRTC 零基础开发者教程》目录 1 工具 1.1 depot_tools 1.1.1 目标 1.1.2 Chromium 1.1.3 使用说明在这儿 1.1.4 下载 1.1.5 使用 1.1.6 具体使用例子 1.2 Gyp工具 1.3 Python工具 1.4 本地集成开发环境(IDE ) 1.4.1 Visual studio 1.4.2 Kdevelop 1.4.3 Eclipse 2 Webrtc 2.1 下载、编译 2.1.1 Windows下 2.1.2 ubuntu下编译 2.1.3 编译Android(只能在 linux 下) 3 webrtc开发 3.1 开发P2P视频软件需要处理的问题 3.1.1 用户列的获取、交换、信令的交换 3.1.2 P2P通信 3.1.3 多媒体处理 3.2 webrtc架构 3.2.1 WebRTC架构组件介绍 3.2.2 WebRTC核心模块API介绍 3.2.3 webRTC核心API详解 4 Libjingle详细介绍 4.1 重要组件 4.1.1 信号 4.1.2 线程和消息 4.1.3 名称转换 4.1.4 SSL支持 4.1.5 连接 4.1.6 传输,通道,连接 4.1.7 候选项 4.1.8 数据包 4.2 如何工作 4.2.1 Application模块 4.2.2 XMPP Messaging Component 模块 4.2.3 Session Logic and management commponent 模块 4.2.4 Peer to peer Component 模块 4.2.5 其他 4.3 建立libjingle应用程序 5 代码分析 5.1 音频通道建立过程 5.2 音频接收播放过程 5.3 视频接收播放过程 6 协议 6.1 XMPP协议 6.1.1 原理介绍 6.1.2 XMPP 协议网络架构 6.1.3 XMPP 协议的组成 6.1.4 Xmpp介绍 6.1.5 协议内容 6.2 Stun协议 6.2.1 P2P实现的原理 6.2.2 P2P的常用实现 6.2.3 Stun URI 6.2.4 内容 6.2.5 中文内容 6.2.6 开源服务器 6.2.7 公开的免费STUN服务器 6.3 Turn协议 6.3.1 概念 6.3.2 Turn uri 6.3.3 开源服务器工程 6.3.4 开源库 6.4 交互式连接建立(Interactive Connectivity Establishment) 6.4.1 IETF规格 6.4.2 开源工程 6.5 XEP-0166 Jingle 6.5.1 绪论 6.5.2 需求 6.6 Sctp协议 6.7 Rtp协议 7 附件 7.1 Gyp工具 7.2 Google test程序 7.3 Webrtc库介绍 7.4 webrtc代码相关基础知识 7.5 STUN和TURN技术浅析 7.6 基于ICE的VoIP穿越NAT改进方案 7.7 ubuntu安装使用stuntman 7.8 一个开源的ICE库——libnice介绍 7.9 4种利用TURN穿越对称型NAT方案的设计与实现 7.10 基于ICE方式SIP信令穿透Symmetric_NAT技术研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值