webrtc-m79-测试peerconnectionserver的webclient-p2p-demo
1 背景
webrtc的代码中有peerconnectionclient和peerconnectionserver的例子,但是没有对应的web端的例子,这里简单的写了一个测试例子,具体如下:
2 具体操作
2.1 操作流程

2.2 测试效果
使用webclient与peerconnectionclient的测试效果如下:

3 前端代码
<html>
<head><title>webclient p2p demo</title><meta charset="utf-8"><style>.left_part {width: 50%;float: left;}.right_part {width: 50%;float: right;overflow-y: scroll;}</style><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head><body><div class="right_part" id="left_part_container"><div>SignalServer:<input type="text" id="signal_url" value="127.0.0.1:8888"><button id="btn_sign_in">登入</button><button id="btn_sign_out">登出</button><br><input type="text" id="selected_peerid_for_p2p" disabled value="不允许修改的文本"><button id="btn_start_p2p" disabled>start_p2p</button></div><br><table id="PeersTable"><thead><tr><th>Name</th><th>PeerId</th><th>Status</th></tr></thead></table></div><div class="left_part" id="left_part_container"><video controls autoplay id="rtc_video_play" height="500" style="width:100%"></video></div><script type="text/javascript">var myselfPeerId = -1;var pc = new RTCPeerConnection({ "offerExtmapAllowMixed": false });var datachannel = null;var stream = new MediaStream();async function initPC() {pc.addTransceiver("audio", {direction: "recvonly"});pc.addTransceiver("video", {direction: "recvonly"});pc.onconnectionstatechange = function(event){console.log("connection state change: ", pc.connectionState);};pc.onicecandidate = async (ev) => {console.log('=======>' + JSON.stringify(ev.candidate)); };pc.ontrack = function(event) {stream.addTrack(event.track); };datachannel = pc.createDataChannel('chat');datachannel.onopen = function(event) {console.log("datachannel onopen: ", event.data);}datachannel.onmessage = function(event) {console.log("receive message: ", event.data);}datachannel.onerror = function(event) {console.log("datachannel error: ", event.data);}datachannel.onclose = function(event) {console.log("datachannel close: ");} }async function startP2P(signal_url) {initPC();var offer = await pc.createOffer();await pc.setLocalDescription(offer);let sendOfferPromise = await fetch(signal_url, {"method": "POST","body": JSON.stringify(offer)});if (sendOfferPromise.ok) {console.log("send offer: " + JSON.stringify(offer)); } else {alert("HTTP-Error: " + sendOfferPromise.status);} } async function nfyFromSignal(nfyPromise) {let nfyString = await nfyPromise.text();if (nfyString.includes("answer")) {console.log("receive answer: " + nfyString);pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(nfyString)));} else if (nfyString.includes("candidate")) {console.log("receive candidate: " + nfyString);pc.addIceCandidate(new RTCIceCandidate(JSON.parse(nfyString)));} else {let peersString = nfyString;// console.log("rsp: ", peersString)let peersChunk = peersString.split("\n");for (let i=0; i<peersChunk.length && peersChunk[i].length>0; ++i) {const peerColumns = peersChunk[i].split(",");// console.log("index: " + i + ", data: " + peerColumns)// for example: kevin@home-pc,36,1// peerColumns[0]: peer_name// peerColumns[1]: peer_id// peerColumns[2]: peer_status// table's column index starts from 1, not 0const row_find_peer_id = $("#PeersTable tr:has(td:nth-child(2):contains('" + peerColumns[1] + "'))");if (row_find_peer_id.length > 0) {console.log("peerid:" + peerColumns[1] + ", status change from " + row_find_peer_id.find('td:nth-child(3)').text() + " to " + peerColumns[2]);row_find_peer_id.find('td:nth-child(3)').text(peerColumns[2]);continue;}const row_find_peer_name = $("#PeersTable tr:has(td:nth-child(1):contains('" + peerColumns[0] + "'))");if (row_find_peer_name.length > 0) {console.log("peerid:" + peerColumns[1] + ", status change from " + row_find_peer_name.find('td:nth-child(3)').text() + " to " + peerColumns[2]);row_find_peer_name.find('td:nth-child(2)').text(peerColumns[1]);row_find_peer_name.find('td:nth-child(3)').text(peerColumns[2]);continue;} const row_peer = $("<tr>");row_peer.append($("<td>").text(peerColumns[0]));row_peer.append($("<td>").text(peerColumns[1]));row_peer.append($("<td>").text(peerColumns[2]));$("#PeersTable").append(row_peer);} }}async function pendingWait(myself_peerid) {const signal_url = document.getElementById("signal_url").value;while (true) {let v = await fetch(`http://${signal_url}/wait?peer_id=${myself_peerid}`);nfyFromSignal(v);}}$('#btn_sign_in').on('click', async () => {const signal_url = document.getElementById("signal_url").value;let signinResultPromise = await fetch(`http://${signal_url}/sign_in`);if (signinResultPromise.ok) {myselfPeerId = parseInt(signinResultPromise.headers.get("Pragma"));console.log("my peerid is: " + myselfPeerId);nfyFromSignal(signinResultPromise);pendingWait(myselfPeerId); } else {alert("HTTP-Error: " + signinResultPromise.status);}}) $('#btn_sign_out').on('click', async () => {$("#PeersTable tbody").empty();const signal_url = document.getElementById("signal_url").value;let signoutResultPromise = await fetch(`http://${signal_url}/sign_out?peer_id=${myselfPeerId}`);if (signoutResultPromise.ok) {console.log("sign_out: " + myselfPeerId + " successful"); } else {alert("HTTP-Error: " + signoutResultPromise.status);}})$('#PeersTable').on('click', 'tr', function() {const row_selected = $(this);const row_selected_peer_id = parseInt(row_selected.find('td:nth-child(2)').text());if (row_selected_peer_id === myselfPeerId) {console.log("You should not choose yourself [" + myselfPeerId + "] to start p2p");$("#btn_start_p2p").prop("disabled", true);return;}const row_selected_peer_id_status = parseInt(row_selected.find('td:nth-child(3)').text());if (row_selected_peer_id_status === 1) {console.log("selected peerid: " + row_selected_peer_id);$('#selected_peerid_for_p2p').val(row_selected_peer_id);$("#btn_start_p2p").prop("disabled", false); } else {console.log("The peer [" + row_selected_peer_id + "] you choose is offline");$("#btn_start_p2p").prop("disabled", true);}})$('#btn_start_p2p').on('click', async () => {const signal_url = document.getElementById("signal_url").value;const remote_peer_id = $('#selected_peerid_for_p2p').val();const sendmsg_url = `http://${signal_url}/message?peer_id=${myselfPeerId}&to=${remote_peer_id}`;console.log("sendmsg url: " + sendmsg_url);// $('#rtc_video_play').show();// $('#rtc_video_play').prop('muted', false);$('#rtc_video_play').prop('srcObject', stream);console.log("Start P2P from [" + myselfPeerId + "] to [" + remote_peer_id + "]");startP2P(sendmsg_url);})</script>
</body>
</html>
相关文章:
webrtc-m79-测试peerconnectionserver的webclient-p2p-demo
1 背景 webrtc的代码中有peerconnectionclient和peerconnectionserver的例子,但是没有对应的web端的例子,这里简单的写了一个测试例子,具体如下: 2 具体操作 2.1 操作流程 2.2 测试效果 使用webclient与peerconnectionclient的…...
C#,《小白学程序》第十五课:随机数(Random)第二,统计学初步,数据统计的计算方法与代码
1 文本格式 /// <summary> /// 《小白学程序》第十五课:随机数(Random)第二,统计学初步,数据统计的计算方法与代码 /// 用随机数做简单的统计并用图形显示统计结果。 /// </summary> /// <param name&q…...
C# 子类如何访问子类的方法(同一父类)
在继承关系中,子类可以通过创建另一个子类的对象来访问其方法。下面是一个示例,展示了子类如何访问另一个子类的方法: public class Animal {public virtual void Speak(){Console.WriteLine("我是动物。");} }public class Cat :…...
《Docker 容器化的艺术:深入理解容器技术》
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack: 📚…...
gitlab配置hook,commit message的时候校验提交的信息
在 GitLab 中配置 Webhook 来调用 Java 接口以校验 commit 信息,是很多公司的一些要求,因为提交信息的规范化是必要的 不阻止commit的版本 在 GitLab 项目中进入设置页面。 在左侧导航栏中选择 “Webhooks”(Web钩子)。 在 We…...
ssh远程管理服务
ssh远程管理服务是什么 SSH是一个安全协议,在进行数据传输时,会对数据包进行加密处理,加密后在进行数据传输。确保了数据传输安全, 那SSH服务主要功能有哪些呢? 1.提供远程连接服务器的服务 1)linux远程连接协议&…...
C语言顺序表
文章目录 前言线性表顺序表静态顺序表动态顺序表 接口实现 前言 我们先补一下上篇博客落下的知识点: 首先说一下斐波那契的时间复杂度和空间复杂度: long long Fac(size_t N) {if(0 N)return 1;return Fac(N-1)*N; }还是说一下size_t代表的类型是unsi…...
滑动窗口详解
滑动窗口本质其实也是一种双指针算法,只是因为它维护的区间随着遍历的进行在不停变化,所以形象地称为“滑动窗口” 一、⻓度最⼩的⼦数组 题目要求找到满足条件的长度最小的子数组,我们先来想想暴力的做法,再来想想能不能优化&am…...
JAVA -华为真题-分奖金
需求: 公司老板做了一笔大生意,想要给每位员工分配一些奖金,想通过游戏的方式来决定每个人分多少钱。按照员工的工号顺序,每个人随机抽取一个数字。按照工号的顺序往后排列,遇到第一个数字比自己数字大的,那么…...
第二章:25+ Python 数据操作教程(第十八节如何使用 Matplotlib 库在 python 中执行绘图和数据可视化)持续更新中
本教程概述了如何使用 Matplotlib 库在 python 中执行绘图和数据可视化。这篇文章的目的是让您熟悉该库的基础知识和高级绘图功能。它包含几个示例,将为您提供使用 Python 生成绘图的实践经验。 目录 什么是 Matplotlib? Matplotlib 基础知识<...
XShell7 + Xftp7 + IDEA 打包MapReduce程序到集群运行
参考博客 【MapReduce打包成jar上传到集群运行】http://t.csdn.cn/2gK1d 【Xshell7/Xftp7 解决强制更新问题】http://t.csdn.cn/rxiBG IDEA打包MapReduce程序 这里的打包是打包整个项目,后期等学会怎么打包单个指定的mapreduce程序再来更新博客。 1、编译打包 …...
微软D365 入门文章汇总以及各项认证介绍(持续跟新.....)
介绍 希望入门D365的同学们,需要具备的知识点,涉及C#,WebApi,前端知识,Power Platform等知识,以及Azure的知识点等,需要有了解。 实施Microsoft Dynamics 365 CE (12章)…...
vscode搭建Django自带后台管理系统
文章目录 一、django自带的后台管理系统1. 建表2. 后台管理系统2.1 创建账号2.2 运行后台2.3 登录 二、模版渲染1. 直接将数据渲染到页面2. 数据传递给js 三、数据库1. 查看当前数据库2. 创建UserInfo数据表3. Django rest framework配置 四、vue前端搭建1. 在Django项目的根目…...
Verilog零基础入门(边看边练与测试仿真)-时序逻辑-笔记(4-6讲)
文章目录 第四讲第五讲第六讲 第四讲 1、计数器 代码: //计数器 timescale 1ns/10ps module counter(clk,res,y); input clk; input res; output[7:0] y;reg[7:0] y; wire[7:0] sum;//1运算的结果(1࿰…...
2023-09-12力扣每日一题
链接: 1462. 课程表 IV 题意 一个pair<int,int>表示a是b的前置 进行n次查询,查询q是否是p的前置(可以不是直接前置) 解: 就是要把01、12、13这种能转换出02、03,弗洛伊德即可 无环无负权 实际…...
leetcode面试题:交换和(三种方法实现)
交换和: 给定两个整数数组,请交换一对数值(每个数组中取一个数值),使得两个数组所有元素的和相等。 返回一个数组,第一个元素是第一个数组中要交换的元素,第二个元素是第二个数组中要交换的元…...
前端可视化界面开发技术:实战与优化
引言 在当今的互联网时代,数据可视化已经成为信息展示和交互的重要方式。特别是在前端开发领域,可视化界面的应用越来越广泛,涉及到数据监控、分析和决策等多种场景。本文将深入探讨前端可视化界面开发的关键技术,通过实例解析提…...
Python实现机器学习(下)— 数据预处理、模型训练和模型评估
前言:Hello大家好,我是小哥谈。本门课程将介绍人工智能相关概念,重点讲解机器学习原理机器基本算法(监督学习及非监督学习)。使用python,结合sklearn、Pycharm进行编程,介绍iris(鸢尾…...
树结构处理,list和tree互转
1、实体类 package com.iot.common.test.entity;import lombok.Data;import java.util.List;/*** description:* author:zilong* date:2023/9/8*/ Data public class Node {//idprivate String id;//父节点idprivate String pId;//名称private String name;//编码private Stri…...
可视化大屏设计模板 | 主题皮肤(报表UI设计)
下载使用可视化大屏设计模板,减少重复性操作,提高报表制作效率的同时也确保了报表风格一致,凸显关键数据信息。 软件:奥威BI系统,又称奥威BI数据可视化工具 所属功能板块:主题皮肤上传下载(数…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
