Webrtc系列三——Ubuntu 20.04上Apprtc服务搭建之一

        由于https://appr.tc已经不维护了,导致研究webrtc源代码变得不太方便。同时webrtc编译出来的AppRTCMobile也无法正常和浏览器进行一对一的实时通信,本人花了好长一些时间来解决这些问题,通过解决这些问题特写下这个文章,一方面起到记录使用,另一方面也可以作为他人参考使用,本文在Ubuntu 20.04.6 LTS上部署apprtc,使得两个chrome浏览器可以进行通信,也可以在webrtc for android的AppRTCMobile.apk和chrome浏览器进行通信。

        本文只考虑在一台机器中本地部署AppRTC服务器及turn服务的情况,如果需要在公网或者正式商用场景部署,需要考虑https和wss安全链接及其证书的申请和配置等。

图1: 本文搭建后的整体架构

一、前置条件

        本文假定同学已经具备了以下条件,如果不具备科学上网的条件,可以下载本人上传到网盘的所有资料,完成本文目标(两个chrome浏览器可以进行通信,也可以在webrtc for android的AppRTCMobile.apk和chrome浏览器进行通信)

  • Ubuntu 20.04.6 LTS 系统,配置好了vim,git,python2(Apprtc不支持3.x,后面有时间再来改apprtc支持python3)等环境
  • 具备科学上网
  • 已经安装好的JDK(1.8),openssh-server、make、libtool等

二、AppRTC安装

1.安装node.js

mkdir ~/Desktop/webrtc
# 也可以采用其他版本的nodejs,本文使用v10.16.0
wget https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-x64.tar.xz
# 解压
tar -xvf node-v10.16.0-linux-x64.tar.xz
# 进入目录
cd node-v10.16.0-linux-x64/
# 查看当前的目录
pwd

# 确认一下nodejs下bin目录是否有node 和npm文件,如果有就可以执行软连接,比如
sudo ln -sf /home/louis/Desktop/webrtc/node-v10.16.0-linux-x64/bin/npm /usr/local/bin/
sudo ln -sf /home/louis/Desktop/webrtc/node-v10.16.0-linux-x64/bin/node /usr/local/bin/

# /home/louis/Desktop/webrtc这个路径你自己创建的路径

# 查看是否安装,安装正常则打印版本号
node -v 
npm -v 

# 有版本信息后安装 grunt-cli,先进到nodejs的bin目录, 要和自己的目录匹配
cd /home/louis/Desktop/webrtc/node-v10.16.0-linux-x64/bin
sudo npm install grunt-cli
sudo ln -sf /home/louis/Desktop/webrtc/node-v10.16.0-linux-x64/bin/grunt /usr/local/bin/

grunt --version
# 显示grunt-cli v1.4.3

2.安装google_appengine

cd ~/Desktop/webrtc/  # 进到webrtc目录
wget https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.40.zip  # 下载google_appengine
unzip google_appengine_1.9.40.zip #解压
export PATH=$PATH:/home/Desktop/webrtc/google_appengine #配置环境变量:在/etc/profile文件最后增加一行,和自己路径保持一致
source /etc/profile

3.安装go

cd ~/Desktop/webrtc/  # 进到webrtc目录
wget http://www.golangtc.com/static/go/1.7/go1.7.linux-amd64.tar.gz
#创建go工作目录
mkdir -p ~/Desktop/webrtc/goworkspace/src
#配置环境变量:在/etc/profile文件最后增加一行:
sudo vim /etc/profile

export GOPATH=/home/louis/Desktop/webrtc/goworkspace
source /etc/profile

4.AppRTC下载和安装

cd ~/Desktop/webrtc/
git clone https://github.com/webrtc/apprtc.git
# 如果github的连接下不了就用gitee的链接
# git clone https://gitee.com/sabergithub/apprtc.git
#将collider的源码软连接到go的工作目录下
ln -sf /home/louis/Desktop/webrtc/apprtc/src/collider/collider $GOPATH/src
ln -sf /home/louis/Desktop/webrtc/apprtc/src/collider/collidermain $GOPATH/src
ln -sf /home/louis/Desktop/webrtc/apprtc/src/collider/collidertest $GOPATH/src

#下一步在编译 go get collidermain
#报错: package golang.org/x/net/websocket: unrecognized import path "golang.org/x/net/websocket"
#所以先执行:
mkdir -p $GOPATH/src/golang.org/x/
cd $GOPATH/src/golang.org/x/
git clone https://github.com/golang/net.git net
cd $GOPATH/src/golang.org/x/net
git checkout v0.16.0 # 切换到老一点的tag v0.16.0,不然编译不过
go install net

