janus的web端开发

janus Web


1. 在线demo

通过janus的源码的html文件以及相应的js文件我们可以参考官方的demo,在上文服务端的部署中最后我们可以进行在线使用。


2. 模块开发


只有demo肯定是不够的,而且使用的是jquerybootStrap,改起来也特别麻烦。

因此我们可以参考janus 的 jsAPI

将需要将功能抽离到vue中,这里因为我使用到的是videoroom,因此代码也是以videoroom为例。


2.1 安装依赖

首先我们需要安装janus需要的依赖

npm i janus-gatewaynpm i webrtc-adapter

2.2 初始化

<template><div><button @click="start">Start</button><button @click="stop">Stop</button><video id="myVideo" style="width: 1280px;height: 720px;border: 1px solid #ccc;margin-top: 10px;" /></div>
</template>
import Janus from 'janus-gateway';
import adapter from 'webrtc-adapter'const server = "ws://xx.xx.xx.xx:8188"; // 这个是上文部署的服务端的IP地址
const videoId = "myVideo"; // template中用来接收流的video标签的id
const janus = ref(null); // 保存janus实例
const pluginHandler = ref(null); // 保存插件句柄, 许多交互操作都需要这个变量来操作
const room = 1234; // 连接的房间id, 默认在后端没改动的情况下为 1234
const userId = ref(null); // 需要拉流的 发布者idconst start = () => {// 浏览器不支持webRTCif (!Janus.isWebrtcSupported()) {return;}// 初始化并指定配置项Janus.init({debug: true,dependencies: Janus.useDefaultDependencies({adapter}),callback: () => startJanus()})
}const startJanus = () => {// 将janus实例保存起来janus.value = new Janus({// 指定上述的janus服务器ip连接server: server,success: function () {attachToStreamingPlugin(janus.value);}});
}

2.3 连接会话

连接会话前需要打开服务端http-server发布的在线demo中的videoroom,加入并且开始推送,前端才能接收到流,否则videoroom里面是空的没有流,前端也就拉不到数据了。

