AppRTC(WebRTC)服务器搭建

前言

最近研究了几天 appr.tc 服务器的搭建,主要目的是想在本地搭建一套 webrtc 服务器环境,可以做一些webrtc相关的实验。

经过几天的折腾,得到以下几点结论:
一、最新的 appr.tc服务器是不能使用 https服务的。主要有两种原因:1. chrome浏览器不支持在非https方式下打开音/视频设备。2. appr.tc中的信令服务器(collider)不支持非 https 服务。
二、appr.tc搭建的服务可以使各端互通,但条件是必须使用第三方证书。第三方证书可以在阿里云申请或诺顿等安全公司申请。如果你是在公司内网搭建服务,那么可以使用nginx做个代理,将证书放到代理服务器端,这样你本地服务器可以使用私有证书,这样就没任何问题了。
三、如果体用了第三方证书,并配有域名的话,请将下面所有的 IP:Port替换成你自己的域名。使用域名+路径的方式,可以将不同的路径映射到不同的端口上

下面我就来描述一下如何搭建 appr.tc 服务。

搭建AppRTC Server的基本步骤

  1. 搭建 Room Server(房间服务器),也就是 AppRTC
  2. 搭建 信令服务器, 它在上面 AppRTC 中的 src/Collider 下
  3. 搭建 CoTURN 服务器,用于音视频数据的转发。
  4. 搭建获取 CoTURN 信息的服务器,也就是 ICE REST API 服务。

几个重要的库

在具体介绍 appr.tc服务如何搭建之前,我们先来了解几个基本概念。

Google Cloud SDK

按照 google 官方的说法,Google Cloud SDK 是一套非常好用的使用 python 管理 App Engine applications 的工具集。gcloud包括本地布署server以及布署和管理你的应用的命令行工具。

其实我并不这么认为,我觉得使用它增加了我的学习成本。当遇要问题时,我其实对它是束手无策的。

我们可以认为它就是一套布署工具,可以帮我们布署和启动服务程序。我们使用它布署启动 room 服务器。

AppRTC

房间与信令服务器。该服务器包括了房间的业务逻辑和信令处理逻辑。其中在 AppRTC中的 collier 目录中是信令服务器的实现。

除了 collider 命令服务器外,其它的代码都是用python写的。

Collider

是一种用 go 语言实现的基于 WebSocket 的命令服务器。要了解 WebSocket 协议可以看这篇文章 WebSocket协议:5分钟从入门到精通。

Coturn

Coturn 是一种TURN服务器(也就是中转服务器),该服务器用于VoIP或通用数据流的NAT穿越和数据转发。

所以总结起来 appr.tc服务包括了room服务器(apprtc)、信令服务器(collider)、NAT穿越与数据转发服务器(coturn)

Grunt

Grunt是一种可以帮助我们解决 JavaScript 的开发过程中,经常会遇到一些重复性的任务,比如合并文件、压缩代码、检查语法错误、将Sass代码转成CSS代码等等。

Grunt能够按照预先设定的顺序自动运行一系列的任务。这可以简化工作流程,减轻重复性工作带来的负担。

Grunt基于Node.js,安装之前要先安装Node.js

