【开发日记】使用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.youkuaiyun.com/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技术研究
### 抓取和分析微信实时音视频通话的数据包 为了有效抓取和分析微信实时音视频通话中的数据包,可以采用多种方法和技术工具来完成这一过程。以下是具体的方法: #### 使用Wireshark进行网络流量捕获 Wireshark是一款广泛使用的开源协议分析器,能够帮助深入理解网络通信细节。对于想要捕捉到微信音视频通话期间产生的UDP/TCP数据流来说,安装并启动Wireshark后设置过滤条件为`udp port 80 or tcp port 443`可专注于常见的HTTP(S)端口以及可能用于传输媒体流的其他自定义端口号。 当执行具体的操作时,例如发起一次新的语音或视频会话之前先暂停Wireshark录制;一旦开始对话即刻恢复捕获直至结束交流为止。这样做有助于减少无关背景噪声干扰目标样本采集工作[^1]。 #### 利用Fiddler调试HTTPS请求 考虑到现代即时通讯应用倾向于加密其信令通道(如建立连接前后的控制指令),利用像Fiddler这样的中间件代理服务器可以帮助拦截解密这些经过SSL/TLS保护的信息交换流程。需要注意的是,这通常涉及到信任根证书导入设备浏览器环境之中以便让应用程序认为正在与合法的服务端实体交谈而不是第三方监听者。 此外,由于部分新型号手机操作系统加强了安全策略限制非官方渠道获取内部API调用详情的能力,因此建议优先选取较旧版本安卓平台作为实验对象更为可行一些[^2]。 #### 关注特定协议特征 根据已有研究指出,在实际环境中观察到来自媒体播放器发送给远端节点带有RTP/RTCP负载的有效载荷格式遵循WebRTC标准框架下的Transport-CC机制来进行拥塞控制反馈报告传递活动。这意味着如果希望进一步解析所获得原始字节串,则有必要熟悉掌握上述提到的相关RFC文档说明及其变体实现方式[^3]。 ```python import wireshark def capture_wechat_call(): cap = wireshark.Capture(interface='eth0', display_filter='udp') packets = [] try: while True: packet = next(cap) if 'rtp' in str(packet.layers).lower() or 'rtcp' in str(packet.layers).lower(): packets.append(packet) except KeyboardInterrupt: pass finally: cap.close() return packets ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二饭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值