#编译collidermain
cd ~/Desktop/webrtc/goworkspace/src
go get collidermain
go install collidermain

5.turn服务器的配置

cd ~/Desktop/webrtc/

sudo apt-get install libssl-dev
sudo apt-get install libevent-dev

wget http://coturn.net/turnserver/v4.5.0.7/turnserver-4.5.0.7.tar.gz #可以使用其他版本
tar xfz turnserver-4.5.0.7.tar.gz
cd turnserver-4.5.0.7
 
./configure 
make 
sudo make install

三、Nginx代理服务器的安装

sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev openssl

cd ~/Desktop/webrtc/
#下载nginx 本文以1.15.8版本为例
wget http://nginx.org/download/nginx-1.15.8.tar.gz
tar xvzf nginx-1.15.8.tar.gz
cd nginx-1.15.8/

# 要支持https请添加--with-http_ssl_module参数
./configure --with-http_ssl_module 
# 编译
make
#安装
sudo make install

四、配置

1. 开启所有需要的端口

sudo ufw allow 3478/tcp
sudo ufw allow 3478/udp
sudo ufw allow 8080/tcp
sudo ufw allow 8080/udp
sudo ufw allow 8089/tcp
sudo ufw allow 8089/udp
sudo ufw allow 3033/tcp
sudo ufw allow 3033/udp

2. 房间服务器配置

以下通过git diff的方式说明本人修改了那些部分以便支持本文目标。

diff --git a/src/app_engine/apprtc.py b/src/app_engine/apprtc.py
index 933bd7c..54126e3 100755
--- a/src/app_engine/apprtc.py
+++ b/src/app_engine/apprtc.py
@@ -149,8 +149,8 @@ def get_wss_parameters(request):
     wss_url = 'ws://' + wss_host_port_pair + '/ws'
     wss_post_url = 'http://' + wss_host_port_pair
   else:
-    wss_url = 'wss://' + wss_host_port_pair + '/ws'
-    wss_post_url = 'https://' + wss_host_port_pair
+    wss_url = 'ws://' + wss_host_port_pair + '/ws'
+    wss_post_url = 'http://' + wss_host_port_pair 
   return (wss_url, wss_post_url)
 
 def get_version_info():
diff --git a/src/app_engine/constants.py b/src/app_engine/constants.py
index 682331b..9e44c4b 100644
--- a/src/app_engine/constants.py
+++ b/src/app_engine/constants.py
@@ -37,23 +37,42 @@ ICE_SERVER_OVERRIDE = None
 #     ]
 #   }
 # ] 
-ICE_SERVER_BASE_URL = 'https://appr.tc'
+#ICE_SERVER_BASE_URL = 'https://appr.tc'
+ICE_SERVER_BASE_URL = 'http://192.168.0.104:3033'
 ICE_SERVER_URL_TEMPLATE = '%s/v1alpha/iceconfig?key=%s'
 ICE_SERVER_API_KEY = os.environ.get('ICE_SERVER_API_KEY')
 HEADER_MESSAGE = os.environ.get('HEADER_MESSAGE')
 ICE_SERVER_URLS = [url for url in os.environ.get('ICE_SERVER_URLS', '').split(',') if url]
 
 # Dictionary keys in the collider instance info constant.
-WSS_INSTANCE_HOST_KEY = 'host_port_pair'
+#WSS_INSTANCE_HOST_KEY = 'host_port_pair'
+WSS_INSTANCE_HOST_KEY = '192.168.0.104:8089'#根据自身的ip和端口来决定
 WSS_INSTANCE_NAME_KEY = 'vm_name'
 WSS_INSTANCE_ZONE_KEY = 'zone'
 WSS_INSTANCES = [{
-    WSS_INSTANCE_HOST_KEY: 'apprtc-ws.webrtc.org:443',
+    WSS_INSTANCE_HOST_KEY: '192.168.0.104:8089',
     WSS_INSTANCE_NAME_KEY: 'wsserver-std',
     WSS_INSTANCE_ZONE_KEY: 'us-central1-a'
 }, {
-    WSS_INSTANCE_HOST_KEY: 'apprtc-ws-2.webrtc.org:443',
+    WSS_INSTANCE_HOST_KEY: '192.168.0.104:8089',
     WSS_INSTANCE_NAME_KEY: 'wsserver-std-2',
     WSS_INSTANCE_ZONE_KEY: 'us-central1-f'
 }]
