当前位置: 首页 > news >正文

webRtc 示例

1、使用socket.io进行会话

2、为了方便,参数写死在前端了,前端界面1代码如下(由界面1发起视频):

<!DOCTYPE html>
<html><head><title>Socket.IO chat</title><meta charset="utf-8"><meta name="description" content="WebRTC code samples"><meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Client-side WebRTC code samples"><meta itemprop="name" content="WebRTC code samples"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#ffffff"><!-- 引入2.0版本的socket.io文件 --><script src="socket.io.js"></script><script src="webrtc.js"></script><script src="jquery-3.6.4.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css"><link rel="stylesheet" href="css/main.css" /><link rel="stylesheet" href="css/c1/main.css" /></head><body><div id="container"><video id="localVideo" title="a" playsinline autoplay muted></video><video id="remoteVideo" title="b" playsinline autoplay></video><div><button id="prepareBtn" type="button" onclick="prepare()">准备</button><button id="callBtn" type="button" onclick="callVideo()">呼叫</button><button id="cancelBtn" type="button" onclick="cancelVideo()">挂断</button></div></div><script>const prepareButton = document.getElementById('prepareBtn');const callBtn = document.getElementById('callBtn');const cancelBtn = document.getElementById('cancelBtn');const localVideo = document.getElementById('localVideo');const remoteVideo = document.getElementById('remoteVideo');let localStream;let pc1;let pc2;let to = '2';var iceServer = {{// urls: 'stun:stun.l.google.com:19302'urls: 'stun:stun.services.mozilla.com'}]};const offerOptions = {offerToReceiveAudio: 1,offerToReceiveVideo: 0};//建立socket连接const socket = io("https://192.168.3.21", {reconnectionDelayMax: 10000,auth: {token: "123"},query: {"userId": "1"}});socket.on("connect", () => {console.log("通道已建立")});//监听服务端发送的 topic1 消息socket.on("exchange", (msg) => {console.log("收到新的数据了");var data = JSON.parse(msg)console.log(data);var type = data.typeif (type === 'invite') {to = data.from} else if (type === 'recive') {to = data.from} else if (type === 'canditate') {if (data.data != undefined) {pc1.addIceCandidate(new RTCIceCandidate(data.data))}} else if (type === 'offer') {//设置远程应答pc1.setRemoteDescription(new RTCSessionDescription(data.data))pc1.createAnswer().then(function (answer) {send({type: 'answer',data: answer})return pc1.setLocalDescription(answer)}).then(sdp => {})} else if (type === 'answer') {if (data.data != undefined) {pc1.setRemoteDescription(new RTCSessionDescription(data.data))}}});function gotStream(stream) {localVideo.srcObject = stream;localStream = stream;}async function init() {navigator.mediaDevices.getUserMedia({audio: true,video: false}).then(gotStream).catch(e => alert(`getUserMedia() error: ${e.name}`));}async function prepare() {init();var data = {type: 'invite',data: 'video',from: '1',toUserId: '2'};// send(data);prepareButton.disabled = true;}function call() {pc1 = new RTCPeerConnection(iceServer);pc1.onicecandidate = e => onIceCandidate(pc1, e);// 有远程视频流时,显示远程视频流 pc1.addEventListener('track', event => {// remoteVideo.srcObject = event.streams[0]// remoteVideo.onloadedmetadata = function (e) {//     remoteVideo.play()// }})pc1.addEventListener('addstream', e => {console.log("AAAAAAAAAAA")console.log(e);remoteVideo.srcObject = e.stream})//初始化本人的视频流navigator.mediaDevices.getUserMedia({audio: false,video: true}).then(stream => {// 将视频流写入到video标签localVideo.srcObject = stream;localStream = stream;stream.getTracks().forEach(track => {pc1.addTrack(track, stream)});//向对方发送应答pc1.createOffer().then(sdp => {pc1.setLocalDescription(sdp)send({type: 'offer',data: sdp})})})localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));callBtn.disabled = true;}function onIceCandidate(pc, event) {if (event.candidate) {send({type: 'canditate',data: event.candidate})}}function send(data) {data.toUserId = data.toUserId || toconsole.log(data)socket.emit("exchange", JSON.stringify(data))}function callVideo() {call();}function cancelVideo() {if (pc1 != null && pc1 != undefined) {pc1.close();}}</script><style>#video {background-color: black;height: 30vh;}</style>
</body></html>

3、前端界面2代码如下(当界面1发起视频呼叫后,该界面被动应答):

<!DOCTYPE html>
<html lang="zh"><head><title>Socket.IO chat</title><meta charset="utf-8"><meta name="description" content="WebRTC code samples"><meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Client-side WebRTC code samples"><meta itemprop="name" content="WebRTC code samples"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#ffffff"><!-- 引入2.0版本的socket.io文件 --><script src="socket.io.js"></script><script src="webrtc.js"></script><script src="jquery-3.6.4.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css"><link rel="stylesheet" href="css/main.css" /><link rel="stylesheet" href="css/c1/main.css" />
</head><body><div id="container"><video id="localVideo" title="a" playsinline autoplay muted></video><video id="remoteVideo" title="b" playsinline autoplay></video></div><script>const localVideo = document.getElementById('localVideo');const remoteVideo = document.getElementById('remoteVideo');let localStream;let pc1;let pc2;let to = '1';var iceServer = {{// urls: 'stun:stun.l.google.com:19302'urls: 'stun:stun.services.mozilla.com'}]};//建立socket连接const socket = io("https://192.168.3.21", {reconnectionDelayMax: 10000,auth: {token: "123"},query: {"userId": "2"}});socket.on("connect", () => {console.log("通道已建立")});//监听服务端发送的 topic1 消息socket.on("exchange", (msg) => {console.log("收到新的数据了");var data = JSON.parse(msg)var type = data.typeconsole.log({"name": "接收方",data});if (type === 'invite') {to = data.from//打开自己的摄像头init();} else if (type === 'recive') {to = data.from} else if (type === 'canditate') {if (pc1 == null) {init();}if (data.data != undefined) {pc1.addIceCandidate(new RTCIceCandidate(data.data))}} else if (type === 'offer') {if (pc1 == null) {init();}pc1.setRemoteDescription(new RTCSessionDescription(data.data))pc1.createAnswer().then(function (answer) {send({type: 'answer',data: answer})return pc1.setLocalDescription(answer)}).then(sdp => {})} else if (type === 'answer') {if (data.data != undefined) {pc1.setRemoteDescription(new RTCSessionDescription(data.data))}}});function gotStream(stream) {localVideo.srcObject = stream;localStream = stream;}function init() {navigator.mediaDevices.getUserMedia({audio: true,video: false}).then(gotStream).catch(e => alert(`getUserMedia() error: ${e.name}`));call();}function onIceCandidate(pc, event) {if (event.candidate) {send({type: 'canditate',data: event.candidate})}}function call() {pc1 = new RTCPeerConnection(iceServer);//获取本地网络信息,并发送给通信方 pc1.onicecandidate = e => onIceCandidate(pc1, e);// 有远程视频流时,显示远程视频流 // pc1.addEventListener('track', event => {//     console.log("BBBBBBBBBBBBBBBBBBBBBBBBB")//     console.log(event);//     console.log(localVideo.srcObject)//     console.log("BBBBBBBBBBBBBBBBBBBBBBBBB+")//     remoteVideo.srcObject = event.streams[0]//     remoteVideo.onloadedmetadata = function (e) {//         console.log("加载完毕")//         remoteVideo.play()//     }// })pc1.addEventListener('addstream', e => {// 将对方的视频流写入到video标签中remoteVideo.srcObject = e.stream})//本地视频流量,打开视频流navigator.mediaDevices.getUserMedia({audio: false,video: true}).then(stream => {// 将视频流写入到video标签中                localVideo.srcObject = stream;localStream = stream;stream.getTracks().forEach(track => {pc1.addTrack(track, stream)})pc1.createOffer().then(sdp => {pc1.setLocalDescription(sdp)send({type: 'offer',data: sdp})})})}function send(data) {data.toUserId = data.toUserId || toconsole.log({"name": "发送",data})socket.emit("exchange", JSON.stringify(data))}</script><style>#video {background-color: black;height: 30vh;}</style>
</body></html>

WebRTC学习(六)端对端传输_51CTO博客_webrtc学习

webRTC结合webSocket实时通信 - 掘金

4、关于 coturn 信令服务的安装,参考以下文档:coturn安装以及报错“coturn/src/apps/relay/netengine.c:316:对‘SSL_CTX_up_ref’未定义的引用“_coturn 启动报错_Mango酱的博客-CSDN博客

5、coturn 安装后的测试:Trickle ICE (webrtc.github.io)

6、代码中进行如下设置: 

  //该参数为了var iceServer = {// iceServers: [{//     urls: 'stun:stun.l.google.com:19302'// }]iceServers: [{urls: 'stun:stun.services.mozilla.com'},{urls: 'turn:ip:3478',credential: '密码',username: '账号'}]};

相关文章:

webRtc 示例

1、使用socket.io进行会话 2、为了方便&#xff0c;参数写死在前端了&#xff0c;前端界面1代码如下&#xff08;由界面1发起视频&#xff09;&#xff1a; <!DOCTYPE html> <html><head><title>Socket.IO chat</title><meta charset"…...

【RabbitMQ】服务启动成功,无法访问localhost:15672(RabbitMQ Management)

问题描述 RabbitMQ 服务已经启动成功&#xff0c;已经安装rabbitmq_management插件&#xff0c;无法访问RabbitMQ Management&#xff08;http://localhost:15672/&#xff09;。 原因分析 15672端口被Microsoft Edge占用。 解决方案 打开cmd终端&#xff0c;输入指令&#…...

【操作记录】pytorch_geometric安装方法

pytorch_geometric安装方法 github地址 主要不要直接pip install安装&#xff0c;会由于依赖无法安装而失败 点击here手动安装依赖 选择对应的pytorch版本&#xff0c;我的是Win10 Python3.8.3Pytorch1.8.1CUDA10.2 手动下载四个依赖包本地安装&#xff1a; 主要不要直接&am…...

EventSystem 事件系统

EventSystem 事件系统 事件系统在开发中必不可少事件系统使用观察者模式可以极大程度降低程序的耦合&#xff0c;之前的文章也讲过事件系统但是不够高效简洁&#xff0c;如何轻便高效优雅的实现一个事件呢&#xff1f;依然基于之前的AssemblyManager 程序集管理器和SingletonS…...

2.2 Vector<T> 动态数组(模板语法)

C数据结构与算法 目录 本文前驱课程 1 C自学精简教程 目录(必读) 2 动态数组 Vector&#xff08;难度1&#xff09; 其中&#xff0c;2 是 1 中的一个作业。2 中详细讲解了动态数组实现的基本原理。 本文目标 1 学会写基本的C类模板语法&#xff1b; 2 为以后熟练使用 S…...

dockerfile 例子(二)

Dockerfile由一行一行的命令语句组成&#xff0c;#开头的为注释行。Dockerfile文件内容分为四个部分&#xff1a;基础镜像信息、维护者信息、镜像操作指令以及容器启动执行指令。 接下来给大家列出Dockerfile中主要命令的说明。 FROM&#xff0c;指定所创建镜像的基础镜像。 …...

openssh---Windows下git安装配置gitlab

安装openssh 1. 专业版Win10/11默认自带&#xff0c;可以查看是否开启 1. Get-WindowsCapability -Online | Where-Object Name -like OpenSSH* 2. Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 3. Add-WindowsCapability -Online -Name OpenSSH.Serve…...

vscode宏键绑定

开发语言php 实现输入[ 得到 [];的效果 [win]ctrlp,[mac]superp 输入>keyboard 选择 在json文件里增加(目前有缺陷,sublime的设置是比较完美的.或者phpstorm默认不需要配置): {"key": "[","command": "editor.action.insertSnippet&…...

外贸企业如何借助CRM提升企业发展?

外贸企业竞争激烈&#xff0c;提高自身竞争力&#xff0c;扩大海外业务市场&#xff0c;是每个外贸企业的目标。为了实现这一目标&#xff0c;不少外贸企业借助CRM系统&#xff0c;优化业务流程&#xff0c;管理维护客户&#xff0c;从而实现可持续发展。那么&#xff0c;外贸企…...

初步了解ES

一、ES基础查询 1、es基础查询 1.1 准备数据 # 准备数据 PUT test_index/_doc/1 {"name":"顾老二","age":30,"from": "gu","desc": "皮肤黑、武器长、性格直","tags": ["黑", &…...

Linux基础(三)

一.系统基本优化 关闭selinux:getenforce 查看selinux状态setenforce 0 临时关闭vim /etc/sysconfig/selinux 永久关闭SELINUXdisabled 关闭防火墙&#xff1a;systemctl stop firewalld 临时关闭防火墙systemctl disable firewalld 永久关闭防火墙sys…...

python函数调用的四种方式

第一种&#xff1a;参数按顺序从第一个参数往后排#标准调用 def normal_invoke(x, y):print("--normal_invoke:--" )print("x is %d" %x )print("y is %d" %y) # 标准调用 normal_invoke(1, 2) 运行结果&#xff1a; --normal_invoke:-- x is 1 …...

如何将两个pdf合并成一个?pdf合并技巧分享

在日常工作过程当中&#xff0c;我们经常需要处理一些文件&#xff0c;而文件的处理往往是琐碎的&#xff0c;想要提高工作效率&#xff0c;需要选择一些合适的方法&#xff0c;并掌握一定的技巧&#xff0c;那么&#xff0c;如何将两个pdf合并成一个?pdf合并技巧有哪些呢?接…...

qt : day 3

1.完成登录框的按钮操作&#xff0c;并在登录成功后进行界面跳转 ------------------------------------------------------------------ .pro ------------------------------------------------------------------ QT core gui texttospeech greaterThan(QT_MAJOR_V…...

flutter高德地图大头针

1、效果图 2、pub get #地图定位 amap_flutter_map: ^3.0.0 amap_flutter_location: ^3.0.0 3、上代码 import dart:async; import dart:io;import package:amap_flutter_location/amap_flutter_location.dart; import package:amap_flutter_location/amap_location_option…...

【线性代数】矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇)

矩阵求导的本质与分子布局、分母布局的本质&#xff08;矩阵求导——本质篇&#xff09; 说在前面一. 函数与标量、向量、矩阵二. 矩阵求导的本质三. 矩阵求导结果的布局四. 分子布局、分母布局的本质五. 向量变元的实值标量函数 说在前面 我将严谨地说明矩阵求导的本质与分子布…...

快速了解状态管理库Pinia及其使用方法

目录 1.pinia是什么 2.为什么要使用pinia 3.pinia的优点 4.pinia在项目中使用 ①创建一个使用pinia的Vue3项目 ②在页面使用store 1.pinia是什么 Pinia 起源于一次探索 Vuex 下一个迭代的实验&#xff0c;如果你学过Vue2&#xff0c;那么你一定使用过Vuex。Vuex在Vue2中主…...

scratch绘制同心圆 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试四级真题和答案解析

目录 scratch绘制同心圆 一、题目要求 1、准备工作 2、功能实现 二、案例分析 <...

【LeetCode】3. 无重复字符的最长子串

3. 无重复字符的最长子串&#xff08;中等&#xff09; 方法&#xff1a;滑动窗口 哈希表 思路 这道题主要用到思路是&#xff1a;滑动窗口 什么是滑动窗口&#xff1f; 其实就是一个队列,比如例题中的 abcabcbb&#xff0c;进入这个队列&#xff08;窗口&#xff09;为 ab…...

苹果macOS 14开发者预览版Beta 7发布 新增超过100款视频壁纸和屏保

8 月 31 日&#xff0c;苹果向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 7 更新&#xff08;内部版本号&#xff1a;23A5337a&#xff09;&#xff0c;本次更新距离上次发布隔了 8 天。 苹果发布 Beta 7 更新的同时&#xff0c;还发布了第 6 个公测版&#xff0c;正式版…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...