- 例子程序出自:
https://github.com/opentok/opentok-android-sdk-samples/tree/master/Basic-Video-Chat
For all the girls I loved
1 2 3 4 5 6 7 8 9 10 11 12 |
this.addEventListener('load', function startApp() { LazyLoader.load([ '/js/libs/browser_utils.js', '/shared/js/utils.js', '/js/helpers/requests.js', '/js/roomController.js', '/js/landingController.js' ]).then(function () { RTCApp.init(); }); }); |
用 LazyLoader 启动了 5个 js 文件 , 之后 调用 RTCApp.init()
1 2 3 4 5 6 7 8 9 |
function init() { debug = new Utils.MultiLevelLogger('rtcApp.js', Utils.MultiLevelLogger.DEFAULT_LEVELS.all); var view = getView(); if (view) { view.init(); } else { debug.error('Couldn\'t find a view for ' + exports.document.location.pathname); } } |
其中 view.init(); 是调用具体view的 init 函数 ,对于 room来说就是 : roomController.js—–> init 函数。
在 roomController.js 的 init 函数 , 有
1 |
Utils.addEventsHandlers('roomStatus:', roomStatusHandlers, exports); |
参数中 roomStatusHandlers 是:
1 2 3 4 5 6 7 8 9 10 |
var roomStatusHandlers = { updatedRemotely: function () { publisherReady.then(function () { _sharedStatus = RoomStatus.get(STATUS_KEY); var roomMuted = _sharedStatus.roomMuted; setAudioStatus(roomMuted); roomMuted && Utils.sendEvent('roomController:roomMuted', { isJoining: true }); }); } }; |
调用的是 : browser_utils.js 的 addEventsHandlers 函数 :
1 2 3 4 5 6 |
var addEventsHandlers = function (eventPreffixName, handlers, target) { eventPreffixName = eventPreffixName || ''; Object.keys(handlers).forEach(function (eventName) { (target || exports).addEventListener(eventPreffixName + eventName, handlers[eventName]); }); }; |
in opentok-rtc project , use grunt to compile less into css .
Grunt 是一个插件化的打包工具, 比如编译 less的插件就是 grunt-contrib-less, 安装方法是 :
1 |
npm install grunt-contrib-less --save-dev |
安装之后还需要 Gruntfile.js 做配置文件 ,
Grunt的 get start 网址: https://gruntjs.com/getting-started
配置文件例子 : https://gruntjs.com/sample-gruntfile
从 opentok截取出来的一个简单的Gruntfile.js 例子 , 这里只用到了编译 less的插件
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 |
module.exports = function(grunt) { // To-Do check what we need and add/remove as needed... [ 'grunt-contrib-less' ].forEach(grunt.loadNpmTasks); grunt.loadTasks('tasks'); // To create HTML test files from a template. To-Do: Dunno if this is even needed or not var TEST_BASE_DIR = 'test/'; grunt.initConfig({ less: { default: { files: { 'myapp/public/stylesheets/landing.opentok.css': 'less/landing.less' } } }, }); // On watch events, if the changed file is a test file then configure mochaTest to only // run the tests from that file. Otherwise run all the tests grunt.registerTask('clientBuild', 'Build css files', [ 'less' ]); grunt.registerTask('initialConfig', [ 'clientBuild' ]); grunt.registerTask('default', ['clientBuild']); }; |
之后执行 grunt clientBuild 即可把 less 文件 编译为 css ,clientBuild 是自定义的任务名
在 opentok-rtc项目中, 还包括了 bower lib的引用 ,
in Gruntfile.js , it figure out where to find source less and where to store dest css , by :
1 2 3 4 5 6 7 8 9 10 11 12 |
less: { default: { files: { 'web/css/landing.opentok.css': 'web/less/landing.less', 'web/css/room.opentok.css': 'web/less/room.less', 'web/css/min.opentok.css': 'web/less/min.less', 'web/css/endMeeting.opentok.css': 'web/less/endMeeting.less', 'web/css/annotation.opentok.css': 'web/less/annotation.less', 'web/css/hangoutScroll.css': 'web/less/hangoutScroll.less' } } }, |
npm install bower –save
之后新建 bower.json
bower install
a)
这个是 image , 代码为:
1 2 3 |
<div class="icon-container"> <i data-icon="tokbox_logo"></i> </div> |
以data 开头的是 html5 新增的自定义属性, 可以是 data-whatever , 具体定义见 icons.less
b)
1 2 3 |
<div class="videoSwitch"> <a id="videoSwitch" class=""><i data-icon="videoSwitch"></i><span>Stop receiving video</span></a> </div> |
这个是相当于radio的按钮, 可通过点击 enable 或者 not , 用 js 实现 ,给 click 事件加 eventlistener , 从而在 class 加 activate 或者 去掉 , 示例代码:
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 |
var videoSwitch; videoSwitch = document.querySelector('.videoSwitch'); function setSwitchStatus(status, bubbleUp, domElem, evtName) { var oldStatus = domElem.classList.contains('activated'); var newStatus; if (status === undefined) { newStatus = domElem.classList.toggle('activated'); } else { newStatus = status; if (status) { domElem.classList.add('activated'); } else { domElem.classList.remove('activated'); } } //bubbleUp && newStatus !== oldStatus && Utils.sendEvent(evtName, { status: newStatus }); } videoSwitch.addEventListener('click', function () { if (!videoSwitch.classList.contains('activated')) { setSwitchStatus(true, true, videoSwitch, 'roomView:videoSwitch'); } else { setSwitchStatus(false, true, videoSwitch, 'roomView:videoSwitch'); } }); |
all css selector explains
https://www.w3schools.com/cssref/css_selectors.asp
1 : 用户可以用学生或者老师的身份登陆
a) 如果是老师 : 可以
进入自己发布过的session , 就是显示所有room
什么是自己的session ?
当用户以用户名登陆之后, 如果创建room, tokbox会在远端记录一个 session id , 但是不记录用户名, 所以, 将 session id 和 用户名连接起来是要实现的功能
不能把 session id 和用户名连一起, 因为tokbox网站明确说:
When possible, do not reuse session IDs between different video chat conversations. Instead, generate new session IDs for each distinct video chat on your application.
所以, 要存的是 username 和 room number的对应关系 , 还有 room template
存 username 和 room number的对应关系 , 用
1 |
<del>serverPersistence.setKey(aReq.body.email, JSON.stringify(aReq.body));</del> |
不对, 用 pushToKey , 因为 一个username可能有多个 room , 取时用 getKeyArray
但是 , archive 从属于 session , 如果要列出room 的archive,只能用 session id 查 , room number 和 session id 的对应关系 ,存在于 redis数据库\
b) 如果是学生, 能看到自己所有订阅 的room
redis查key :
1 |
redis-cli KEYS '*' |
查 key的 value
1 |
redis-cli -p 6379 GET otrtc_room__33 |
upload , del archive ,
invite student
enable or not student video or audio
share screen
white board
b) 如果是学生 , 可以
看到一个 所有 teacher 的 列表页面, 并选择进入room , 列表应表明此room的所有者是否正在线, 此room的当前在线人数 .
这就需要有一个函数能查询到所有的session ,以及session对应的room number,How To ?
https://github.com/opentok/opentok-node
如何用 node.js 写一个server , 包括如何创建 session , token , work with archive
https://github.com/opentok/opentok-web-samples
各种 web client sample, 包括angular js , vue 等
https://github.com/opentok/learning-opentok-node
学习如何用 node.js 写 server
From https://tokbox.com/developer/guides/create-session/
session 可以理解为一个room , 测试账号创建的session 是否有限制 ?
没有限制, 但是在tokbox的设计, 每个人应该只有一个 session
session 并不过期 , 也不能被显式销毁
OpenTok sessions do not expire. However, authentication tokens do expire. Also note that sessions cannot explicitly be destroyed.
用户是否可以有多个session ? No
archive 从属于 session ,
session 自带一些事件, 可以给这些事件设置回调, 比如统计room的在线人数
1 2 3 4 5 6 7 8 9 10 11 12 |
var session = OT.initSession(apiKey, sessionID); session.on('connectionCreated', function(e) { connectionCount++; ... }); session.on('connectionDestroyed', function(e) { connectionCount--; ... }); |
如果在 js 用 createSession 函数创建了session , 怎么取创建的session ID
room.ejs 是 https://github.com/opentok/opentok-rtc
此项目最重要的一个页面, 涉及到全部的api ,
a) room.ejs 有
1 2 3 4 5 6 7 8 |
<div> <button id="message-btn" disabled> <i data-icon="message"></i> </button> <p>Message <span id="unreadMsg">(<span id="unreadCount">0</span>)</span> </p> </div> |
然后
roomView.js
1 2 3 |
case 'message-btn': setChatStatus(!messageButtonElem.classList.contains('activated')); break; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function setChatStatus(visible) { if (visible) { _chatHasBeenShown = true; setUnreadMessages(0); messageButtonElem.classList.add('activated'); // hide call controls on small screens if (window.innerWidth <= 480) { hideCallControls(); } } else { messageButtonElem.classList.remove('activated'); } Utils.sendEvent('roomView:chatVisibility', visible); HTMLElems.flush('#toggleChat'); } |
这里应该着重理解 sendEvent这个函数,
当执行这句时: Utils.sendEvent(‘roomView:chatVisibility’, visible);
CSS 部分
1 2 3 4 5 |
<div id="top-banner"> <div class="icon-container"> <i data-icon="tokbox_logo"></i> </div> </div> |
也就是说, data- 后可以接自己定义的任何字符 , 参考文章:
https://johnresig.com/blog/html-5-data-attributes/
——-
in room.less :
1 2 3 4 5 6 7 8 9 10 |
[data-icon="tokbox_logo"] { background-image: url("/images/tokbox-nexmo-logo.svg"); width: 235px; height: 41px; @media @smartphonesPortrait { background-image: url("/images/tokbox-logo-bug.svg"); width: 27px; height: 27px; } } |
in
1 |
bower install --allow-root |
1 |
sudo npm install -g bower |
first new a “bowe.json” file ,which content is :
1 2 3 4 5 6 |
{ "name": "opentok-rtc", "dependencies": { "theme": "tef-components/theme#0.2.68" } } |
then , install and download bower
1 |
sudo npm install -g bower |
1 |
bower install --allow-root |
bower install mean install the package specified in bower.json , in this case , tokbox company use the package :
https://github.com/tef-components/
this package is a free less lib for button, theme, text-input , etc .
For how to learn less , see
https://www.tutorialspoint.com/less/nested_rules.htm
a beginner less introduce in Chinese :
https://www.tutorialspoint.com/less/nested_rules.htm
a) first , how to do a simple node.js server
https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd
更好的是直接去看 expressjs 的 hello world : https://expressjs.com/en/starter/hello-world.html
b) opentok-rtc ‘s server is made by swager-boilerplate , which address is :
https://github.com/AntonioMA/swagger-boilerplate
In this site , it say : Simple implementation of a Node Express server described using a Swagger API, in JSON form.
how to make a Node Express server is in point a)
for swagger , here is a introduce article :
https://mherman.org/blog/swagger-and-nodejs/
c) swagger-boilerplate 用到了 .yml 文件作为 rest server api 定义文件 , yml 文件2个空格代表一个层级, 多个键值对用 – 分开
swagger api 的在线编辑界面 http://editor.swagger.io/
如何做一个简单的 swagger api : https://www.blazemeter.com/blog/create-your-first-openapi-definition-with-swagger-editor/
d) 怎么返回具体的页面
1) 可以在 expressjs 的js 文件 用 sendFile 返回 html , 但这里不是
2) 注意到 package.json 有 “ejs”: “^2.5.5”
3) 实际使用 的方法是 res.render(
4) how to use expressjs and ejs :
https://scotch.io/tutorials/use-ejs-to-template-your-node-application
—
here is a example : https://mherman.org/blog/swagger-and-nodejs/
显示所有key :
1 |
redis-cli KEYS '*' |
对某一个key取value
1 |
redis-cli -p 6379 GET mzcw2011@sina.cn |
这里假定 邮箱是key , server 端口 6379
如何从 node.js 存到 redis server ?
在 serverMethods.js中, register的post方法 , 写:
1 |
serverPersistence.setKey(aReq.body.email, JSON.stringify(aReq.body.username)); |
server停止后 , redis 存进去的数据还在
删除
1 |
redis-cli -p 6379 DEL mzcw2011@sina.cn |
ServerPersistence 是这样被初始化的 :
1 2 3 4 5 6 7 |
var ServerPersistence = SwaggerBP.ServerPersistence; var connectionString = (aModules && aModules.params && aModules.params.persistenceConfig) || env.REDIS_URL || env.REDISTOGO_URL || ''; //logger.log('connection string is ' + connectionString); var serverPersistence = new ServerPersistence([], connectionString, aLogLevel, aModules); |
SwaggerBP是从这里
var SwaggerBP = require(‘swagger-boilerplate’);
room 相关的 api 接口
getRoomArchive ——– 得到room 的所有 archive , 用 roomname 做参数
url 为 : https://47.52.61.15:8123/room/111/archive
首先, archive存在哪里 ?
archive 可以被保存的前提是 :
Important: You can only archive sessions that use the OpenTok Media Router (sessions with the media mode set to routed).
就是说只有特定类型的session, 它的archive 才可以被保存 。
如果配置了微软云或者亚马逊云, 会存到配置 ; 如果没有, 会存到 tokbox云, 只保存72小时 。
用户是否只能 record live stream as archive , 能不能上传录制好的视频
getroom 是建立一个临时的session , 以测试用户的音视频连接
getroominfo 是在 persistent store 查询房间号, 如果有, 进入
getUsableSessionInfo. 函数按房间号查询session, 如果没有, 创建新的
opentok 账号
mzcw2011@sina.cn
Passw0rd77#
api key 46419702
project secret : b8f17a054ccde74e68453464ad6b1c879a75d030
环境 win10 64 位
a) node.js , 已安装 , 64位的
b) Redis
在这里下载 3.2.100 的 zip 版本 并启动 : https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
a) 从这里 clone : https://github.com/opentok/opentok-rtc
首先进入 config 文件夹, 修改 config-ci.json 为 :
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 |
{ "showTos": false, "OpenTok":{ "apiKey": "46419702", "apiSecret": "b8f17a054ccde74e68453464ad6b1c879a75d030" }, "Archiving":{ "enabled":false, "archiveManager":{ "enabled":false } }, "Feedback":{ "enabled":false }, "Screensharing":{ "enabled":true, "chromeExtensionId":"test", "annotations":{ "enabled":true } }, "SIP": { "enabled": false, "uri": "sip:test@sip.test.com", "username": "test", "password": "test", "requireGoogleAuth": false } } |
这里的apikey和 apisecret改成自己的
b) 不知道是否还需要安装python, 好像是需要的,因为本机已有,未测试
c) npm 安装package : 进入程序主目录执行
1 |
npm install |
d) 启动服务端, 记得redis要先启动
而且,启动 redis server 之后, 再启动 redis-cli , 并增加2个键
1 2 |
set tb_api_key 46419702 set tb_api_secret b8f17a054ccde74e68453464ad6b1c879a75d030 |
然后启动 server
1 |
node server |
—————— 在 ubuntu 的安装
apt install git
git clone https://github.com/opentok/opentok-rtc.git
apt install nodejs
apt install redis-server
设置redis-server为服务 :
1 2 |
<del>sudo systemctl enable redis-server.service </del> |
此后要注意 redis 的权限问题, redis 服务的配置文件在 /etc/redis/redis.conf
其中写到 : pidfile /var/run/redis/redis-server.pid
新开一个 putty , 输入 : redis-server
回到原来的putty , 进入下载好的 opentok-rtc/config 目录 , 复制 example.json , 重命名为 config.json , 并编辑修改 key 和 secret ,改为自己的 ,
安装 npm
apt install npm
在 opentok-rtc 跟目录下, 执行 npm install
安装所有package 之后, 执行 node server 启动服务器
此时访问 ip:8123 应该可以看到页面了, 但是, 发现css没起作用 ,
a) 安装 less
apt install node-less
b) 安装 bower
1 |
sudo npm install -g bower |
执行 bower install –allow-root
c) 安装 grunt
sudo npm install -g grunt
此处要注意, 在 ali ubuntu主机, 如果 npm install grunt –save-dev , 会失败,不知道为什么
安装之后 , 在跟目录执行 grunt clientBuild , 会把 less 生成对应的 css
第一步 , 修改 opentok-rtc-master\screen-sharing-extension-chrome\manifest.json 文件 的这一部分 , 改为 :
1 2 3 4 5 |
"content_scripts": [ { "matches": ["<all_urls>"], "js": [ "content-script.js" ], "all_frames": true }], |
第二步, 进入 chrome://extensions/ , 开 developer mode 开光, 选 左上角 load unpacked , 然后选中 整个 screen-sharing-extension-chrome 目录
第三步, 修改 服务器 /config/config.json 文件 , 将 screen – sharing 部分改为
1 2 3 4 5 6 7 |
"Screensharing":{ "enabled":true, "chromeExtensionId": "eifdenegdphapilkmbpdbgenhanlbdad", "annotations":{ "enabled":true } }, |
chromeExtensionId 是客户端 加载 extension之后产生的, 也在 chrome:/extension能看到
最后启动服务, room 会多出一个 screen-share的选项 。