使用EasyRTC发送文本消息

WebRTC介绍中简单说了一下WebRTC标准:你可以尝试使用WebRTC,了解一些基本信息。

对于开发人员来说,如果去开发自己的WebRTC呢,这需要使用实现WebRTC标准的具体技术。

本文中选用了EasyRTC,一种WebRTC的实现。

下面内容将包括:

  • EasyRTC是什么
  • 如何使用EasyRTC搭建自己的视频聊天环境
  • 使用EasyRTC提供的API,实现基本的文字聊天功能

EasyRTC是什么

一句话,EasyRTC是WebRTC标准的一个实现。

它包括:

  • 服务器端,nodejs实现的
  • Web端javascript api,相当于是对WebRTC API的封装和简化
  • iOS和Android本地API,这个应该是付费版本才有

EasyRTC自己的slogan是:

Open source WebRTC tools for enterprise developers

他们希望为企业提供,最快的、最强壮的和最易于使用的WebRTC视频、音频和数据的底层功能实现。

他们认为,到2016年,会有30亿人使用WebRTC:

看起来还不坏啊,如果真能达到这个使用人数。

他们开源了服务器端和Web端的javascript api,见GitHub

不过没有提供移动端(iOS和Android)的API,我向EasyRTC询问了是否能提供它们的试用版本,以便评估,一有回复我就在这里更新。

从EasyRTC报价来看:

  • 核心部分(服务器端和web端)开源,得到广泛使用和测试,起到市场效应,另外也节约了测试成本
  • 基于传统的软件销售策略,提供每服务器(限制最大1000聊天室)的价格($9,995 USD)
  • iOS和Android API也是包含在付费版本中
  • tawk.com的技术是EasyRTC提供的,如果用户需要,他们可帮助构建类似tawk的服务

EasyRTC的所属公司是Priologic,这是一家加拿大公司,位于加拿大西部温哥华岛的最南端维多利亚:

维多利亚人口只有8万人,风景不错的宜居旅游城市,离美国的西雅图很近。

安装、运行EasyRTC,跑通视频聊天环境

按照官网的安装说明EasyRTC: Server Installation,应该很容易安装好。

我在Ubuntu12.04以及Mac OSX 10.9.2下都可顺利将easyrtc/server_example/server.js跑起来:

你可以尝试,开两个浏览器窗口(建议Chrome,兼容性最好),或者和局域网内的同事一起玩儿。

再或者,你可以将EasyRTC server跑在公网的服务器上,邀请有摄像头的朋友一起玩儿,我测试了多个,基本成功。不成功的可能是网络问题,需要在EasyRTC基础上配置额外的TURN server。

使用EasyRTC编写文本消息聊天功能

以上可以作为使用者了解EasyRTC的功能。

EasyRTC提供了API,可以将WebRTC技术灵活的加入到自己的Web App中去。

搭建开发环境

要点是:

  • nodejs做web开发,一般用expressjs,EasyRTC是否能很好的融合进来,这个没有问题
  • EasyRTC底层通讯使用了Socket.io,EasyRTC的web app是否能部署在WebServer后面,应该是没有问题,见官方文档,提及了Apache和IIS,我使用的是Nginx,可以使用

搭建开发环境,我现在的一般做法是:

创建expressjs项目

我是通过命令行创建expressjs项目,然后在package.json文件中加入依赖包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
}
,

"dependencies": {
"express": "3.4.8",
"jade": "*",
"socket.io":"*",
"easyrtc":"*"
}

}

然后,在app.js中,将easyrtc的代码加进来就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

/**
* Module dependencies.
*/


var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');

//easyrtc
var io = require("socket.io");
var easyrtc = require("easyrtc");


var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}

app.get('/', routes.index);
app.get('/users', user.list);

var webServer = http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});


// easyrtc
// Start Socket.io so it attaches itself to Express server
var socketServer = io.listen(webServer, {"log level":1});

// Start EasyRTC server
var rtc = easyrtc.listen(app, socketServer);

如果跑起来没问题,应该能看到类似下面的日志:

info    - EasyRTC: Starting EasyRTC Server (v1.0.10) on Node (v0.10.24)
info    - EasyRTC: EasyRTC Server Ready For Connections (v1.0.10)

完整的源代码可见这里

最简单的文本聊天:基于Socket.io

为了验证环境搭建是否可用,参考官方示例里的Instant Messaging Demo,编写了个最简单(简陋)的聊天程序。

源代码见GitHub

将RtcDemos跑起来的步骤

clone下来后,安装步骤是:

安装nodejs所需库:

npm install

如果没有安装bower,需要安装一下(可能需要sudo):

sudo npm install -g bower

bower的用法,可参见我的另外一篇日志:使用CanJS编写Web前端应用

