WebRTCWebRTC多媒体开发

Ubuntu 下搭建 AppRTC 服务

2017-08-23  本文已影响1134人  Gobert

研究 WebRTC 协议,最好先自己基于官方 Demo 动手搭一套服务环境,其中包括 房间服务器 AppRTC信令服务器(AppRTC 目录下的 src/Collider)coTurn NAT 穿透服务器 ,分别通过下载、编译并配置相关参数,便可以成功的搭建起一套 WebRTC 实时音视频通信系统;

而客户端可以使用 Firefox brower 和 Android 客户端 AppRTCMobile Demo。

以下为浏览器与Android AppRTCMobile Demo 建立视频通话效果图(Android 截图)!

在搭建的过程中,走了一些弯路,现记录下正确的流程,以供学习交流!

注:搭建过程中需要从 Google 服务器下载工具包,所以请事先准备好相应的网络环境!

一、环境准备

本人一直在 Ubuntu 下进行编译、配置、调试 webrtc 相关服务,故以下内容均是指在 Ubuntu 下的操作流程!

1、安装 Ubuntu 系统

目前 AppRTC 目前仅支持 Linux/MAC 下运行(Linux kernel 均可),安装 Ubuntu 系统。

安装好 Git ,以下载 AppRtc 源码 :

sudo apt-get install git

2、 VPN网络

搭建过程中需要从 Google 服务器下载源代码和工具包,所以请事先准备好相应的翻墙网络环境!

二、编译 & 运行 AppRTC

1、下载 AppRTC 源码

如果本机已经配置好了 ssh public key,则可以通过以下命令进行下载:

git clone git@github.com:webrtc/apprtc.git

或者通过 Https 进行下载,不需要配置 ssh key:

git clone https://github.com/webrtc/apprtc.git

编译并运行 AppRTC,可参照其 README,需首先下载安装并配置相关依赖包;

可依次执行以下安装命令,如果全部执行成功,则直接跳到第 6 步:

sudo apt-get install nodejs
sudo npm install -g npm
sudo apt-get install nodejs-legacy
sudo npm -g install grunt-cli 
sudo apt-get install python-requests

2、下载编译 Google App Engine SDK for Python

Google App Engine 是一种让您可以在 Google 的基础架构上运行您的网络应用程序。Google App Engine 应用程序易于构建和维护,并可根据您的访问量和数据存储需要的增长轻松扩展。使用 Google App Engine,将不再需要维护服务器:您只需上传您的应用程序,它便可立即为您的用户提供服务。

当前,Google App Engine支持的编程语言包括 Python、Java、PHP 和 GO。Google说它准备在未来支持更多的语言,Google App Engine也将会独立于某种语言。任何支持 WSGI 的使用 CGI 的 Python 框架可以使用。框架可以与开发出的应用程序一同上传,也可以上传使用Python编写的第三方库。这里我们使用 基于 Python 的 App Engine。

参考文档安装 Google app engine sdk ,严格按照文档进行安装即可;

3、下载Node.js

Node.js 是一个能够在服务器端运行 JavaScript 的开放源代码、跨平台的 JavaScript 运行环境;Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。 Node.js 的包管理器 npm,是全球最大的开源管理系统。

Node.js大部分基本模块都用JavaScript语言编写。在Node.js出现之前,JavaScript通常作为客户端程序设计语言使用,以JavaScript写出的程序常在用户的浏览器上运行。Node.js的出现使JavaScript也能用于服务器端编程。Node.js含有一系列内置模块,使得程序可以脱离 Apache Http Server 或 IIS,作为独立服务器运行。

下载 并配置 bin 目录到 环境变量 PATH 中,或者直接使用命令安装:

sudo apt-get install nodejs
sudo apt-get install nodejs-legacy

4、下载 Grunt

在 JavaScript 的开发过程中,经常会遇到一些重复性的任务,比如合并文件、压缩代码、检查语法错误、将Sass代码转成CSS代码等等。通常,我们需要使用不同的工具,来完成不同的任务,既重复劳动又非常耗时。Grunt就是为了解决这个问题而发明的工具,可以帮助我们自动管理和运行各种任务。

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

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

安装 Grunt 可以通过官网介绍进行下载安装,或者通过 npm 进行安装:

sudo apt-get install npm
sudo npm -g install grunt-cli   //-g 表示全局安装

5、安装 Python-requests 依赖

sudo apt-get install python-requests

