目录
前言
作为“全干工程师”,前段时间刚开发完小游戏,最近又当起了音视频开发工程师,最近因为公司里的项目,甲方需求需要支持播放rtsp矿山监控视频,但是因为rtsp不能支持在浏览器直接播放。接下来有两种方案,第一个是在服务端用ffmpeg转码成flv再在前端使用flv.js进行播放,也就是我们之前使用的方案,但是延迟大,容易卡顿不稳定。第二种方案是用webRTC方案,延迟低,性能好,实时性高。就选择了webRTC,但是大多数网上的教程大多数有头无尾,都只是介绍了怎么搭建webRTC,其实都只能在内网播放,最重要的coturn服务器搭建都没有说,实际有很多坑,今天这篇文章就教大家怎么从入门到应用WebRTC,先会跟大家介绍怎么搭建webRTC,接下来会介绍怎么搭建路由器内网映射,最后会给大家介绍怎么在windows上搭建coturn服务器(虽然官网说只支持Linux但还是有办法)。
WebRTC-Streamer
首先我的服务器系统环境是windows,在webRTC技术选型上我选择了WebRTC-Streamer,比较方便好用。这个是github地址,然后去这里下载最新版release包,下载完成以后,使用powershell,进入命令行,进入webrtc-streamer安装目录下,简单执行一下./webrtc-streamer -C config.json -o测试,此时就可以在浏览器的http://127.0.0.1:8000看到一些视频了,这里介绍一下webRTC-streamer的所有启动参数
./webrtc-streamer -V
-v[v[v]] : verbosity
-V : 打印版本
-H [hostname:]port : HTTPServer绑定 (default 0.0.0.0:8000)
-w webroot : 获取文件的路径
-c sslkeycert : HTTPS的私钥和证书路径
-N nbthreads : HTTP服务器的线程数
-A passwd : 用于HTTP服务器访问的密码文件
-D authDomain : HTTP服务器访问的身份验证域(默认值:mydomain.com)
-S[stun_address] : 使用嵌入的STUN服务器绑定到地址(默认值为0.0.0.0:3478)
-s[stun_address] : 使用外部的STUN服务器绑定到地址(默认值为0.0.0.0:3478)
-t[username:password@]turn_address : 使用外部TURN中继服务器(默认:禁用)
-T[username:password@]turn_address : 使用嵌入式TURN中继服务器(默认:禁用)
-a[audio layer] : 指定要使用的音频捕获层(默认值:0)
-q[filter] : 指定发布筛选器(默认值:.*)
-o : 使用空编解码器(保持帧编码)
-C config.json : 从JSON配置文件加载URL
-R [Udp port range min:max] : 设置webrtc-udp端口范围(默认值为0:65535)
-n name -u videourl -U audiourl : 注册视频url和音频url的名称
[url] : 要在源列表中注册的url
细节注意
这里最好带上 -o 否则cpu会受到影响,如果需要改成其他端口号可以用 -H 参数进行指定,毕竟8000端口比较常用。后面还有-S和-T参数是后面会用到的,可以接入使用STUN服务器和TURN服务器,后面会讲。
端口映射
经过前面那些步骤,本地已经可以播放视频了,但是别人看不到,这个时候就需要进行端口映射,利用路由器的虚拟服务器功能,我这里是用的TP-LINK的路由器,在传输控制-NAT设置-虚拟服务器下,新增一条记录webrtc,输入外部端口和内部端口,内部服务器IP是你的服务器下ipconfig里的ipv4地址。这里我们再新增一个turn服务器的端口映射后面用得到,端口都选3478,服务器协议一定要选ALL因为要同时支持UDP和TCP,截图如下:
- webrtc端口映射配置:
- turn服务器端口映射配置:
内网测试播放
前面就已经搭建好你的webrtc服务器了,此时,你应该可以在内网同一网段下看到公网ip:公网端口(你的公网ip可以用这个工具查看)下的webrtc-streamer首页了,这里有一些config文件里的示例的rtsp,多选择一些,总有一些可以播放的,可以用来判断服务是否正常。
前端代码
如果你可以在浏览器里成功看到webrtc的视频,那么可以继续写前端代码,这里我用的是vue框架,废话不多说,show me the code.
<template>
<a-modal
title="webRTC视频监控(H.264专线)"
:width="1100"
:visible="visible"
cancelText="关闭"
@cancel="handleCancel"
:confirmLoading="confirmLoading"
@ok="handleCancel"
>
<div class="wrap">
<div v-for="(_value, _key, index) in lines" :key="index">
<video ref="player" muted autoplay controls width="1000"></video>
</div>
</div>
</a-modal>
</template>
<script>
import { MONITOR_WEBRTC_SERVER_URL, VIDEO_TYPE_ENUM } from '@/constants'
import '@/utils/webrtc/adapter.min.js'
import WebRtcStreamer from '@/utils/webrtc/webrtcstreamer'
import webrtcConfig from '@/utils/webrtc/webrtcconfig'
import isSupportsWebRTC from '@/utils/webrtc/isSupportsWebRTC'
export default {
name: 'VideoMonitor',
data() {
return {
players: [],
lines: [],
webRtcServerList: [],
}
},
props: {
// 控制显隐
visible: {
type: Boolean,
default: false,
required: true,
},
// 行数据
resData: {
type: Object,
default: () => {},
required: false,
},
// url
url: {
type: String,
default: '',
required: false,
},
customOptions: {
type: Object,
default: () => {},
required: false,
},
},
created() {
this.handleCreateVideo()
},
watch: {
visible(val) {
if (val) {
this.handleCreateVideo()
} else {
// 页面销毁前解绑 webRtcServer
this.handleReset()
}
},
},
beforeDestroy() {
this.handleReset()
},
methods: {
handleReset() {
for (let i = 0; i < this.webRtcServerList.length; i++) {
const webRtcServer = this.webRtcServerList[i]
if (!webRtcServer) return
webRtcServer.disconnect()
}
this.webRtcServerList = []
this.lines = []
},
handleCancel() {
this.$emit('cancel')
this.handleReset()
},
handleCreateVideo() {
let options = webrtcConfig.options
// 判断浏览器是否支持 webRTC 直播视频
if (!isSupportsWebRTC()) {
this.$message.error('当前浏览器不支持 WebRTC 无法播放直播视频!')
this.handleCancel()
return
}
const { videoType, title } = this.customOptions
const lines = title.split(',')
const serverUrl = MONITOR_WEBRTC_SERVER_URL
// 过滤重复的 createVideo
if (this.lines.length >= lines.length) {
return
}
for (let i = 0; i < lines.length; i++) {
const channel = lines[i]
let url = this.url
switch (videoType) {
case VIDEO_TYPE_ENUM.默认:
// 默认大华的监控地址
url = this.url.replace('?', `?channel=${channel}&`)
break
// 海康视频可以直接连线路101,201,01是主码流
case VIDEO_TYPE_ENUM.海康:
url = this.url.endsWith('/') ? this.url + channel + '01' : this.url + `/${channel}01`
break
// 天翼云 url 不需要处理
default:
break
}
this.lines.push(url)
setTimeout(() => {
var videoElement = this.$refs.player[i]
const webRtcServer = new WebRtcStreamer(videoElement, serverUrl)
webRtcServer.connect(url, '', options)
this.webRtcServerList.push(webRtcServer)
})
}
},
},
}
</script>
<style lang="css" scoped>
.wrap {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.wrap .video {
width: 1000px;
max-height: 800px;
}
</style>
// isSupportsWebRTC.js
// 用于判断浏览器是否支持 WebRTC
export default () => {
try {
let testRTCPeerConnection =
window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.RTCIceGatherer
if (testRTCPeerConnection) {
let serverConfig = {
iceServers: [
{
urls: ['stun:stun.l.google.com:19302'], // 这里的stun地址可以换成自己的
},
],
}
new RTCPeerConnection(serverConfig)
return true
} else {
throw '当前浏览器不支持 WebRTC 无法播放直播视频!'
}
} catch (error) {
console.error('当前浏览器不支持 WebRTC 无法播放直播视频!')
return false
}
}
这里我的 customOptions 是由外部传参传入的,videoType是视频监控类型,title是所有线路的字符串,用逗号连接,比如1,2,3就是表示监控线路1,2,3。其他的代码需要根据自己需要调整。包括不同的厂商提供的摄像机rtsp地址。WebRtcStreamer.js,adapter.min.js,webrtcconfig.js文件都是从webRTC-streamer的Release文件包下html目录下获取。这里后面还有个坑,后面会说。
Coturn服务器
Cygwin64安装
这个时候如果你只是内网访问就已经没有问题了,但是我们需要外网也可以访问,webRTC-streamer这东西,主要是他有个问题,所有的中间NAT映射都会让他迷路,所以需要用stun服务器去拿到公网ip,turn服务器进行穿透中继,之前部署到k8s集群看不到视频就是因为没有部署这个,不过我们现在是windows,还需要一个所以我们需要再部署一个coturn服务器来中继到外网,但是coturn服务器在windows系统上需要借助Cygwin64工具才可以运行,主要提供linux里的那些库函数和方法。在这里Cygwin官网安装地址安装好cygwin64,安装教程如下:
1.打开安装软件setup.exe
2.选择下载源,从互联网安装
3.选择安装目录
4.选择本地软件包目录,不用动就可以
5.选择互联网连接,我这里选择直连,如果有梯子可以选系统代理设置
6.选择下载站点地址,我这里选择163的,也可以选择淘宝的
7.选择需要的安装包,这里我已经下载过了,下面这些是必要的包,可以搜索安装上,主要是这几个gambas3-gb-openssl,gcc-core,gcc-g++,libevent-devel,libssl-devel,make
8.下一页进行安装,安装完成选择添加快捷方式到桌面
接下来就可以点击cygwin快捷方式打开,在这里就可以执行gcc,make那些linux命令了。
运行coturn
然后下载coturn源码,下载完成解压,在cygwin命令行里cd到coturn目录,执行:
1.生成Makefile文件:
CC=gcc ./configure
如果出现 Makefile created: success. 就没有问题
2.编译make:
make
3.安装依赖:
make install
安装完成,如果前面是成功的,进入bin目录下就可以看到 turnserver.exe 还有其他可执行exe文件,但是我们还少了一些文件,签名证书和turnserver.config.
4.签名证书
签名证书可以自己在cygwin命令行里生成一下,刚刚下载了openssl就可以用上了
openssl req -x509 -newkey rsa:2048 -keyout ./turn_server_pkey.pem -out ./turn_server_cert.pem -days 99999 -nodes
这样就会在当前目录下生成两个pem文件,可以选择把他们新建个pem文件夹拖进去
5.配置 turnserver.config
新建一个turnserver.config文件,里面输入以下config内容,记得verbose不要大写,否则就会一直报错timeout,参数具体解释在这里
listening-ip=192.168.1.113
listening-port=3478
tls-listening-port=5349
relay-ip=192.168.1.113
external-ip=xxx(公网ip)
relay-threads=50
lt-cred-mech
cert=pem/turn_server_cert.pem
pkey=pem/turn_server_pkey.pem
pidfile=turnserver.pid
min-port=49152
max-port=65535
user=admin:123456
cli-password=123456
realm=my-domain-name
verbose
fingerprint
syslog
6.执行以下代码,-r后面可以随意接其他字符,-o是后台运行,因为是webRTC所以需要接-a参数
./turnserver -a -f -user=admin:123456 -c ./turnserver.conf -r hangzhou -o
7.这个时候可以执行以下指令看下是否正在运行,3478是上面设定的turn/stun服务监听端口也是默认的端口
netstat -ano|findstr 3478
8.如果需要关掉的可以执行以下指令,PID是上个命令里的线程id
taskkill /f /t /PID 22432
如果没有问题的话到这里就外网就应该可以接收到webRTC视频了。但是可能还有个注意点,就是客户端的代码里没有申明turn和stun服务器的ip和账号密码导致请求都没有到我们的turn服务器。具体的解决方法可以看我的issue。