如何搭建 appr.tc 服务器

  1. 从 git 上 Clone AppRTC。在代码中包括了 room服务器和collider信令服务器。

  2. 安装、布署、启动 Collider,这一步比较复杂。

    • 安装 Go 工具,并创建工作空间。在 ubuntu 下安装 Go 比较简单,如 apt install golang-1.10-go。 创建的 go 工作空间,如:export GOPATH=$HOME/goWorkspace/ 。它包括两个子目录,分别是 bin和 src

      • bin : 该子目录中存放编译后的可执行文件。
      • src : 该子目录中存放 go 项目源文件。
    • 链接 collider 目录下的子目录到 $GOPATH/src下

      ln -s `pwd`/apprtc/src/collider/collider $GOPATH/src
      ln -s `pwd`/apprtc/src/collider/collidermain $GOPATH/src
      ln -s `pwd`/apprtc/src/collider/collidertest $GOPATH/src
      
    • 安装依赖

      go get collidermain
      
    • 编译安装 collidermain

      go install collidermain
      
    • 布署 collider 服务

      1. 创建 /collider 和 /cert 目录 (如:sudo mkdir -p /collider, sudo mkdir -p /cert)
      2. 拷贝 $GOPATH/bin/collidermain 到 /collider 目录
      3. 创建 ssl 证书。创建证书的命令如下:sudo openssl req -x509 -newkey rsa:2048 -keyout key.pem -out /etc/cert.pem -days 99999 -nodes
      4. 将证书命名为 cert.pem 和 key.pem 并拷到 /cert 目录中。注:文件名和目录可以到 collider/collider.go文件中修改(通过搜索关键字 cert 找到修改的位置)
    • 启动 collider 信令服务器

      /collider/collidermain -port=8089 -tls=true -room-server="https://ip:port"
      

      当然,你还可以修改 collider/collidermain/main.go 文件,文件中的tls, port, room-server分别对应上面命令行中的参数。也就是说,如果在启动命令中不加任何参数,它就会使用 main.go中设置的参数,否则使用命令行中指定的参数。

      room-server 指的是 apprtc 服务,所以这里要指定 apprtc的端口,https 默认是 8081

      注:在网上看到很多文章说 collider 可以将tls设置为 false,经我亲测,将 tls设置为 false后,collider就不能正常工作了,如果有成功的可以与我联系。

  3. 安装并启动 Coturn TURN server

    • 首先,下载Coturn源码

    • 注:需要安装必要的依赖,如open-ssl,sqlite3-devel等

    • 编译并安装
      进入到Coturn源码目录下

      ./configure --prefix=/usr/local/turnserver 
      sudo make && sudo make install
      
    • 创建用户

      sudo turnadmin -a -u 用户名 -p 密码 -r 域(写你自己服务器的IP)
      

      使用上面命令创建的用户是一个长期用户,所以在下面配置文件中的lt-cred-mech要设置上。创建好用户后,可以使用下面的命令查看创建的用户

      turnadmin -l
      
    • 设置好 Coturn 配置

      #本地监听的网卡设备,这里根据自己的实际情况填写
      listening-device=eth1
      listening-port=3478
      #本地用于转发的网卡设备,这里根据自己的实际情况填写
      relay-device=eth1
      #指定的转发端口的分配范围,测试时,可以将防火墙全部关闭,防止 UDP 端口被屏蔽
      min-port=3480
      max-port=3500
      #日志输出级别,turnserver 启动时加上 -v,可以得到更清晰的日志输出
      Verbose
      #消息验证,WebRTC 的消息里会用到
      fingerprint
      #webrtc 通过 turn 中继,必须使用长验证方式
      lt-cred-mech
      # ICE REST API 认证需要(如果打开了这行,turn就不工作了)
      use-auth-secret
      # REST API 加密所需的 KEY
      # 这里我们使用“静态”的 KEY,Google 自己也用的这个
      static-auth-secret=4080218913
      #用户登录域,下面的写法可以不改变它,因为再启动 turnserver 时,可以通过指定参数覆盖它
      realm=<填写你自己的服务器的IP>#这个特别关键,如果这里不是你的服务器的IP,数据就不通
      #可为 TURN 服务提供更安全的访问(这个我没用,不知道干啥的)
      #stale-nonce
      #在Coturn代码中的/etc/examples/目录下有秘钥文件,可以直接用
      cert=/usr/local/turnserver/etc/turn_server_cert.pem
      pkey=/usr/local/turnserver/etc/turn_server_pkey.pem
      #屏蔽 loopback, multicast IP地址的 relay
      no-loopback-peers
      no-multicast-peers
      #启用 Mobility ICE 支持(不懂)
      mobility
      #禁用本地 telnet cli 管理接口
      no-cli
      
    • 启动Coturn服务

      sudo turnserver -v /etc/turnserver.conf
      

      还可以用下面的命令启动,这样就不用写配置文件了,命令如下:

      sudo turnserver -v -L ip  -a -f -r 你的服务器的IP
      

      通过 -v 指定日志输出级别; -L 指定用于绑定的网卡 IP 地址;-a 指定使用长期凭证机制,turn中继转发模式,必须使用长期凭证机制;-f 指定 turn 消息使用 fingerprint;-r 指定使用的域名,将覆盖 turnserver.conf 文件中的配置;

    • 测试 Coturn 服务

      1. 打开 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/这个网址
      2. 在该网址上增加 turn 服务。如 turn:IP:3478
      3. 填入用户名密码
  4. 布署与启动 room 服务(appr.tc)

    • 下载 Google app engine SDK for Python

    •  

      以centos安装为例,官方使用yum安装,需要,配置代理/etc/yum.conf,加入proxy=https://ip:port

      下载之后不需要按照常 Google 官方文档中的说明操作,只需要将它的 bin 目录添加环境变量中即可。即添加 "export PATH=$PATH:/xxx/xxx/bin到 ~/.bashrc 文件中。这样就可以访问 dev_appserver.py 这个工具了。
    • 安装 node.js

      sudo apt-get install nodejs
      

      或通过源码安装。

    • 安装 grunt

      sudo apt-get install npm
      sudo npm -g install grunt-cli
      
    • 打开 apprtc/src/app_engine/constants.py修改以下内容:

      ICE_SERVER_BASE_URL = 'https://ip:port'
      ICE_SERVER_URL_TEMPLATE = '%s/iceconfig?key=%s'
      ICE_SERVER_API_KEY = os.environ.get('ICE_SERVER_API_KEY')
      

      上面的配置是为了动态获取 stun/turn 服务器的密码,所以其IP地址与端口号应该与下面的 ICE REST API 服务中的一样,即端口号为 3033。

      以及

      # Dictionary keys in the collider instance info constant.
      WSS_INSTANCE_HOST_KEY = 'host_port_pair'
      WSS_INSTANCE_NAME_KEY = 'vm_name'
      WSS_INSTANCE_ZONE_KEY = 'zone'
      WSS_INSTANCES = [{
             WSS_INSTANCE_HOST_KEY: 'IP:PORT',
             WSS_INSTANCE_NAME_KEY: 'wsserver-std',
             WSS_INSTANCE_ZONE_KEY: 'us-central1-a'
      }]
      

      上面这个配置是为了使房间服务器与信令服务器 collider 进行通讯,所以配置的 IP 和 端口要与上面设置collider时的一样。

    • 安装 JDK
      通过java -version判断是否已经安装了 JDK,如果没有安装的话,先装 JDK安装上。别外 JDK只能安装 JDK7 或 JDK8,太高或太低的版本都不行。

      sudo apt install openjdk-8-jdk
      
    • 编译 apprtc
      修改了 appr.tc 的代码后,使用 grunt build 进行编译,在 apprtc 目录下执行下面命令:

      sudo npm install # 安装 apprtc 中需要的 nodejs 依赖包,其存放在 package.json 文件中
      sudo grunt build
      
    • 错误:[email protected] 安装错误

      > [email protected] install /root/webrtc/apprtc/node_modules/iltorb
      > node-pre-gyp install --fallback-to-build
      
      node-pre-gyp ERR! Tried to download(404): https://node-iltorb.s3.amazonaws.com/iltorb/v1.3.1/node-v64-linux-x64.tar.gz
      node-pre-gyp ERR! Pre-built binaries not found for [email protected] and [email protected] (node-v64 ABI) (falling back to source compile with node-gyp)
      node-pre-gyp ERR! Tried to download(undefined): https://node-iltorb.s3.amazonaws.com/iltorb/v1.3.1/node-v64-linux-x64.tar.gz
      node-pre-gyp ERR! Pre-built binaries not found for [email protected] and [email protected] (node-v64 ABI) (falling back to source compile with node-gyp)

      解决办法: 单独拿出来安装(可能是网络原因)

      npm install iltorb
      # 再执行
      sudo npm install
    • 错误 : requests模块不存在

      Running "shell:buildAppEnginePackage" (shell) task
      Traceback (most recent call last):
        File "./build/build_app_engine_package.py", line 12, in 
          import requests
      ImportError: No module named requests
      Warning: Command failed: python ./build/build_app_engine_package.py src out/app_engine
      Traceback (most recent call last):
        File "./build/build_app_engine_package.py", line 12, in 
          import requests
      ImportError: No module named requests
       Use --force to continue.

      解决办法:安装这个依赖

      pip install requests
    •  

    • 布署room server

      /dev_appserver.py --host 0.0.0.0 --enable_host_checking=no --ssl_certificate_path=/xxx/cert.pem --ssl_certificate_key_path=/xxx/key.pem  ./out/app_engine
      