const attachToStreamingPlugin = (janus) => {// 创建一个新的会话janus.attach({// 指定插件为videoroom, 需要使用streaming则进行切换, 插件不同代码也不同, 需要另外编写逻辑和处理回调。plugin: "janus.plugin.videoroom",// 指定房间号, 默认1234room,// 成功连接时的回调, 保存插件句柄, getParticipant获取房间内所有发布者的列表success: function (pluginHandle) {pluginHandler.value = pluginHandle;getParticipant()},// 接收到信息时的回调// 由于需要建立webrtc双向连接, 因此需要接收jsep信息并createAnswer回复本地描述来维持webrtc的连接// 具体逻辑在handleSDPonmessage: function (msg, jsep) {handleSDP(jsep);},// 接收到远程的流时的处理onremotetrack: function (stream) {handleStream(stream);},// 清除信息时回调oncleanup: function () {}});
}// 获取房间内所有发布者的列表
const getParticipant = () => {pluginHandler.value.send({message: {request: "listparticipants",room,audio: true,video: true,},success: function (response) {// 成功回调中可以获取所有房间内发布者的列表const participants = response["participants"];// 选择第一个用户开始订阅 可以添加业务逻辑拉第几个或多个const firstPart = participants[0]startStream(firstPart)},error: function (error) {}});
}

2.4 订阅发布者的流

const startStream = (selectedStream) => {// 获取到发布者的idvar selectedStreamId = selectedStream?.["id"];if (selectedStreamId === undefined || selectedStreamId === null) {return console.log("::: No selected stream :::");}// 将id存到userId中userId.value = selectedStreamId// 订阅流video和audiopluginHandler.value.send({message: {request: "join",feed: selectedStreamId,room: room,ptype: "subscriber",audio: true,video: true,}})
}const handleSDP = (jsep) => {if (jsep !== undefined && jsep !== null) {// 处理jsep信息并创建回复,成功回复之后通过keepRTC回调保持会话pluginHandler.value.createAnswer({// 将发送过来的jsep信息返回jsep,// 由于只发送jsep信息所以将audioSend和videoSend设置为false,不传输媒体流media: {audioSend: false, videoSend: false},// 成功后执行keepRTC并将sdp参数传入success: keepRTC,error: function (error) {console.error("::: WebRTC error :::" + JSON.stringify(error));}});}
}const keepRTC = (sdp) => {// 发送start请求保持连接pluginHandler.value.send({message: {request: "start"},jsep: sdp});
}

2.5 流的处理

const handleStream = (stream) => {// 接收到远程流之后新建一个媒体流 将远程流加入轨道const streamRemote = new MediaStream();streamRemote.addTrack(stream);const videoElement = document.getElementById(videoId);// 在video标签显示内容videoElement.srcObject = streamRemote;videoElement.oncanplay = () => {videoElement.play()};
}const stopStream = () => {pluginHandler.value.send({message: {request: "stop"}});pluginHandler.value.hangup();
}

完整示例代码(vue3)

<template><div><button @click="start">Start</button><button @click="stop">Stop</button><video id="myVideo" style="width: 1280px;height: 720px;border: 1px solid #ccc;margin-top: 10px;"></video></div>
</template><script setup>
import {ref} from 'vue'import Janus from 'janus-gateway';
import adapter from 'webrtc-adapter'const server = "ws://xxx.xx.xxx.xx:8188";
const videoId = "myVideo"; // 接收流的video标签的id
const janus = ref(null); // 保存janus实例
const pluginHandler = ref(null); // 保存插件句柄, 许多交互操作都需要这个变量来操作
const room = "1234"; // 连接的房间id, 默认在后端没改动的情况下为 1234
const userId = ref(null); // 需要拉流的发布者idconst start = () => {init()
}const stop = () => {stopStream()
}const init = () => {// 浏览器不支持webRTCif (!Janus.isWebrtcSupported()) {console.error("::: No webrtc support :::");return;}// 初始化并指定配置项Janus.init({debug: true,dependencies: Janus.useDefaultDependencies({adapter}),callback: () => startJanus()})
}const startJanus = () => {// 创建一个新的会话janus.value = new Janus({server: server,success: function () {attachToStreamingPlugin(janus.value);},error: function (error) {console.log("::: error :::", error);},destroyed: function () {console.log("::: destroyed :::");}});
}const attachToStreamingPlugin = (janus) => {janus.attach({plugin: "janus.plugin.videoroom",room,// 成功连接时的回调, 保存插件句柄, 获取房间内所有发布者的列表success: function (pluginHandle) {pluginHandler.value = pluginHandle;getParticipant()},/*接收到信息时的回调,由于需要建立webrtc双向连接, 因此需要接收jsep信息并createAnswer回复本地描述来维持webrtc的连接,具体逻辑在handleSDP。*/onmessage: function (msg, jsep) {console.log(" ::: message :::", JSON.stringify(msg));console.log(" ::: jsep :::", jsep);handleSDP(jsep);},// 接收到远程的流时的处理onremotetrack: function (stream) {console.log(" ::: remote stream :::", stream);handleStream(stream);},oncleanup: function () {console.log(" ::: cleanup notification :::");},error: function (error) {console.log("::: Error attaching plugin :::" + error);},});
}const getParticipant = () => {pluginHandler.value.send({message: {request: "listparticipants",room: +room,audio: true,video: true,},success: function (response) {// 成功回调中可以获取所有房间内发布者的列表const participants = response["participants"];// 选择第一个用户开始订阅 默认只有一个流const firstPart = participants[0]startStream(firstPart)},error: function (error) {console.error("::: Error getting participant list :::", error);}});
}const startStream = (selectedStream) => {// 获取到发布者的idvar selectedStreamId = selectedStream?.["id"];if (selectedStreamId === undefined || selectedStreamId === null) {return console.log("::: No selected stream :::");}userId.value = selectedStreamId// 订阅流video和audiopluginHandler.value.send({message: {request: "join",feed: selectedStreamId,room: +room,ptype: "subscriber",audio: true,video: true,}})
}const handleSDP = (jsep) => {if (jsep !== undefined && jsep !== null) {pluginHandler.value.createAnswer({jsep,media: {audioSend: false, videoSend: false},success: keepRTC,error: function (error) {console.error("::: WebRTC error :::" + JSON.stringify(error));}});}
}const keepRTC = (sdp) => {console.log("::: sdp :::", sdp);pluginHandler.value.send({message: {request: "start"},jsep: sdp});
}const handleStream = (stream) => {const streamRemote = new MediaStream();streamRemote.addTrack(stream);const videoElement = document.getElementById(videoId);videoElement.srcObject = streamRemote;videoElement.oncanplay = () => {videoElement.play()};
}const stopStream = () => {pluginHandler.value.send({message: {request: "stop"}});pluginHandler.value.hangup();
}
</script>

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

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

相关文章

3d软件动物生活习性仿真互动教学有哪些优势

软体动物是一类广泛存在于海洋和淡水环境中的生物&#xff0c;其独特的形态和生活习性给学生带来了新奇和有趣的学习主题&#xff0c;为了方便相关专业学科日常授课教学&#xff0c;web3d开发公司深圳华锐视点基于真实的软体动物&#xff0c;制作软体动物3D虚拟展示系统&#x…

CMake 学习笔记 (Generator Expressions)

CMake 学习笔记 &#xff08;Generator Expressions&#xff09; Generator Expressions 可以认为是一种特殊的变量&#xff0c;它会在编译阶段求值。通常用在 target_link_libraries(), target_include_directories(), target_compile_definitions() 上。 用 Generator Expr…

【visual studio2019】如何打开即时窗口

在 Visual Studio2019 中打开即时窗口&#xff0c;有两种方法&#xff1a; 1、可以通过“调试”菜单&#xff0c;然后选择“窗口”下的“即时窗口”选项 2、直接使用快捷键“Ctrl Alt I” 此时即时窗口将显示在 Visual Studio2019 的底部。在即时窗口中&#xff0c;可以执…

oracle环境变量

查看oracle环境变量 env |grep ORA [oracleizhp3b679b0ht5m1rzqhubz tomcat]$ env |grep ORA ORACLE_SIDorcl ORACLE_BASE/u01/app/oracle ORACLE_HOME/u01/app/oracle/product/12/db_1重新 登陆刷新环境变量配置 source ~/.bash_profile 登陆oracle cd /u01/app/oracle/p…

Java读取及生成pb文件并转换jsonString

Java读取及生成pb文件并转换jsonString 1. 效果图2. 原理2.1 Protocol Buffers是什么2.2 支持的语言2.3 根据.proto生成.java2.4 初始化及构建pb&#xff0c;读取&#xff0c;转jsonString 3. 源码3.1 address.proto3.2 PbParseUtil.java 参考 读取pb及生成pb文件pb文件转换jso…

stable diffusion

一&#xff1a;安装。 stable diffusion 安装和使用全教程 - 知乎 Stable Diffusion安装 - 知乎 环境安装&#xff1a; 1&#xff1a;python 3.10安装。 Download Python | Python.org 切记要安装3.10版本&#xff0c;因为Stable diffusion是用3.10版本编写的&#xff0c;所…

【C++】 哈希

一、哈希的概念及其性质 1.哈希概念 在顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经过关键码的多次比较。比如顺序表需要从第一个元素依次向后进行查找&#xff0c;顺序查找时间复杂度为…

VS Code环境配置问题

VS Code 环境配置问题 文章目录 VS Code 环境配置问题配置 C问题解决不乱码只显示结果避免闪退&#xff0c;中文乱码 配置 Java下载 JDKJDK 环境配置安装插件 配置 C 跟着官网教程&#xff08;英文版&#xff09;和其他博客配置了一遍&#xff0c;却遇到了很多小问题&#xff…

MyBatis源码剖析之延迟加载源码细节

文章目录 什么是延迟加载&#xff1f;实现局部延迟加载全局延迟加载 延迟加载原理实现延迟加载原理&#xff08;源码剖析)Setting 配置加载&#xff1a;延迟加载代理对象创建注意事项 什么是延迟加载&#xff1f; 在开发过程中很多时候我们并不需要总是在加载⽤户信息时就⼀定…

Android 开发代码规范

一. AndroidStudio开发工具规范 使用最新的稳定版本.统一文件的编码格式为utf-8. 清除每个类里面的无效的import导包.代码样式统一,比如&#xff0c;tab缩进4个空格&#xff0c;或者 tab size等如果没有特殊情况使用默认的配置即可。每行字数每行字符数不得超过 160 字符&…

【100天精通python】Day20:文件及目录操作_os模块和os.psth模块,文件权限修改

目录 专栏导读 1 文件的目录操作 os模块的一些操作目录函数​编辑 os.path 模块的操作目录函数 2 相对路径和绝对路径 3 路径拼接 4 判断目录是否存在 5 创建目录、删除目录、遍历目录 专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/qq_35831906/category_12…

Mysql-MVCC 并发版本控制

参考链接&#xff1a;一文读懂MVCC实现原理_Nicolos_Z的博客-CSDN博客 1.总述&#xff1a; MVCC 主要是InnoDB解决数据库事务读写&#xff0c;导致的脏读、重复读问题的处理方法。通过快照读的方式&#xff0c;提高数据库并发查询的能力。 2.MVCC的实现 实现MVCC主要用到了…

在OK3588板卡上部署模型实现人工智能OCR应用

一、主机模型转换 我们依旧采用FastDeploy来部署应用深度学习模型到OK3588板卡上 进入主机Ubuntu的虚拟环境 conda activate ok3588 安装rknn-toolkit2&#xff08;该工具不能在OK3588板卡上完成模型转换&#xff09; git clone https://github.com/rockchip-linux/rknn-to…

金蝶云星空任意文件读取漏洞复现(0day)

0x01 产品简介 金蝶云星空是一款云端企业资源管理&#xff08;ERP&#xff09;软件&#xff0c;为企业提供财务管理、供应链管理以及业务流程管理等一体化解决方案。金蝶云星空聚焦多组织&#xff0c;多利润中心的大中型企业&#xff0c;以 “开放、标准、社交”三大特性为数字…

ChatGPT伦理挑战:人工智能的权利与责任

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Android 首次开机优化分析工具bootchart

Android开机时长优化_android 开机时间优化_Mart!nHu的博客-CSDN博客 bootchart使用_bootchart.jar_xuyewen288的博客-CSDN博客 bootchart_hc-斌斌的博客-CSDN博客 性能分析工具 — bootchart 工具使用(android 8.1)_岁月斑驳7的博客-CSDN博客 linux-用户进程时间统计_pybo…

HCIP期中实验

考试需求 1 、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2 、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3 、整张拓扑均使用私网地址进行配置。 4 、整张网络中&#xff0c;运行 OSPF 协议…

除......之外,不等于

查找除复旦大学的用户信息_牛客题霸_牛客网 3种方法 1. <> select device_id,gender,age,university from user_profile where university <> 复旦大学; 2. !&#xff08;其实是<>不等于的另外一种写法&#xff09; select device_id,gender,age,univ…

实时协作:团队效率倍增的关键

实时协作是指团队在当前时刻共同完成项目的能力。无论是否使用技术&#xff0c;都能实现这一点。然而&#xff0c;随着远程工作的盛行&#xff0c;安全的协作工具被用来让团队成员在项目和一般业务之间保持联系和同步。 传统协作与实时协作的区别 两种类型的协作最明显的区别…

uniapp 微信小程序 navigationBarBackgroundColor 标题栏颜色渐变

大体思路&#xff1a; 第一步&#xff1a;“navigationStyle”:“custom” 第二步&#xff1a; template内 重点&#xff1a;给view添加ref“top” 第三步&#xff1a;添加渐变色样式 1、pages.json {"path" : "pages/user/user","style" : …