一对一WebRTC视频通话系列(五)——综合调试和功能完善

本系列博客主要记录一对一WebRTC视频通话实现过程中的一些重点,代码全部进行了注释,便于理解WebRTC整体实现。


本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习,梳理总结后写下文章,对音视频相关内容感兴趣的读者,可以点击观看课程网址:零声教育


一对一WebRTC视频通话系列往期博客

一对一WebRTC视频通话系列(一)—— 创建页面并显示摄像头画面
一对一WebRTC视频通话系列(二)——websocket和join信令实现
一对一WebRTC视频通话系列(三)——leave和peer-leave信令实现
一对一WebRTC视频通话系列(四)——offer、answer、candidate信令实现


主要完成工作:
(1)点击离开时,要将RTCPeerConnection关闭(close);
(2)点击离开时,要将本地摄像头和麦克风关闭;
(3)检测到客户端退出时,服务器再次检测该客户端是否已经退出房间。
(4)RTCPeerConnection时传入ICE server的参数,以便当在公网环境下可以进行正常通话

一、客户端

(1)点击离开时,要将RTCPeerConnection关闭(close);
(2)点击离开时,要将本地摄像头和麦克风关闭;
点击离开按钮后,
doLeave() -> hangup() -> closeLocalStream()

  1. doLeave()函数:发送消息离开房间。
    首先,创建一个jsonMsg对象,包含命令(cmd)、房间ID(roomId)和本地用户ID(localUserId)。
    使用JSON.stringify()方法将jsonMsg对象转换为字符串。
    调用zeroRTCEngine.sendMessage()方法将消息发送给服务器。
    输出消息内容到控制台。
    调用hangup()函数关闭本地视频流和RTCPeerConnection

  2. hangup()函数:关闭本地视频流和RTCPeerConnection
    设置localVideo.srcObject为null,不显示本地流。
    设置remoteVideo.srcObject为null,不显示对方。
    调用closeLocalStream()函数关闭本地流。
    检查pc变量是否为null,如果是,则关闭RTCPeerConnection

  3. closeLocalStream()函数:关闭本地视频流。
    检查localStream变量是否为null,如果是,则停止所有视频流。

  4. openLocalStream(stream)函数:用于打开本地流。
    检查stream变量是否为null,如果是,则输出日志信息,并调用doJoin()函数

function doLeave() {var jsonMsg = {'cmd': 'leave','roomId': roomId,'uid': localUserId,};var message = JSON.stringify(jsonMsg); //将json对象转换为字符串zeroRTCEngine.sendMessage(message);   //设计方法:用实现方法而不是直接用变量    console.info("doLeave message: " + message);hangup();
}function hangup() {localVideo.srcObject = null;//0.不显示本地流remoteVideo.srcObject = null;//1.不显示对方closeLocalStream();//2.关闭本地流if(pc != null){pc.close();//3.关闭RTCPeerConnectionpc = null;}
}
function closeLocalStream() {if(localStream != null){localStream.getTracks().forEach(function(track){track.stop();});localStream = null;}
}

关闭远程视频流,关闭RTCPeerConnection对象。

