webrtc在视频通话过程中如何实时录制通话视频?

前言

在上一篇文章中初步介绍了如何利用webrtc简化和增强webrtc直连过程中遇到的繁琐和瓶颈问题,以及简单的实现网络视频通话的小教程,本篇文章将介绍如何在上述视频通话过程中实时录制通话数据.

准备基础的通话demo,开始录制教程

本次的demo以上次使用的demo为主,增加录制功能

初始化录制和回放janus插件

插件名称 janus.plugin.recordplay
that.$store.state.recordPlay为初始化插件后获取的全局handle,所有关于录制的句柄都要用这个.

 // 初始化视频录制回放handle
initRecordPlay(){
  const that = this;
  janus.attach({
		  plugin: "janus.plugin.recordplay",
		  success: function(pluginHandle) {
			that.$store.commit("setRecordPlay",pluginHandle)
			  Janus.log("Plugin attached! (" + pluginHandle.getPlugin() + ", id=" + pluginHandle.getId() + ")");
		  },
		  error: function(cause) {
			   Janus.error("  -- Error attaching recordplay plugin...", error);
		  },
		  
		  onmessage: function(msg, jsep) {
		   Janus.debug(" ::: Got a message :::", msg);
		   var result = msg["result"];
		   if(result) {
				if(result["status"]){
					var event = result["status"];
					if(event === 'preparing' || event === 'refreshing') {
					Janus.log("Preparing the recording playout");
					that.$store.state.recordPlay.createAnswer(
						{
							jsep: jsep,
							media: { 
								video:false,
								audio:false,
								data:true
								},
							success: function(jsep) {
								var body = { request: "start" };
								that.$store.state.recordPlay.send({ message: body, jsep: jsep });
							},
							error: function(error) {
								Janus.error("WebRTC error:", error);
							}
						});
					if(result["warning"]){
						console.log()
					}
				} else if(event === 'recording') {
					if(jsep)
						that.$store.state.recordPlay.handleRemoteJsep({ jsep: jsep });
						var id = result["id"];
					if(id) {
						Janus.log("The ID of the current recording is " + id);
						
					}
				} else if(event === 'playing') {
					Janus.log("Playout has started!");
				} else if(event === 'stopped') {
					Janus.log("Session has stopped!");
				}
			  }
			}
		  },
		  
		  onlocalstream:function(stream){
			  console.log("本地视频")
		  },
		  onremotestream: function(stream) {
			console.log("远程视频")
			that.setTargetMedia(stream,'recordPlay')// 监听到视频源将其输出到指定的video标签
			Janus.debug(" ::: Got a remote stream :::", stream);
		  },
		 
  });
		
},

开始录制

利用上面初始化号的全局录制句柄that.$store.state.recordPlay向janus发送具体的指令,开始录制.

recordvideo(){
			const that = this;
			if(!this.username){
				this.$message.error("用户名不能为空")
				return
			}
			that.$store.state.recordPlay.createOffer({
				success: function(jsep) {
					console.log("Got SDP!", jsep);
					var body = { request: "record", name: getNowStrTime(new Date())+"-"+that.username };
					that.$store.state.recordPlay.send({ message: body, jsep: jsep });
				},
				error: function(error) {
					that.$store.state.recordPlay.hangup();
				}
			});
			
		},

结束录制

本质上就是挂断录制的那个句柄

stoprecordvideo(){
	this.$store.state.recordPlay.hangup();
  },

获取录制的视频

这个list指令会返回录制的视频集合,后续可以根据具体每个视频的ID去播放视频

loadAllvideos(){
		const that = this;
		var body = { request: "list" };
		this.$store.state.recordPlay.send({ message: body,success:function(res){
			console.log("videos:",res)
			
		}})
	},

输出结果

以上就是获取到刚才录制的基础信息,字段name是录制的时候发送的参数var body = { request: "record", name: getNowStrTime(new Date())+"-"+that.username };这边定义的,时间和登录用户

播放录制的内容

根据上面获取到的录制信息集合中的id字段,通过录制句柄发送播放指令即可

playvideo(row){
   // row.id 即为上述获取到的集合中每个具体项的ID
	var body = { request: "play",id:row.id };
	this.$store.state.recordPlay.send({ message: body})
		},

这里发送play指令后,句柄会根据这个做出响应,具体可以看到初始化插件中onmessage监听中的信息,当然下面的在初始化插件的时候已经写好了.

onmessage: function(msg, jsep) {
   Janus.debug(" ::: Got a message :::", msg);
   var result = msg["result"];
   if(result) {
		if(result["status"]){
			var event = result["status"];
			if(event === 'preparing' || event === 'refreshing') {
			Janus.log("Preparing the recording playout");
			that.$store.state.recordPlay.createAnswer(
				{
					jsep: jsep,
					media: { 
						video:false,
						audio:false,
						data:true
						},
					success: function(jsep) {
						Janus.debug("Got SDP!", jsep);
						var body = { request: "start" };
						that.$store.state.recordPlay.send({ message: body, jsep: jsep });
					},
					error: function(error) {
						Janus.error("WebRTC error:", error);
					}
				});
			if(result["warning"]){
				console.log()
			}
		} else if(event === 'recording') {
			// Got an ANSWER to our recording OFFER
			if(jsep)
				that.$store.state.recordPlay.handleRemoteJsep({ jsep: jsep });
				var id = result["id"];
			if(id) {
				Janus.log("The ID of the current recording is " + id);
				
			}
		} else if(event === 'playing') {
			Janus.log("Playout has started!");
		} else if(event === 'stopped') {
			Janus.log("Session has stopped!");
		}
	  }
	}
  },

结束播放

stopplayvideo(row){
       //这里的id和上面播放的ID一样,
	var body = { request: "stop",id:row.id };
	this.$store.state.recordPlay.send({ message: body})
},

如何下载录制的视频

janus本身的录制信息

janus录制的视频格式并不直接是mp4格式,而是针对每个视频有三个文件

janus录制完成后的文件

.nfo 内容是上面获取录制信息的时候获取到的每个视频文件的基本信息,比如视频名称和视频文件,音频文件

[2464070935677548]
name = 2021-08-15-19-22-19-aaa
date = 2021-08-15 11:22:20
audio = rec-2464070935677548-audio.mjr
video = rec-2464070935677548-video.mjr

如何转换到mp4

janus虽然直接保存的上面的非mp4格式,但是也同样提供了转换成mp4格式的插件,下面我将如何使用插件的方法写在下面的脚本里.
本质就是将对应的 .mjr文件转换成基本的视频(.webm)和音频文件(.opus),然后再利用 ffmpeg合并视频和音频源,输出mp4,大体脚本如下,如果想要完整脚本的话可以留言联系我.

tmp_video=./tmp/mjr-$RANDOM.webm

tmp_audio=./tmp/mjr-$RANDOM.opus

januspprec_dir=/usr/local/bin/

$januspprec_dir/janus-pp-rec ./rec-2464070935677548-audio.mjr $tmp_video

$januspprec_dir/janus-pp-rec ./rec-2464070935677548-video.mjr $tmp_audio
-----------------------

ffmpeg -i $tmp_audio -i $tmp_video  -c:v copy -c:a opus -strict experimental 2464070935677548-aaa.mp4

最后往期推荐