配置 ICE REST API 服务

实现 js 代码

var https = require('https')
var fs = require('fs')
var express = require('express')
var crypto = require('crypto')
var app = express()

var option = {
        key : fs.readFileSync('/cert/key.pem'),
        cert: fs.readFileSync('/cert/cert.pem'),
}

var hmac = function (key, content) {
  var method = crypto.createHmac('sha1', key)
  method.setEncoding('base64')
  method.write(content)
  method.end()
  return method.read()
}

app.get('/iceconfig', function (req, resp) {
  var query = req.query
  var key = '4080218913'
  var time_to_live = 3600*24
  var timestamp = Math.floor(Date.now() / 1000) + time_to_live
  var turn_username = timestamp + ':' + 'garrylea'
  var password = hmac(key, turn_username)

  resp.header("Access-Control-Allow-Origin", "*");   //设置跨域访问

  return resp.send({
    iceServers: [
      {
        urls: [
          'turn:ip:3478?transport=tcp',
          'turn:ip:3478?transport=udp',
          'turn:ip:3479?transport=tcp',
          'turn:ip:3479?transport=udp',
        ],
        username: turn_username,
        credential: password
      }
    ]
  })
})

var server = https.createServer(option, app);

server.listen('3033', function () {
  console.log('server started')
})