function handleRemotePeerLeave(message) {console.info("handleRomotePeerLeave message: " + message.remoteUid);remoteVideo.srcObject = null;if(pc != null){pc.close();//关闭RTCPeerConnectionpc = null;}
}

二、服务端

(3)检测到客户端退出时,服务器再次检测该客户端是否已经退出房间。

var server = ws.createServer(function (conn) {console.log("New connection");conn.sendText('我收到你的连接了')conn.client = null;//1.对应客户端信息// 监听客户端发送的消息conn.on("text", function (str) {console.info("Received msg:"+str);var jsonMsg = JSON.parse(str);switch(jsonMsg.cmd){case SIGNAL_TYPE_JOIN:conn.client = handleJoin(jsonMsg, conn); //2.返回值需要修改break;case SIGNAL_TYPE_LEAVE:handleLeave(jsonMsg);break;case SIGNAL_TYPE_OFFER:handleOffer(jsonMsg);break;case SIGNAL_TYPE_ANSWER:handleAnswer(jsonMsg);break;                 case SIGNAL_TYPE_CANDIDATE:handleCandidate(jsonMsg);break;}});// 连接关闭时的输出conn.on("close", function (code, reason) {console.log("Connection closed,code: " + code + " reason:" + reason); if(conn.client != null){ //3.如果客户还未删除//强制让客户端从房间退出handleForceLeave(conn.client);}});// 监听连接错误conn.on("error", function (error) {console.error("发生错误:", error);})
}).listen(port);

当连接关闭时,如果连接的客户端对象尚未删除,调用handleForceLeave函数强制让客户端从房间退出。

实现原理:
通过监听用户连接对象的 client.onclose 事件来触发 handleForceLeave 函数,并在其中强制离开用户。
1.首先,从用户连接对象中获取房间ID和用户ID。
2.然后,在全局变量roomTableMap 中查找房间ID对应的房间对象。
3.判断用户ID是否存在于房间内。如果不在房间内,则输出日志并返回。
4.如果用户已经在房间内,则输出日志并从房间对象中移除用户ID。
5.判断房间对象中是否还有其他用户。如果有其他用户,则给所有房间内其他用户发送用户离开消息。

function handleForceLeave(client){// 获取房间ID和用户IDvar roomId = client.roomId;var uid = client.uid;// 1.先查找房间号var roomMap = roomTableMap.get(roomId);if(roomMap == null){console.error("roomId: " + roomId + " is not exist");return;}// 2.判别uid是否在房间内if(roomMap.contains(uid) == false)  {console.info("uid: " + uid + " have leave roomId " + roomId);return;}// 3.说明客户端没有正常离开,所以我们要强制离开程序console.info("uid: " + uid + " force leave roomId " + roomId);roomMap.remove(uid);if(roomMap.size() >= 1){var clients = roomMap.getEntrys();for(var i in clients){jsonMsg = {'cmd':SIGNAL_TYPE_PEER_LEAVE,'remoteUid':uid}// 给所有房间内其他用户发送用户离开消息var msg = JSON.stringify(jsonMsg);var remoteUid = clients[i].key;var remoteClient =roomMap.get(remoteUid);if(remoteClient){console.info("notify peer "+ remoteClient.uid +" uid " + uid + " leave room");remoteClient.conn.sendText(msg);}}}    
}

三、公网通讯

(4)RTCPeerConnection时传入ICE server的参数,以便当在公网环境下可以进行正常通话

3.1 启动coturn

# nohup是重定向命令,输出都将附加到当前目录的 nohup.out 文件中; 命令后加 & ,后台执行起来后按
ctr+c,不会停止
sudo nohup turnserver -L 0.0.0.0 -a -u sxl:zxc -v -f -r nort.gov &
# 前台启动
sudo turnserver -L 0.0.0.0 ‐a -u sxl:zxc -v -f -r nort.gov
#然后查看相应的端口号3478是否存在进程
sudo lsof -i:3478

安装 sysstat包,查看网络情况

sudo apt-get install sysstat
sudo sar -n DEV 1

3.2修改配置文件

修改客户端main.js代码,

    var defaultConfiguration = {  bundlePolicy: "max-bundle",rtcpMuxPolicy: "require",iceTransportPolicy:"relay",//relay 或者 all// 修改ice数组测试效果,需要进行封装iceServers: [{"urls": ["turn:192.168.226.3:3478?transport=udp","turn:192.168.226.3:3478?transport=tcp"       // 可以插入多个进行备选],"username": "sxl","credential": "zxc"},{"urls": ["stun:192.168.226.3:3478"]}]};

new RTCPeerConnection()时,使用defaultConfiguration参数来创建对象。

pc = new RTCPeerConnection(defaultConfiguration);

测试

设置configuration,先设置为relay中继模式,只有relay中继模式可用的时候,才能部署到公网去(部署到公网后也先测试relay)。
使用realy中继:
在这里插入图片描述
使用局域网P2P
在这里插入图片描述
可以看出采用realy中继通信下,网络流量明显大于p2p。
下图显示了网络协商打印情况:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/834714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据分析处理的步骤是什么?制造业企业如何挑选数据分析处理软件?看这篇就够了

随着工业4.0的深入实施以及国家对制造业高质量发展战略的日益强调&#xff0c;工业数据已经崭露头角&#xff0c;成为生产经营活动中至关重要的核心要素。不仅如此&#xff0c;工业数据还作为优质的生产要素&#xff0c;为新兴生产力的形成提供了强有力的支撑&#xff0c;从而推…

服务异步通讯MQ

同步调用存在的问题: 异步调用方案: RabbitMQ安装: 第一种:在线拉取 docker pull rabbitmq:3-management 第二种:将已有的安装包放入再用load加载 我这里放到tmp包里边 然后:cd /tmp docker load -i mq.tar 加载进去 然后运行mq容器 docker run \-e RABBITMQ_DEFAULT_USER…

(13)配置飞行中的FFT(一)

文章目录 前言 1 参数说明 前言 ArduPilot 预先配置了所有 FFT 设置的适当默认值。 &#xff01;Note 此功能包含在内存为 2MB 的自动驾驶仪中。请查看自动驾驶仪的"各板固件限制列表"(List of Firmware Limitations by Board)&#xff0c;以确定你的自动驾驶仪…

Fourteen Day 2024年5月10日

Battle n.战斗 战役 战争 vi.决战 斗争 Gun battle. 枪战 Gun n.枪 炮 Go out to battle. 奔赴战场。 Cattle n.牛 The cattle were eating grass. 牛在吃草。 Grass n.草 草坪 牧场 Stand n.站 坐落 She stands in the rain. 她站在雨中。 Rain n.雨 vi.下雨 Sta…

大模型入门(六)—— RLHF微调大模型

一、RLHF微调三阶段 参考&#xff1a;https://huggingface.co/blog/rlhf 1&#xff09;使用监督数据微调语言模型&#xff0c;和fine-tuning一致。 2&#xff09;训练奖励模型 奖励模型是输入一个文本序列&#xff0c;模型给出符合人类偏好的奖励数值&#xff0c;这个奖励数值…

未来编码探索:揭秘Java的进化之旅与技术革新!

Java是一种广泛使用的编程语言&#xff0c;自1995年问世以来&#xff0c;它在企业级应用、移动应用开发、大数据处理等领域都有着广泛的应用。随着时间的推移&#xff0c;Java也在不断发展和进化&#xff0c;以满足不断变化的技术需求和市场趋势。本文将全面详细地探讨Java的未…

MyBatis(该篇足已)

目录 一.MyBatis是什么&#xff1f; 二.为什么学习MyBatis呢&#xff1f; 三.MyBatis的学习 3.1MyBatis的开发流程 3.2MyBatis项目 四.MyBatis的增删改操作 五.参数占位符 #{} 和 ${} 六.映射返回 七.映射失败 八.数据库连接池 九.动态SQL 9.1<if>标签 9.2&…

LeetCode63:不同路径Ⅱ

题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角…

5.07 Pneumonia Detection in Chest X-Rays using Neural Networks

肺炎诊断是一个耗时的过程&#xff0c;需要高技能的专业人员分析胸部X光片chest X-ray (CXR)&#xff0c;并通过临床病史、生命体征和实验室检查确认诊断。 它可以帮助医生确定肺部感染的程度和位置。呼吸道疾病在 X 光片上表现为一处膨胀的不透明区域。然而&#xff0c;由于不…

力扣HOT100 - 155. 最小栈

解题思路&#xff1a; 辅助栈 class MinStack {private Stack<Integer> stack;private Stack<Integer> min_stack;public MinStack() {stack new Stack<>();min_stack new Stack<>();}public void push(int val) {stack.push(val);if (min_stack.i…

OLAP与OLTP

OLAP 简介 OLAP&#xff08;联机分析处理&#xff0c;全称Online Analytical Processing&#xff09;是一种针对大规模数据集进行高性能分析和查询的数据处理技术。与传统的联机事务处理&#xff08;OLTP&#xff09;不同&#xff0c;OLAP更侧重于支持复杂的分析和决策支持任…

LeetCode 404.左叶子之和

LeetCode 404.左叶子之和 1、题目 题目链接&#xff1a;404. 左叶子之和 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别…

SaToken框架实现在Rpc上下文的login处理逻辑

最近在工作中遇到一个需求&#xff0c;需要在项目A中实现一个rpc接口供其他项目调用&#xff0c;接口返回登录token&#xff0c;从而实现其他项目的用户能免密登录到项目A。 项目A是用了SaToken来做的鉴权&#xff0c;原本我的打算是直接在rpc中调用StpUtil.login()方法来实现登…

在Flask中使用Celery完成异步和定时任务(Flask、Celery、Redis)

编程目标 通过使用Flask和Celery&#xff0c;实现一个简单的Web应用程序&#xff0c;能够接收HTTP POST请求&#xff0c;并异步发送电子邮件。 说明 使用Flask创建一个简单的Web应用程序&#xff0c;包含一个HTTP POST路由&#xff0c;用于接收发送电子邮件的请求。使用Cele…

离心式冷水机组的控制逻辑

1&#xff09;冷冻水泵启停控制 机组处于停机状态下启动机组时&#xff0c;冷冻水泵相对于油泵提前 5 分钟启动&#xff0c;在机组开机状态下 &#xff08;包括待机&#xff09;&#xff0c;冷冻水泵一直处于开机状态&#xff0c;机组正常关机后&#xff0c;冷冻水泵相对于主电…

基于Spring Boot的酒店管理系统设计与实现

基于Spring Boot的酒店管理系统设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 系统首页界面图&#xff0c;在系统首页可以查看首页…

java io包

InputStream InputStream 是 Java I/O 中所有输入流的抽象基类&#xff0c;它定义了读取字节流的基本方法。InputStream 类提供了许多子类&#xff0c;用于从不同的数据源读取数据&#xff0c;如文件、网络连接、内存等。 InputStream 提供了以下常用的方法&#xff1a; int…

Spring Data JPA 与 MyBatisPlus的比较

前言 JPA&#xff08;Java Persistence API&#xff09;和MyBatis Plus是两种不同的持久化框架&#xff0c;它们具有不同的特点和适用场景。 JPA是Java官方的持久化规范&#xff0c;它提供了一种基于对象的编程模型&#xff0c;可以通过注解或XML配置来实现对象与数据库的映射…

如何给网页添加一个炫酷鼠标点击特效,鼠标特效源码分享(更多特效持续收集中...)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 鼠标特效 📒📝 火花特效🎈 源码📝 爱心特效🎈 源码📝 彩球爆炸特效🎈 源码📝 更多特效📖 介绍 📖 你是否厌倦了平淡无奇的网页交互?是否渴望为你的网站增添一抹亮色?本文将持续更新,与大家分享收集到的前…

区块链 | NFT 相关论文:Preventing Content Cloning in NFT Collections(二)

&#x1f436;原文&#xff1a; Preventing Content Cloning in NFT Collections &#x1f436;写在前面&#xff1a; 这是一篇 2023 年的 CCF-C 类&#xff0c;本博客只记录其中提出的方法。 F C o l l N F T \mathbf{F_{CollNFT}} FCollNFT​ and ERC-721 NFTs 在以太坊这样…