用它安装项目所需的js客户端库,比如jquery。

然后,需要:

bower install

好了,执行:

node app

然后访问:

http://localhost:8080/rtc_demos.html

可以看到一个列表,选择使用WebSocket文字聊天

我在公网上部署了一个示例,见使用WebSocket文字聊天

可能是因为Nginx配置问题,会在服务器端有个warn(当访问一次这个网页的时候):

warn  - websocket connection invalid

另外,在网页的Console中:

WebSocket connection to 'ws://rtc.shiqichan.com/socket.io/1/websocket/KzspKrHOIrCoMdLKrK1C' failed: Error during WebSocket handshake: Unexpected response code: 502 

但是这不影响使用:

以后有空查一下这个问题如何解决,毕竟有个报错不好。

找到原因了,会报错,是因为nginx版本比较低,1.1.x,不支持websocket的反向代理。

解决的办法是升级nginx到最新版本(目前是1.6.0)。具体修改办法见nginx官方install文档。我是ubuntu,使用的是Ubuntu PPA的办法。

另外,需要做配置:

location / {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://localhost:8080;
}

有关EasyRTC代码的简要说明

看一下源代码,就应该知道如何配置所需的类库了,主要是:

  • socket.io,easyrtc依赖它,在实际开发中不会直接使用到socket.io,都是通过easyrtc
  • easyrtc

步骤要点是:

  • 需要easyrtc.connect,让你的网页和服务器端连接,和其他javascript程序模式类似,需要有连接成功和失败的回调函数
  • 连接成功后,服务器会给你当前网页返回一个client id,以后你想call谁,需要用这个id,每次你刷新页面(重新加载web app)都会得到一个新的id
  • 如果你知道别人的client id,你就可以调用sendDataWS方法向它发送文本消息
  • 怎么知道别人给你发消息了?需要通过setPeerListener注册一个回调,在当别人给你发来消息时触发
  • 次要问题,room的概念,就是聊天室,一个页面(web app)可以加入多个room,而只有相同room的人才可以互发信息

基于WebRTC的data channel的文本聊天

实际上,上面的方法并没有使用到WebRTC的API,只不过是EasyRTC封装socket.io的一个功能。

我们可以使用WebRTC的Data Channel发送文本信息(实际上还可以发送视频、音频和二进制文件),比sendDataWS稍微复杂。

源代码见GitHub

你也可以直接访问我部署好的一个示例:使用WebRTC Data Channel文字聊天。和上文类似,也是会先出现一个报错,但是不影响使用。

使用技术的介绍

为了写这个示例,我用到了requirejscanjs,其实主要是canjs,主要是不想为页面交互写过多的jquery和dom代码。这可能会带来理解的障碍,好在CanJS并不难学习。

或者看我的另外一篇日志:使用CanJS编写Web前端应用,可能会有所帮助。

有关EasyRTC代码的简要说明

要点如下:

  • 上来还是要connect,成功了就可以得到服务器端分配的client id
  • 设置setRoomOccupantListener,这是个房客变化的监听器,也就是说谁加入或者退出都会触发它,它可以帮助我们重新构建可聊天人员的名单
  • 和上面示例不同,想通过Data Channel发送消息,还需要打开Data Channel,即调用call方法,这里再细说几点:
    • 上面示例,直接通过socket.io发送消息,消息经过服务器中转
    • 使用Data Channel则不同,EasyRTC作为signaling server,配合浏览器端WebRTC的P2P功能,建立了两个浏览器的直接通道,以后传输数据是P2P了,也就是点到点,不再经过服务器端
    • signaling server的基本功能是,它可知道两个浏览器的真正外网ip和端口,并互相告知,这样就可以建立P2P连接了
    • 不是所有的情况都可这样建立P2P连接,如果是这些情况(具体不展开说了),默认的EasyRTC server就无能为力了。如果还想建立浏览器之间的连接,需要在EasyRTC signaling server的配置中,增加TURN server的配置(可以是第三方的服务器,TURN是个标准,或者自己搭建一个)
    • 为什么不默认支持TURN,因为这时的P2P已经无法建立了,解决办法是数据通过服务器中转,这是个耗费带宽和计算资源的事情
  • call只是建立了连接,如果要传输文本数据,需要sendDataP2P
  • 当然还要有挂断的操作,就是关闭这个Data Channel,就是hangup方法
  • 和上文类似,setPeerListener可以让你收到对方发来的信息
  • setDataChannelOpenListenersetDataChannelCloseListener监听Data Channel的打开和关闭,来刷新界面的状态等
  • setRoomOccupantListener也是必不可少的,用于刷新聊天室内的用户列表

其实掌握上面的这些要点,加入音频和视频问题已经不大了,稍后我再给出有关这方面的说明。