上面代码中有几点要说明:

  1. 上面的turn:ip:3478这个不要换成域名。
  2. 用户名的格式为 时间戳:用户名。时间戳是由当前时间换成秒数 + 过期时间
  3. credential的值是key加密后base64编码,再与用户名连在一起。注意,这里的key要与 turn 配置文件中的 key保持一至
  4. 提供的必须是https服务。

启动 ICE REST API 服务

node index.js

配置服务器遇到的问题

  • 私有证书问题。使用私有证书导致只能浏览器之间进行通讯。移动端与浏览器之间不能通讯。解决办法是花钱申请第三方证书。
  • 地址映射错误。使用域名后,映射的地址出错了。比如通过apprtc.xxxx.com/iceconfig映射到 192.168.31.6:3033这个地址是不对的,应该映射到 192.168.31.3033/iceconfig这样才行。
  • turn服务不通问题。后来经多方查询,是由于设置的域不对,之前设置的是north.gov,应该设置为你的服务器的IP地址就可以了。
  • ICE REST API 使用http问题。应该改为https才能访问。也就是说所有的地址都应该是https的,而不能有的是https,有的是http。
  • 用户退出报错。原因是由于在 collider服务的 src/collider/collidermain/main.go文件设置的room-server地址不是域名的方式,也就是说不是第三方证书的方式,这样就造成用户退出时,命令服务器通知 room-server时,由于证书的原因导致出错。
  • 换成域名后浏览器报 Failed to start signaling: Failed to execute 'pushState' on 'History': A history state object with URL这样的错误。可以在 src/web_app/js/appcontroller.js 文件中将 window.history.pushState({'roomId': roomId, 'roomLink': roomLink}, roomId, roomLink);这一句注释掉就好了。

小结

总的来说,配置 appr.tc 服务还是蛮复杂的。在网上看了很多文章没有一个可以配通过的。在配置的过程中每一个参数都要仔细的琢磨生怕配错。

总之来之不易,希望可以帮到用到的人。

参考资料

  • 官方文档
  • 主要参考了这篇文章
  • 以及这篇

特别推荐

我的视频课



作者:音视频直播技术专家
链接:https://www.jianshu.com/p/a19441034f17
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的:(web)