一对一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…

大模型入门(六)—— 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…

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…

基于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…

【数学建模】天然肠衣搭配问题衍生问题/线性规划限制条件建立问题

线性规划限制条件建立问题 前景回顾/提出问题回顾1回顾2/问题提出解决前提 解决方法坐标轴(区间)法总结 前景回顾/提出问题 回顾1 首先回顾一下DVD在线租赁问题 在 question2中&#xff0c;需要保证每个人都不会收到自己不喜欢的DVD&#xff0c;即客户在线订单数为0时候&…

umi6.x + react + antd的项目增加403(无权限页面拦截),404,错误处理页面

首先在src/pages下创建403&#xff0c;404&#xff0c;ErrorBoundary 403 import { Button, Result } from antd; import { history } from umijs/max;const UnAccessible () > (<Resultstatus"403"title"403"subTitle"抱歉&#xff0c;您无权…

HarmonyOS开发之ArkTS使用:新建活动页面

目录 目录 引言 关于ArkTS 开发环境准备 新建项目 新建活动页面 编写ArkTS代码 注册页面 运行应用 最后 引言 随着HarmonyOS&#xff08;鸿蒙操作系统&#xff09;的不断发展&#xff0c;越来越多的前端开发者投入到这个全新的生态系统中。而在HarmonyOS的开发中&…

线上副业新选择:宅家工作,4个项目助力增收!

在这个繁华世界&#xff0c;财富与智慧并驾齐驱。越来越多的人意识到&#xff0c;除了主业外&#xff0c;开拓一份副业是实现财富增长的重要途径。在此&#xff0c;我为大家精心挑选了几个值得一试的网上赚钱副业。 1&#xff0c;参与网络调查与问卷填写 随着大数据时代的到来…

kkkkkkkkkkkk564

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习 &#x1f4dd;人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

YOLOv8 Tensorrt Python/C++部署详解

按照大佬的方法进行部署&#xff0c;但是中间出现了很多问题&#xff0c;这里进行一下总结。 YOLOv8 Tensorrt Python/C部署教程_yolo 安装tensorrt-CSDN博客https://blog.csdn.net/weixin_45747759/article/details/130341118 Monday-Leo/Yolov5_Tensorrt_Win10: A simple i…

Kafka从0到消费者开发

安装ZK Index of /zookeeper/zookeeper-3.9.2 下载安装包 一定要下载-bin的&#xff0c;不带bin的是源码&#xff0c;没有编译的&#xff0c;无法执行。-bin的才可以执行。 解压 tar -zxvf apache-zookeeper-3.9.2-bin.tar.gz 备份配置 cp zoo_sample.cfg zoo_sample.cfg-b…