企业级音视频会议实战之webrtc服务器janus品尝实战

2,158 阅读3分钟

前言

之前写过单纯用webrtc和springboot实现单人,多人,屏幕分享等功能的一系列文章了,心疼各位giegie,已将例子放在下面,不麻烦你们去找了

单纯使用webrtc的缺点

  • 维护连接关系上,无法统计也无法集中统一管理客户端(尤其系统中出现多对的p2p);
  • 在通信过程中获取媒体传输的实时码率,也无法对正在传输中的媒体流做出中间过滤,涉及到录制等操作时就没法玩了;
  • 每次建立通信,代码虽然很容易写出来,但是需要很繁琐;
  • 统一的日志记录;

janus演示图

使用webrtc服务器之后(这里以janus为例)

  • 回声测试、会议桥、媒体记录器、SIP 网关等基本功能
  • 可插拔的,按需引入所需的功能,比如会议功能,p2p通信功能,录制功能,播放第三方媒体流rtmp,屏幕共享等每个小功能可单独引入,只需要引入对应的插件即可
  • 自带用户统计,只需要按照特定的格式去请求即可,相当于给你提供了websockte服务器,你只需要按照规范来就完事了
  • 使用json作为向服务器请求服务的参数,简洁
  • 接入成本及其低

janus服务器搭建教程

  • 在已经安装了docker的服务器上,创建docker-compose.yml,内容如下

注意:下面有几个文件需要手动去添加janus.jcfgjanus.eventhandler.sampleevh.jcfg相当于俩插件配置,这里面需要更改一些东西,所以直接挂载到宿主机即可,文件内容在https://github.com/meetecho/janus-gateway/tree/master/conf,找到同名字的(不用考虑文件后缀.sample,仅看前半部分即可)复制内容到本地创建的那俩文件里即可 同时要注意看下面挂载的路径,换成自己想换的目录即可

version: '2.1'
services:
  #
  # janus-gateway
  #
  janus-gateway:
    image: 'sucwangsr/janus-webrtc-gateway-docker:20220407'
    command: ["/usr/local/bin/janus", "-F", "/usr/local/etc/janus"]
    network_mode: "host"
    volumes:
#- "./etc/janus/janus.transport.http.jcfg:/usr/local/etc/janus/janus.transport.http.jcfg"  # 打开adminapi的时候设
      - "./etc/janus/janus.jcfg:/usr/local/etc/janus/janus.jcfg"
      - "./etc/janus/janus.eventhandler.sampleevh.jcfg:/usr/local/etc/janus/janus.eventhandler.sampleevh.jcfg"
    restart: always
  • 更改重要配置参数

修改janus.jcfg文件,找到下面几个参数

api_secret = "sukejanxxusrocks"  ## 客户端使用restApi用的token
token_auth_secret = "sukexjanus" ## 使用ws使用的token
token_auth = true  ## 使用开启校验ws
admin_secret = "suaanusoverlord"  #管理员
  • 启动和日志查看
docker-compose up -d
docker-compse logs ## 查看日志

web端vue项目中初始化和使用

  • 官网git下载最新的js复制到本地文件,最后一行加入 export default Janus

下载地址:https://github.com/meetecho/janus-gateway/blob/master/html/janus.js

  • APP.vue引入
import adapter from 'webrtc-adapter'; //本地安装
import Janus from "./assets/janus/janus.js";

Janus.init({
	debug: true,
	dependencies: Janus.useDefaultDependencies({
	  adapter: adapter
	}),
	callback: ()=> {
	  if(!Janus.isWebrtcSupported()) {
		console.log('not Supported Webrtc!');
		return;
	  }
	}
});
var janus = new Janus(
        {
			server: 'http://192.168.1.12/janus',
			apisecret:'apisecret',//这个密钥就是前面服务器搭建时配置的api_secret
			success: function() {
					// Done! attach to plugin XYZ
					console.log("done")
			},
			error: function(cause) {
					// Error, can't go on...
					console.log(cause)
			},
			destroyed: function() {
					// I should get rid of this
					console.log("destroyed")
			}
        });

初始化成功则会打印如下

Initializing library
janus.js?6559:450 Library initialized: true
janus.js?6559:473 Using REST API to contact Janus: http://192.168.1.12:8088/janus

使用janus实现人员注册视频通话

前面基础的环境已经准备就绪,接下来就是加载janus.plugin.videocall插件,实现视频通话,插件相关文档https://janus.conf.meetecho.com/docs/pages.html

  • 用初始化好的janus全局变量加载上面的插件