diff --git a/src/web_app/html/index_template.html b/src/web_app/html/index_template.html
index ade4c22..d032f20 100644
--- a/src/web_app/html/index_template.html
+++ b/src/web_app/html/index_template.html
@@ -137,6 +137,15 @@
   <script src="/js/storage.js"></script>
 
   <script type="text/javascript">
+    var servers=[{
+        credential:"louis",
+        username:"louis",
+        urls:[
+        "turn:192.168.0.104:3478?transport=udp",
+        "turn:192.168.0.104:3478?transport=tcp"
+        ]
+        }];
+      
     var loadingParams = {
       errorMessages: {{ error_messages }},
       isLoopback: {{ is_loopback }},
@@ -147,7 +156,8 @@
 {% endif %}
       mediaConstraints: {{ media_constraints | safe }},
       offerOptions: {{ offer_options | safe }},
-      peerConnectionConfig: {{ pc_config | safe }},
+      //peerConnectionConfig: {{ pc_config | safe }},
+      peerConnectionConfig: { "rtcpMuxPolicy":"require","iceServers":servers,"bundlePolicy":"max-bundle"},
       peerConnectionConstraints: {{ pc_constraints | safe }},
       iceServerRequestUrl: '{{ ice_server_url }}',
       iceServerTransports: '{{ ice_server_transports }}',
diff --git a/src/web_app/js/appcontroller.js b/src/web_app/js/appcontroller.js
index 16a75d5..b01321e 100644
--- a/src/web_app/js/appcontroller.js
+++ b/src/web_app/js/appcontroller.js
@@ -429,11 +429,12 @@ AppController.prototype.onKeyPress_ = function(event) {
 };
 
 AppController.prototype.pushCallNavigation_ = function(roomId, roomLink) {
-  window.history.pushState({'roomId': roomId, 'roomLink': roomLink}, roomId,
-      roomLink);
+  // window.history.pushState({'roomId': roomId, 'roomLink': roomLink}, roomId,
+  //     roomLink);//编译报错
 };
 
 AppController.prototype.displaySharingInfo_ = function(roomId, roomLink) {
+  roomLink=roomLink.replace("http","https"); //浏览器通话跨域问题 :pushState Messages:Failed to start signaling: Failed to execute ‘pushState’ on ‘History’
   this.roomLinkHref_.href = roomLink;
   this.roomLinkHref_.text = roomLink;
   this.roomLink_ = roomLink;

以上修改需要重新在apprtc目录下编译

cd ~/Desktop/webrtc/apprtc
sudo grunt build

3.nginx代理配置

(1)产生证书
sudo mkdir -p /cert
cd /cert
# CA私钥
openssl genrsa -out key.pem 2048
# 自签名证书
openssl req -new -x509 -key key.pem -out cert.pem -days 9999
(2)配置web服务器

配置文件/usr/local/nginx/conf/conf.d/apprtc-websocket-proxy.conf 

upstream roomserver {
   server 192.168.0.104:8080;
}
server {
    listen 443 ssl;
    ssl_certificate /cert/cert.pem;
    ssl_certificate_key /cert/key.pem; 
    charset utf-8;
    # ip地址或者域名
    server_name 192.168.0.104;
    location / {
        # 转向代理的地址
        proxy_pass http://roomserver$request_uri;
        proxy_set_header Host $host;
    }
}

编辑nginx.conf文件,在末尾}之前添加包含文件 

include /usr/local/nginx/conf/conf.d/*.conf;
}

(3)配置websocket代理

完整配置文件:/usr/local/nginx/conf/conf.d/apprtc-websocket-proxy.conf

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
upstream websocket {
    server 192.168.0.104:8089;
}

server {
    listen 8088 ssl;
    ssl_certificate /cert/cert.pem;
    ssl_certificate_key /cert/key.pem;

    server_name 192.168.0.104;
    location /ws {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_connect_timeout 4s; #配置点1
        proxy_read_timeout 6000s; #配置点2,可以考虑这个时间配置长一点
        proxy_send_timeout 6000s; #配置点3
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

4.turn web服务器

为能支持webrtc for android的AppRTCMobile.apk能正常和浏览器连接,需要增加一个http的turn访问服务器,通过nodejs启动它,本人将其命名为ice.js,在此之前,需要nodejs安装一下

sudo npm install express

完整的turn web服务代码如下,监听3033端口,将客户端的turn url请求返回正常的turn服务器信息

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

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

function handleIceRequest(req, resp) {
  console.log('handleIceRequest louis louis')
  var query = req.query
  var key = '4080218913'
  var time_to_live = 600
  var timestamp = Math.floor(Date.now() / 1000) + time_to_live
  var turn_username = timestamp + ':ninefingers'
  var password = hmac(key, turn_username)

  console.log('handleIceRequest req' +  req)

  return resp.send({
    iceServers: [
      {
        urls: [
          'stun:192.168.0.104:3478',//根据自身的ip修改
          'turn:192.168.0.104:3478'//根据自身的ip修改
        ],
        username: turn_username,
        credential: password
      }
    ]
  })
}

app.get('/v1alpha/iceconfig', handleIceRequest)
app.post('/v1alpha/iceconfig', handleIceRequest)

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

5.turn服务配置

直接给出配置文件

#本地监听的网卡设备,这里根据自己的实际情况填写
listening-device=ens37 #网卡名
listening-port=3478 #端口
#本地用于转发的网卡设备,这里根据自己的实际情况填写
relay-device=ens37
#指定的转发端口的分配范围,测试时,可以将防火墙全部关闭,防止 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=louis
#用户登录域,下面的写法可以不改变它,因为再启动 turnserver 时,可以通过指定参数覆盖它
realm=<填写你自己的服务器的IP>#这个特别关键,如果这里不是你的服务器的IP,数据就不通
#可为 TURN 服务提供更安全的访问(这个我没用,不知道干啥的)
#stale-nonce
#在Coturn代码中的/etc/examples/目录下有秘钥文件,可以直接用
#cert=/home/louis/Desktop/webrtc/turnserver-4.5.0.7/examples/etc/turn_server_cert.pem
#pkey=/home/louis/Desktop/webrtc/turnserver-4.5.0.7/examples/etc/turn_server_pkey.pem
cert=/cert/cert.pem
pkey=/cert/key.pem
#屏蔽 loopback, multicast IP地址的 relay
no-loopback-peers
no-multicast-peers
#启用 Mobility ICE 支持(不懂)
mobility
#禁用本地 telnet cli 管理接口
no-cli

五、启动服务 

为了方便启动,本人做了一个shell脚本 start.sh,可以用来启动所有的服务,脚本内容如下:

#/usr/bin/bash

sudo kill -9 `ps -elf| grep turnserver | awk '{print$4}'`
sudo kill -9 `ps -elf| grep collidermain | awk '{print$4}'`
sudo kill -9  `ps -elf| grep dev_appserver.py | awk '{print$4}'`
sudo kill -9  `ps -elf| grep ice.js | awk '{print$4}'`

cd /home/louis/Desktop/webrtc/apprtc
sudo grunt build
cd -

sleep 1

sudo turnserver -L 0.0.0.0 -z -S -u louis:louis -v -f -r 192.168.0.104 -c /home/louis/Desktop/webrtc/turnserver.conf 2>&1 > turnserver.log &

sleep 1

sudo node /home/louis/Desktop/webrtc/apprtc/ice.js  &
sleep 1
sudo /home/louis/Desktop/webrtc/goworkspace/bin/collidermain -port=8089 -tls=false -room-server="http://192.168.0.104:8080" 2>&1 > signal.log  &
#sudo /home/louis/Desktop/webrtc/goworkspace/bin/collidermain -port=8089 -tls=false -room-server="http://192.168.0.104:8080" &

sleep 1
#sudo  /home/louis/Desktop/webrtc/google_appengine/dev_appserver.py --host=0.0.0.0  /home/louis/Desktop/webrtc/apprtc/out/app_engine --skip_sdk_update_check &
sudo  /home/louis/Desktop/webrtc/google_appengine/dev_appserver.py --host=0.0.0.0  /home/louis/Desktop/webrtc/apprtc/out/app_engine --skip_sdk_update_check 2>&1 > roomserver.log &

sleep 1
sudo /usr/local/nginx/sbin/nginx -s stop
sudo /usr/local/nginx/sbin/nginx

sleep 1
ps -elf | grep -E "turn|dev_app|nginx|http|collidermain|ice.js"

此次所有的安装和配置工作都已经完成了,接下来将在“Webrtc系列四——Ubuntu 20.04上Apprtc服务搭建之二”中测试所有的链路和给出本人的所有代码。

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

louis-tt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值