6、编译 AppRTC

进入 AppRTC 目录,执行编译命令:

npm install
sudo grunt build

编译成功后,会在 out/app_engine 目录下生成 server 可执行脚本。

7、配置 apprtc.py

AppRTC 配置文件存放在 AppRTC 源码目录下的 out/app_engine 下:

gobert@gobert-ThinkPad-X230:~/OpenSource/apprtc/out/app_engine$ ls
analytics_enums.py  apprtc.py      compute_page.py  full_template.html   js
analytics_page.py   apprtc.py_bak  constants.py     html                 probers.py
analytics.py        app.yaml       cron.yaml        images               third_party
apiauth.py          bigquery       css              index_template.html  version_info.json
gobert@gobert-ThinkPad-X230:~/OpenSource/apprtc/out/app_engine$ 

打开 apprtc.py 配置文件,修改 get_wss_parameters(request) 方法定义,目的为不要让客户端或浏览器使用 ssl 进行连接(因为我们刚开始还没有任何根证书),但是如果有第三 方根证书的签名机构颁发的证书就不需要这样了。

将 wss 改为 ws, https 改为 http 即可:

if wss_tls and wss_tls == 'false':
    wss_url = 'ws://' + wss_host_port_pair + '/ws'
    wss_post_url = 'http://' + wss_host_port_pair
else:
    wss_url = 'ws://' + wss_host_port_pair + '/ws'
    wss_post_url = 'http://' + wss_host_port_pair

8、配置 constants.py

打开并修改 constants.py 文件,因为我们计划后续支持 AppRTC Demo 与 浏览器之间的视频通话,而 AppRTC Demo 默认只支持通过 HTTP REST API 的方式获取 TURN Server 地址信息,所以我们必须配置一个 ICE HTTP URL,当客户端请求此 URL 时,返回一个 json 字符串,其中包含 turnserver 地址及认证信息,url 地址根据自己配置的具体的 http server ip & port 进行设定:

# TODO(jansson): Remove once AppRTCDemo on iOS supports ICE_SERVER.
#TURN_BASE_URL = 'https://computeengineondemand.appspot.com'
TURN_BASE_URL = 'http://100.100.32.64:3033'
TURN_URL_TEMPLATE = '%s/turn?username=%s&key=%s'
CEOD_KEY = '4080218913'

ICE_SERVER_BASE_URL = 'http://100.100.32.64:3033'
#ICE_SERVER_BASE_URL = 'https://networktraversal.googleapis.com'
#ICE_SERVER_URL_TEMPLATE = '%s/v1alpha/iceconfig?key=%s'
ICE_SERVER_URL_TEMPLATE = '%s/iceconfig?key=%s'
ICE_SERVER_API_KEY = os.environ.get('ICE_SERVER_API_KEY')

配置 信令服务器 collider 信息,指定 collider 运行端口号为 8089,后面在启动 collider 时,要与其指定绑定的端口号相对应;

WSS_INSTANCES 只保留一个即可:

# 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: '100.100.32.64:8089',
    WSS_INSTANCE_NAME_KEY: 'wsserver-std',
    WSS_INSTANCE_ZONE_KEY: 'us-central1-a'
}]

9、启动 AppRTC Server

在 AppRTC 目录下执行启动命令:

dev_appserver.py -–host=0.0.0.0 ./out/app_engine    

注:--host 指定绑定 IP 地址,如 100.100.32.64,如果不指定,则默认使用 localhost,但其它终端不能访问。

dev_appserver.py 拥有众多配置参数,详细如下:

usage: dev_appserver.py [-h] [-A APP_ID] [--host HOST] [--port PORT]
                        [--admin_host ADMIN_HOST] [--admin_port ADMIN_PORT]
                        [--auth_domain AUTH_DOMAIN] [--storage_path PATH]
                        [--log_level {debug,info,warning,critical,error}]
                        [--max_module_instances MAX_MODULE_INSTANCES]
                        [--use_mtime_file_watcher [USE_MTIME_FILE_WATCHER]]
                        [--threadsafe_override THREADSAFE_OVERRIDE]
                        [--php_executable_path PATH]
                        [--php_remote_debugging [PHP_REMOTE_DEBUGGING]]
                        [--php_gae_extension_path PATH]
                        [--php_xdebug_extension_path PATH]
                        [--appidentity_email_address APPIDENTITY_EMAIL_ADDRESS]
                        [--appidentity_private_key_path APPIDENTITY_PRIVATE_KEY_PATH]
                        [--python_startup_script PYTHON_STARTUP_SCRIPT]
                        [--python_startup_args PYTHON_STARTUP_ARGS]
                        [--jvm_flag JVM_FLAG] [--go_work_dir GO_WORK_DIR]
                        [--enable_watching_go_path [ENABLE_WATCHING_GO_PATH]]
                        [--custom_entrypoint CUSTOM_ENTRYPOINT]
                        [--runtime RUNTIME] [--blobstore_path BLOBSTORE_PATH]
                        [--mysql_host MYSQL_HOST] [--mysql_port MYSQL_PORT]
                        [--mysql_user MYSQL_USER]
                        [--mysql_password MYSQL_PASSWORD]
                        [--mysql_socket MYSQL_SOCKET]
                        [--datastore_path DATASTORE_PATH]
                        [--clear_datastore [CLEAR_DATASTORE]]
                        [--datastore_consistency_policy {consistent,random,time}]
                        [--require_indexes [REQUIRE_INDEXES]]
                        [--auto_id_policy {sequential,scattered}]
                        [--logs_path LOGS_PATH]
                        [--show_mail_body [SHOW_MAIL_BODY]]
                        [--enable_sendmail [ENABLE_SENDMAIL]]
                        [--smtp_host SMTP_HOST] [--smtp_port SMTP_PORT]
                        [--smtp_user SMTP_USER]
                        [--smtp_password SMTP_PASSWORD]
                        [--smtp_allow_tls [SMTP_ALLOW_TLS]]
                        [--search_indexes_path SEARCH_INDEXES_PATH]
                        [--clear_search_indexes [CLEAR_SEARCH_INDEXES]]
                        [--enable_task_running [ENABLE_TASK_RUNNING]]
                        [--allow_skipped_files [ALLOW_SKIPPED_FILES]]
                        [--watcher_ignore_re WATCHER_IGNORE_RE]
                        [--api_port API_PORT] [--grpc_api GRPC_APIS]
                        [--grpc_api_port GRPC_API_PORT]
                        [--automatic_restart [AUTOMATIC_RESTART]]
                        [--dev_appserver_log_level {debug,info,warning,critical,error}]
                        [--skip_sdk_update_check [SKIP_SDK_UPDATE_CHECK]]
                        [--default_gcs_bucket_name DEFAULT_GCS_BUCKET_NAME]
                        [--env_var ENV_VARIABLES]
                        [--google_analytics_client_id GOOGLE_ANALYTICS_CLIENT_ID]
                        [--google_analytics_user_agent GOOGLE_ANALYTICS_USER_AGENT]
                        yaml_path [yaml_path ...]

至此房间服务器 AppRTC Server 已经运行起来了。

三、编译 & 运行 Collider

WebRTC 并未规定信令服务器的具体协议标准,其只需要帮助客户端来回传递信息即可,这个过程在 webrtc 中并未实现,需要开发者自己实现,不过在 AppRTC 中提供了一个 Collider (集成在 AppRTC 内部的)信令服务器可供参考、调试。

1、安装 Go 开发包

Collider 基于 Go 语言进行开发,编译 collider 则必须依赖 go 语言工具包,执行以下命令首先安装 Go 语言开发工具:

sudo apt-get install golang-go

2、配置 Go 环境变量

首先创建 Go 工作目录 $HOME/goWorkspace,并添加环境变量 GOPATH ,并在 GOPATH 中手动创建 src 目录;

编辑 /etc/profile 文件,在最下方添加如下内容:

#set go path
export GOPATH=$HOME/goWorkspace

添加完成后,执行

source /etc/profile

使环境变量生效;

最后在 $GOPATH 中手动添加 src 目录:

mkdir $GOPATH/src

注:如需 room 权限,则自行添加 sudo 前缀。

3、拷贝 collider 源码

在 $GOPATH/src 目录下创建指向 collider 源码目录的软链接,或者直接拷贝 collider 目录源码至 GOPATH 目录;

创建软链接时不要使用官方推荐的 'pwd',否则更换了目录,软链接就会指向了无效目录,建议使用绝对路径,如:

 sudo ln -s $HOME/OpenSource/apprtc/src/collider/collider $GOPATH/src
 sudo ln -s $HOME/OpenSource/apprtc/src/collider/collidermain $GOPATH/src
 sudo ln -s $HOME/OpenSource/apprtc/src/collider/collidertest $GOPATH/src