janus.attach(
{
		plugin: "janus.plugin.videocall",
		opaqueId: opaqueId,//随机变量即可
		success: function(pluginHandle) {
			// 这个变量一定要记住了pluginHandle,后续的操作都需要这个变量来操作
				Janus.log("Plugin attached! (" + pluginHandle.getPlugin() + ", id=" + pluginHandle.getId() + ")");
				// that.$store.commit("setVideoCallPluginHandle",pluginHandle)
		},
		error: function(cause) {
				console.log("videocall error cause",cause)
		},
		onmessage: function(msg, jsep) {
			// 所有相关操作的响应都会在这里出来(比如下面的用户注册成功失败响应)
				console.log("videocall onmessage",msg,jsep);
				
		},
		iceState: function(state) {
			Janus.log("ICE state changed to " + state);
		},
		mediaState: function(medium, on) {
			Janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium);
		},
		webrtcState: function(on) {
			Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
		},
		onlocalstream: function(stream){
			// 本地媒体流监听获取
			// that.setTargetMedia(stream,'local')
			console.log("localstream",stream)
		},
		onremotestream: function(stream) {
			//远程通话时远端媒体流监听
			//在这里可以通过前面全局变量pluginHandle.getBitrate获取实时通话的比特率
			console.log("remotestream",stream)
		},
		ondataopen: function(data) {
			Janus.log("The DataChannel is available!",data);
			
		},
		ondata: function(data) {
			Janus.debug("We got data from the DataChannel!", data);
		},
		oncleanup: function() {
			// PeerConnection with the plugin closed, clean the UI
			// The plugin handle is still valid so we can create a new one
	}
	  
});

加载成功后,控制台会打印如下类似的内容

Created session: 8531598282085770
janus.js?6559:1280 Created handle: 7328474459571692
App.vue?234e:67 Plugin attached! (janus.plugin.videocall, id=7328474459571692)

注:前面加载插件成功之后会有一个很重要的变量pluginHandle,后续对视频通话的所有操作都是基于这个handle的

  • 向janus注册通话用户(callhandler 就是上述初始化后的handle)

下面注册的参数都是janus规范好的,username传自己的参数即可

var register = { request: "register", username: this.loginInfo.username };
callhandler.send({ message: register });

注册成功,则会在前面onmessage监听到下面打印的内容,重复注册的为第二条都会有对应提示Already registered (zhangsan)"

在两个页面分别注册,也就是注册两个用户

  • 发起视频通话
const that = this;
//创建offer 这个基本流程和普通建立rtc连接的流程一样的,不懂的直接回到前面看看我之前不用janus服务器的纯webrtc实现
callhandler.createOffer(
{
	media: { 
		audio:true,
		video: { width: 1920, height: 1080 }
		// video:"lowres"/"lowres-16:9"/"stdres"/"stdres-16:9"/"hires"/"hires-16:9",
		},
	iceRestart: true,
	success: function(jsep) {
		Janus.debug("Got SDP!", jsep);
		var body = { request: "call", username: 'lisi' };
		callhandler.send({ message: body, jsep: jsep });
	},
	error: function(error) {
		Janus.error("WebRTC error...", error);
	}
});

这边创建offer后呼叫另一个注册用户lisi,在lisi的那边onmessage监听方法下面,就会监听到呼叫,之后创建应答

//监听到呼入事件(janus自带的规范好的事件名称)
if(event === 'incomingcall') {
	Janus.log("Incoming call from " + result["username"] + "!");
	that.$store.state.videoCall.createAnswer(
		{
			jsep: jsep,
			media: {
				audio:true,
				video: { width: 1920, height: 1080 }
				},	
			success: function(jsep) {
				Janus.debug("Got SDP!", jsep);
				var body = { request: "accept" };
                                //向呼叫者发送accept事件
				that.$store.state.videoCall.send({ message: body, jsep: jsep });
			},
			error: function(error) {
				Janus.error("WebRTC error:", error);
			}
		});
}
----------------呼叫者监听到accepted事件-------------------------
if(event === 'accepted') {
	var peer = result["username"];
	if(!peer) {
		Janus.log("Call started!");
	} else {
		Janus.log(peer + " accepted the call!");
	}
	// Video call can start
	if(jsep)
		that.$store.state.videoCall.handleRemoteJsep({ jsep: jsep });

}

以上基本整个流程完毕,就可以进行视频通话了

最后

有什么问题请留言哦