4、编译、安装 collider

将上一步中指向的 collider 源码进行编译并安装到系统中,首先要将 collider server 中指定的 Room Server 地址改为本地的 AppRTC Server 地址,修改 collider/collidermain/main.go 文件中的 roomSrv 地址:

var roomSrv = flag.String("room-server", "https://appr.tc", "The origin of the room server")
改为:
var roomSrv = flag.String("room-server", "http://192.168.1.107:8080/", "The origin of the room server")

如果没有翻墙的话,go get 将无法安装 golang 的官方包,导致编译报错,如:

package golang.org/x/net/websocket: unrecognized import path "golang.org/x/net/websocket" (https fetch: Get https://golang.org/x/net/websocket?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)

其实 golang 在 github 上建立了一个镜像库,如 https://github.com/golang/net 即是 https://golang.org/x/net 的镜像库,获取 golang.org/x/net 包,其实只需要以下步骤:

mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/net.git

其它 golang.org/x 下的包获取皆可使用该方法

编译并安装 collider:

go get collidermain
go install collidermain

如果提示 $GOPATH not set,请排查 GOPATH 设置是否正常,倘若还是搞不定的话,就使用如下命令进行编译安装:

sudo env GOPATH=$HOME/goWorkspace go get collidermain
sudo env GOPATH=$HOME/goWorkspace go install collidermain

5、启动 collider

任意目录下,通过如下命令启动 collider 服务,其中 port 需配置为 apprtc server 的 constants.py 中信令服务器 WSS_INSTANCE_HOST_KEY 的端口地址:

collidermain -port=8089 -tls=false

其中 --port 指定端口,-tls 是否开启 ssl 安全验证;collidermain 还有一个启动配置参数:-room-server 用于制定房间服务器地址,如果未指定,则默认使用源码 collider/collidermain/main.go 文件中的 roomSrv 地址。如:

collidermain -port=8089 -tls=false -room-server="http://100.100.32.64:8080"

三、配置 & 启动 coTurn

coturn 是一个 turn server,其支持浏览器通过 stun 协议与其进行通讯,以获取浏览器自己的公网地址及 NAT 信息,如果建立 ICE Server 则需要自己建立一个 http Server,客户端通过 REST API 进行访问以获取 turn Server 地址及认证信息等;我们将首先通过配置,保证浏览器使用我们自己的 TURN Server。

1、下载

下载 Ubuntu 下对应的最新版本,下载地址
coturn 底层网络库依赖 libevent,所以需首先安装 libevent,这个我们就直接通过 apt-get 进行下载安装,不单独下载源码进行编译安装了:

sudo apt-get install libevent-dev

2、编译

coturn 下载的是源码,需自己编译,进入 coturn 源码目录,依次执行以下命令:

./configure
make

编译成功后,会在源码 bin 目录中生成配置及可执行文件(手动将 example 目录中的 turnserver.conf 配置文件拷贝到 bin 目录):

gobert@gobert-ThinkPad-X230:~/OpenSource/coturn/bin$ ls
turnadmin            turnutils_natdiscovery  turnutils_stunclient
turnserver           turnutils_oauth         turnutils_uclient
turnserver.conf      turnutils_peer          turnutils_rfc5769check

3、配置

修改 turnserver.conf 配置为如下内容,并根据自己的实际情况做适当的修改:

#如果多网卡,记得此处设置为和你所用监听的IP相对应的eth
listening-device=wlxe840f236118e
listening-port=3478
relay-device=wlxe840f236118e
#转发端口号范围
min-port=59000
max-port=65000
#Verbose
fingerprint
#webrtc需要使用此选项
lt-cred-mech
use-auth-secret
static-auth-secret=4080218913
#之前turnadmin中-r参数的值,此处要对应
realm=qiniu
#stale-nonce=600
#max-allocate-lifetime=3000
#可以添加用户名和密码
user=gobert:4080218913
#测试期间可以使用example/etc中的pem,自己计算的话需要用到openssl,方法为:
#sudo openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes

#填写pem目录即可,如
#cert=~/OpenSource/coturn/example/etc/turn_server_cert.pem
#pkey==$HOME/OpenSource/coturn/example/etc/turn_server_pkey.pem
# Certificate file.
# Use an absolute path or path relative to the 
# configuration file.
#
cert=/usr/local/etc/turn_server_cert.pem

# Private key file.
# Use an absolute path or path relative to the 
# configuration file.
# Use PEM file format.
#
pkey=/usr/local/etc/turn_server_pkey.pem

no-loopback-peers
no-multicast-peers
mobility
no-cli
#各项参数含义,可以看turnserver.conf中的说明。

或者根据自己一项一项的在 turnserver.conf 文件中查找并修改;

4、启动 coTurn

进入 bin 目录

sudo ./turnserver

四、配置 ICE REST API

客户端连接 Room Server apprtc 后,通过 Room Server 得到用于获取 ICE Server 信息的 iceServerRequestUrl,然后浏览器和 AppRTC Demo 通过请求此 URL,得到 ICE Server 相关信息(返回 json),具体标准请参考:TURN REST API

下面一一介绍,如何配置 REST API 接口,以供浏览器及 AppRTC Demo 获取 coTurn Server 连接信息。

1、配置 REST API

如果前面已经成功编译 apprtc server,则一定已经安装过了 Node.js 工具包,这里就介绍通过 Node.js 配置 REST API 的方法;另:通过 apache2 或者 nginx 解析 php 去实现也可以,本人均已配置通过(前期花了较大的精力去一步步解决配置 nginx 解析 php 的问题),但走到最后感觉最方便的还是 Node.js:

2、 修改 apprtc 配置

修改 apprtc 源码目录下 /out/app_engine/js/apprtc.debug.js 文件,将 requestIceServers 方法中调用 sendAsyncUrlRequest 时使用的 POST 方法改为 GET 方法,因为我们的这个 nodejs 代码不支持 POST 方法:

function requestIceServers(iceServerRequestUrl, iceTransports) {
return new Promise(function(resolve, reject) {
  //sendAsyncUrlRequest("POST", iceServerRequestUrl).then(function(response) {
  sendAsyncUrlRequest("GET", iceServerRequestUrl).then(function(response) {
    var iceServerRequestResponse = parseJSON(response);
    if (!iceServerRequestResponse) {
      reject(Error("Error parsing response JSON: " + response));
      return;
    }
    if (iceTransports !== "") {
      filterIceServersUrls(iceServerRequestResponse, iceTransports);
    }
    trace("Retrieved ICE server information.");
    resolve(iceServerRequestResponse.iceServers);
  }).catch(function(error) {
    reject(Error("ICE server request error: " + error.message));
    return;
  });
});

注:此项修改主要解决客户端通过 POST 不能访问我们的 REST API 获取 turn server 的问题!

3、修改 Android Demo 源码

参照以上方法配置后,浏览器已经可以正常的进入房间,开启音视频通话,而通过 Android demo(AppRTCMobile)请求时会报 404 错误(Connection error Room IO Error, Non-200 response when requesting TURN Server from ×××HTTP/1.1 404 not found)

解决方法:通过修改 RoomParametersFetcher.java 文件,找到并注释掉此行代码即可:

//connection.setDoOutput(true);

具体作用请自行查找资料。

修改后,需重新编译生成 AppRTCMobile.apk 并安装:

ninja -C out/Debug

4、重启服务

修改了上述文件配置,建议重新启动下相关服务进程:

五、测试

1、访问测试

通过浏览器与Android AppRTCMobile Demo 进行联调测试!

至此,我们已经可以通过我们自己搭建的 Room Server、Collider Server、ICE Server 进行音视频聊天了!

注:官方 Demo 默认仅支持两人进入房间。

当前仅支持 Firefox 浏览器,因为 Chrome 浏览器(version 47 以后)对音视频采集有权限控制,其目前仅支持在 localhost 打开音视频采集,如果是其它网络地址,则需要通过 HTTPS 进行加密访问。

关于如何让 Chrome 浏览器支持访问 AppRTC Server,将在后续更新中介绍。

以下为浏览器与Android Demo 联调效果图!

2、抓包验证

在建立音视频通话过程中,通过 wireshark 抓包,并过滤 stun 协议,通过查看数据包往来判断会话建立过程全部通过内网服务器:

3、浏览器调试

在调试 REST API 时,借助浏览器的控制台可以很好的进行错误的定位和排查,下图为配置好后,浏览器控制台的正确输出:

通过查看来往消息,可以清晰的看到 webrtc 在建立音视频通话的过程中,与 room server、collider server、coturn server 之间的通讯流程。

上一篇 下一篇

猜你喜欢

热点阅读