李勇

Merge branch 'mcuClientBranch'

要显示太多修改。

为保证性能只显示 36 of 36+ 个文件。

此 diff 太大无法显示。
root: true
env:
es6: true
node: true
browser: true
mocha: true
ecmaFeatures:
modules: true
extends:
"airbnb"
rules:
quotes: 0
func-names: 0
comma-dangle: 0
no-new-func: 0
no-eq-null: 0
no-param-reassign: 0
... ...
.DS_Store
*.log
node_modules
src
test
examples
coverage
... ...
language: node_js
node_js:
- "iojs"
... ...
1.0.6 / 2017-2-3
==================
* update typescript config
1.0.5 / 2016-12-29
==================
* update typescript support
1.0.4 / 2016-12-23
==================
* add typescript support
1.0.3 / 2016-12-04
==================
* add examples index-ie8.html
* remove `es6-promise` dependent
1.0.2 / 2016-09-26
==================
* Use original url when Request error
1.0.1 / 2016-08-14
==================
* Format code
* Update Readme
1.0.0 / 2015-11-19
==================
* Remove Bower support
* Add jsonpCallback and jsonpCallbackFunction as options
0.9.2 / 2015-08-11
==================
* Remove global export of fetchJsonp
0.9.1 / 2015-08-11
==================
* Update removeScript fix legacy IE
... ...
# Maintaining
## Releasing a new version
This project follows [semver](http://semver.org/). So if you are making a bug
fix, only increment the patch level "1.0.x". If any new files are added, a
minor version "1.x.x" bump is in order.
### Make a release commit
To prepare the release commit:
1. Change the npm [package.json](https://github.com/camsong/fetch-jsonp/blob/master/package.json)
`version` value to match.
2. Make a single commit with the description as "Fetch JSONP 1.x.x".
3. Finally, tag the commit with `v1.x.x`.
```
$ git pull
$ vim package.json
$ git add package.json
$ git commit -m "Fetch JSONP 1.x.x"
$ git tag v1.x.x
$ git push
$ git push --tags
```
... ...
# Fetch JSONP [![Build Status](https://travis-ci.org/camsong/fetch-jsonp.svg)](https://travis-ci.org/camsong/fetch-jsonp) [![npm version](https://badge.fury.io/js/fetch-jsonp.svg)](http://badge.fury.io/js/fetch-jsonp) [![npm downloads](https://img.shields.io/npm/dm/fetch-jsonp.svg?style=flat-square)](https://www.npmjs.com/package/fetch-jsonp)
JSONP is NOT supported in standard Fetch API, https://fetch.spec.whatwg.org.
fetch-jsonp provides you same API to fetch JSONP like naive Fetch, also comes
with global `fetchJsonp` function.
If you need a `fetch` polyfill for old browsers, try [github/fetch](http://github.com/github/fetch).
## Installation
You can install with `npm`.
```
npm install fetch-jsonp
```
## Promise Polyfill for IE
IE8/9/10/11 does not support [ES6 Promise](https://tc39.github.io/ecma262/#sec-promise-constructor), run this to polyfill the global environment at the beginning of your application.
```js
require('es6-promise').polyfill();
```
## Usage
The `fetch-jsonp` function supports any HTTP method. We'll focus on GET and POST
example requests.
### Fetch JSONP in simple way
```javascript
fetchJsonp('/users.jsonp')
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
```
### Set JSONP callback name, default is 'callback'
```javascript
fetchJsonp('/users.jsonp', {
jsonpCallback: 'custom_callback'
})
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
```
### Set JSONP request timeout, default is 5000ms
```javascript
fetchJsonp('/users.jsonp', {
timeout: 3000,
jsonpCallback: 'custom_callback'
})
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
```
### Caveats
You need to call `.then(function(response) { return response.json(); })` in order
to keep consistent with Fetch API.
## Browser Support
![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png)
--- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | 8+ ✔ | Latest ✔ | 6.1+ ✔ |
# License
MIT
# Acknowledgement
Thanks to [github/fetch](https://github.com/github/fetch) for bring Fetch to old browsers.
... ...
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports', 'module'], factory);
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
factory(exports, module);
} else {
var mod = {
exports: {}
};
factory(mod.exports, mod);
global.fetchJsonp = mod.exports;
}
})(this, function (exports, module) {
'use strict';
var defaultOptions = {
timeout: 5000,
jsonpCallback: 'callback',
jsonpCallbackFunction: null
};
function generateCallbackFunction() {
return 'jsonp_' + Date.now() + '_' + Math.ceil(Math.random() * 100000);
}
// Known issue: Will throw 'Uncaught ReferenceError: callback_*** is not defined'
// error if request timeout
function clearFunction(functionName) {
// IE8 throws an exception when you try to delete a property on window
// http://stackoverflow.com/a/1824228/751089
try {
delete window[functionName];
} catch (e) {
window[functionName] = undefined;
}
}
function removeScript(scriptId) {
var script = document.getElementById(scriptId);
document.getElementsByTagName('head')[0].removeChild(script);
}
function fetchJsonp(_url) {
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
// to avoid param reassign
var url = _url;
var timeout = options.timeout || defaultOptions.timeout;
var jsonpCallback = options.jsonpCallback || defaultOptions.jsonpCallback;
var timeoutId = undefined;
return new Promise(function (resolve, reject) {
var callbackFunction = options.jsonpCallbackFunction || generateCallbackFunction();
var scriptId = jsonpCallback + '_' + callbackFunction;
window[callbackFunction] = function (response) {
resolve({
ok: true,
// keep consistent with fetch API
json: function json() {
return Promise.resolve(response);
}
});
if (timeoutId) clearTimeout(timeoutId);
removeScript(scriptId);
clearFunction(callbackFunction);
};
// Check if the user set their own params, and if not add a ? to start a list of params
url += url.indexOf('?') === -1 ? '?' : '&';
var jsonpScript = document.createElement('script');
jsonpScript.setAttribute('src', '' + url + jsonpCallback + '=' + callbackFunction);
jsonpScript.id = scriptId;
document.getElementsByTagName('head')[0].appendChild(jsonpScript);
timeoutId = setTimeout(function () {
reject(new Error('JSONP request to ' + _url + ' timed out'));
clearFunction(callbackFunction);
removeScript(scriptId);
}, timeout);
});
}
// export as global function
/*
let local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof self !== 'undefined') {
local = self;
} else {
try {
local = Function('return this')();
} catch (e) {
throw new Error('polyfill failed because global object is unavailable in this environment');
}
}
local.fetchJsonp = fetchJsonp;
*/
module.exports = fetchJsonp;
});
\ No newline at end of file
... ...
declare function fetchJsonp(url: string, options?: fetchJsonp.Options): Promise<fetchJsonp.Response>;
declare namespace fetchJsonp {
interface Options {
timeout?: number;
jsonpCallback?: string;
jsonpCallbackFunction?: string;
}
interface Response {
json(): Promise<any>;
json<T>(): Promise<T>;
ok: boolean;
}
}
export = fetchJsonp;
... ...
{
"_args": [
[
"fetch-jsonp",
"D:\\work\\McuClient"
]
],
"_from": "fetch-jsonp@latest",
"_id": "fetch-jsonp@1.0.6",
"_inCache": true,
"_installable": true,
"_location": "/fetch-jsonp",
"_nodeVersion": "5.7.1",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/fetch-jsonp-1.0.6.tgz_1486087842804_0.46444737794809043"
},
"_npmUser": {
"email": "neosoyn@gmail.com",
"name": "camsong"
},
"_npmVersion": "3.6.0",
"_phantomChildren": {},
"_requested": {
"name": "fetch-jsonp",
"raw": "fetch-jsonp",
"rawSpec": "",
"scope": null,
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/fetch-jsonp/-/fetch-jsonp-1.0.6.tgz",
"_shasum": "8d2ae174ed14108292f025f43fa07d2078de6736",
"_shrinkwrap": null,
"_spec": "fetch-jsonp",
"_where": "D:\\work\\McuClient",
"author": {
"name": "Cam Song"
},
"bugs": {
"url": "https://github.com/camsong/fetch-jsonp/issues"
},
"dependencies": {},
"description": "Fetch JSONP like a boss using Fetch API",
"devDependencies": {
"babel": "^5.8.21",
"babel-core": "^5.8.21",
"babel-eslint": "^4.0.5",
"chai": "^3.2.0",
"eslint": "^1.1.0",
"eslint-config-airbnb": "^0.0.7",
"eslint-plugin-react": "^3.2.1",
"mocha": "^2.2.5"
},
"directories": {},
"dist": {
"shasum": "8d2ae174ed14108292f025f43fa07d2078de6736",
"tarball": "https://registry.npmjs.org/fetch-jsonp/-/fetch-jsonp-1.0.6.tgz"
},
"gitHead": "3b1be53776fa36a548fbf2aa16063c27ca318661",
"homepage": "https://github.com/camsong/fetch-jsonp#readme",
"keywords": [
"fetch",
"jsonp",
"github fetch",
"ajax"
],
"license": "MIT",
"main": "build/fetch-jsonp.js",
"maintainers": [
{
"email": "neosoyn@gmail.com",
"name": "camsong"
}
],
"name": "fetch-jsonp",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/camsong/fetch-jsonp.git"
},
"scripts": {
"build": "babel src/ --modules umd --out-dir build",
"clean": "rm -rf build",
"lint": "eslint src/ test/",
"test": "mocha --compilers js:babel/register --recursive --ui bdd --reporter spec"
},
"version": "1.0.6"
}
... ...
# exclude all
/*
# project structure
!/src/
!/etc/
!/doc/
!/test/
!/dist/
# project files
!.gitignore
!README.md
!package.json
!LICENSE
!webpack.config.umd.js
... ...
iphunter
to hunt a fatest http response.
# usage
iphunter(iplist,check_call_back[,timeout]);
```javascript
import iphunter from 'iphunter';
iphunter([
'192.168.99.199',
'baidu.com',
'aliyun.com',
'qq.com',
'192.168.99.100',
'127.0.0.0:8080',
'192.168.1.48:8080',
'localhost:8080'
], function (fatest_ip_response) {
if(!fatest_ip_response) return console.error('nothing!');
console.log('done -> ', fatest_ip_response);
},3000)
```
... ...
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>UMD PLAYGROUND</title></head><body><div id="stage"></div><script type="text/javascript" src="main.js"></script></body></html>
\ No newline at end of file
... ...
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.iphunter=t():e.iphunter=t()}(this,function(){return function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3;if(!(e&&e.length&&t))throw new Error("ips and callback are required.");new o(e,t,n)}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();t.default=i;var o=function(){function e(t,i,r){n(this,e),this.ip="",this.ipcallback=i,this.timeoutId=null,this.reqsCache=[];for(var o=0;o<t.length;o++)this.reqsCache.push(this.send(t[o],r-10));this.timeoutId=setTimeout(this.notify.bind(this),r)}return r(e,[{key:"clearAll",value:function(){this.reqsCache&&this.reqsCache.length&&this.reqsCache.forEach(function(e){e.abort()}),clearTimeout(this.timeoutId),this.ip="",this.ipcallback=null,this.timeoutId=null,this.reqsCache=[]}},{key:"clearReq",value:function(e){this.reqsCache.splice(this.reqsCache.indexOf(e),1)}},{key:"notify",value:function(){this.ipcallback(this.ip),this.clearAll()}},{key:"send",value:function(e,t){var n=this,i=new XMLHttpRequest;return i.open("HEAD","//"+e+"/?_="+Date.now()),i.timeout=t,i.onload=function(){n.ip=e,n.clearReq(i),i.onload=null,n.notify()},i.ontimeout=function(){n.clearReq(i),i.ontimeout=null},i.onerror=function(){n.clearReq(i),i.onerror=null},i.onabort=function(){n.clearReq(i),i.onabort=null},i.send(),i}}]),e}();(function(){"undefined"!=typeof __REACT_HOT_LOADER__&&(__REACT_HOT_LOADER__.register(o,"IpHunter","/Users/AlexWang/ws/iphunter/src/main.js"),__REACT_HOT_LOADER__.register(i,"check","/Users/AlexWang/ws/iphunter/src/main.js"))})()}])});
\ No newline at end of file
... ...
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>UMD PLAYGROUND</title></head><body><div id="stage"></div><script type="text/javascript" src="test.js"></script></body></html>
\ No newline at end of file
... ...
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.iphunter=t():e.iphunter=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(2)},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3;if(!(e&&e.length&&t))throw new Error("ips and callback are required.");new r(e,t,n)}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}();t.default=o;var r=function(){function e(t,o,i){n(this,e),this.ip="",this.ipcallback=o,this.timeoutId=null,this.reqsCache=[];for(var r=0;r<t.length;r++)this.reqsCache.push(this.send(t[r],i-10));this.timeoutId=setTimeout(this.notify.bind(this),i)}return i(e,[{key:"clearAll",value:function(){this.reqsCache&&this.reqsCache.length&&this.reqsCache.forEach(function(e){e.abort()}),clearTimeout(this.timeoutId),this.ip="",this.ipcallback=null,this.timeoutId=null,this.reqsCache=[]}},{key:"clearReq",value:function(e){this.reqsCache.splice(this.reqsCache.indexOf(e),1)}},{key:"notify",value:function(){this.ipcallback(this.ip),this.clearAll()}},{key:"send",value:function(e,t){var n=this,o=new XMLHttpRequest;return o.open("HEAD","//"+e+"/?_="+Date.now()),o.timeout=t,o.onload=function(){n.ip=e,n.clearReq(o),o.onload=null,n.notify()},o.ontimeout=function(){n.clearReq(o),o.ontimeout=null},o.onerror=function(){n.clearReq(o),o.onerror=null},o.onabort=function(){n.clearReq(o),o.onabort=null},o.send(),o}}]),e}();(function(){"undefined"!=typeof __REACT_HOT_LOADER__&&(__REACT_HOT_LOADER__.register(r,"IpHunter","/Users/AlexWang/ws/iphunter/src/main.js"),__REACT_HOT_LOADER__.register(o,"check","/Users/AlexWang/ws/iphunter/src/main.js"))})()},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}var i=n(1),r=o(i);(0,r.default)(["192.168.99.199","baidu.com","aliyun.com","qq.com","192.168.99.100","127.0.0.0:8080","192.168.1.48:8080","localhost:8080"],function(e){console.log("done -> ",e)});(function(){"undefined"==typeof __REACT_HOT_LOADER__})()}])});
\ No newline at end of file
... ...
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>UMD PLAYGROUND</title>
</head>
<body>
<div id="stage"></div>
</body>
</html>
... ...
{
"_args": [
[
"iphunter",
"D:\\work\\McuClient"
]
],
"_from": "iphunter@latest",
"_id": "iphunter@1.0.6",
"_inCache": true,
"_installable": true,
"_location": "/iphunter",
"_nodeVersion": "6.9.1",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/iphunter-1.0.6.tgz_1488779370023_0.8911087329033762"
},
"_npmUser": {
"email": "1669499355@qq.com",
"name": "xinwangwang"
},
"_npmVersion": "3.10.8",
"_phantomChildren": {},
"_requested": {
"name": "iphunter",
"raw": "iphunter",
"rawSpec": "",
"scope": null,
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/iphunter/-/iphunter-1.0.6.tgz",
"_shasum": "6b7559d73002bd8cc93d558a604d64518d180840",
"_shrinkwrap": null,
"_spec": "iphunter",
"_where": "D:\\work\\McuClient",
"author": {
"name": "AlexWang"
},
"dependencies": {},
"description": "to hunt a fatest http response.",
"devDependencies": {},
"directories": {
"doc": "doc",
"test": "test"
},
"dist": {
"shasum": "6b7559d73002bd8cc93d558a604d64518d180840",
"tarball": "https://registry.npmjs.org/iphunter/-/iphunter-1.0.6.tgz"
},
"gitHead": "c9958f825f514736bd0451f632c227db4bf0a7b7",
"keywords": [
"ipcheck"
],
"license": "MIT",
"main": "dist/main.js",
"maintainers": [
{
"email": "1669499355@qq.com",
"name": "xinwangwang"
}
],
"name": "iphunter",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"scripts": {
"test": "test/index.js"
},
"version": "1.0.6",
"wbp": {
"build": "dist/",
"entries": {
"main": "./src/main.js",
"test": "./test/test.js"
},
"project": "umd",
"source": "src/"
}
}
... ...
class IpHunter {
constructor(ips, callback, timeout) {
this.ip = '';
this.ipcallback = callback;
this.timeoutId = null;
this.reqsCache = [];
for (let i = 0; i < ips.length; i++) {
this.reqsCache.push(this.send(ips[i], timeout - 10));
}
this.timeoutId = setTimeout(this.notify.bind(this), timeout);
}
clearAll() {
if (this.reqsCache && this.reqsCache.length) {
this.reqsCache.forEach((req) => {
req.abort();
})
}
clearTimeout(this.timeoutId);
this.ip = '';
this.ipcallback = null;
this.timeoutId = null;
this.reqsCache = [];
}
clearReq(req) {
this.reqsCache.splice(this.reqsCache.indexOf(req), 1);
}
notify() {
this.ipcallback(this.ip);
this.clearAll();
}
send(pip, timeout) {
const req = new XMLHttpRequest();
req.open('HEAD', `//${pip}/?_=${Date.now()}`);
req.timeout = timeout;
req.onload = () => {
this.ip = pip;
this.clearReq(req);
req.onload = null;
this.notify();
}
req.ontimeout = () => {
this.clearReq(req);
req.ontimeout = null;
}
req.onerror = () => {
this.clearReq(req);
req.onerror = null;
}
req.onabort = () => {
this.clearReq(req);
req.onabort = null;
}
req.send();
return req
}
}
/**
* ips check
* @param {array} ips
* @param {number} callback
* @return {null}
*/
export default function check(ips, callback, timeout = 3000) {
if (!(ips && ips.length && callback)) throw new Error('ips and callback are required.');
new IpHunter(ips, callback, timeout);
}
... ...
import check from 'main.js';
check([
'192.168.99.199',
'baidu.com',
'aliyun.com',
'qq.com',
'192.168.99.100',
'127.0.0.0:8080',
'192.168.1.48:8080',
'localhost:8080'
], function (ip) {
console.log('done -> ', ip);
})
... ...
module.exports = function (umdConf) {
umdConf.devServer.host = '0.0.0.0';
umdConf.webpackFeatures.enableEntryHTML();
umdConf.output.publicPath = '';
if (umdConf.devMode) {
umdConf.webpackFeatures.enableEntryHot('test');
} else {
umdConf.webpackFeatures.enableUglifyJs({
comments: false
});
}
// console.log(umdConf);
};
... ...
... ... @@ -23,13 +23,13 @@ export default class Emiter {
}
}
}
_emit(eid, data) {
_emit(eid, data,data2) {
if (eid) {
//eid=* broadcast
let asteriskStub =this.MAPS['*'];
if (asteriskStub && asteriskStub.length) {
asteriskStub.forEach(function (elistener) {
elistener(eid, data);
elistener(eid, data,data2);
})
}
... ... @@ -37,7 +37,7 @@ export default class Emiter {
let stub = this.MAPS[eid];
if (stub && stub.length) {
stub.forEach(function (elistener) {
elistener(data);
elistener(data,data2);
});
}
}
... ...
... ... @@ -5,6 +5,9 @@ require('string.fromcodepoint');
import Emiter from './Emiter';
import Sass from 'Sass';
import ServerCheck from 'ServerCheck';
import RecordPlayBackParse from 'RecordPlayBackParse';
import MD5 from "md5";
import Mcu from 'mcu';
import MessageTypes from 'MessageTypes';
import Loger from 'Loger';
... ... @@ -19,29 +22,23 @@ import GlobalConfig from 'GlobalConfig';
import ApeConsts from 'apes/ApeConsts';
import Base64 from 'base64-js';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import UTF8 from 'utf-8';
let loger = Loger.getLoger('MessageEntrance');
let _sdkInfo={"version":"v.1.0.1","author":"www.3mang.com"};
let _sdkInfo = {"version": "v.1.8.0.20170314-1", "author": "www.3mang.com"};
//APE
let _sass;
let _mcu ;
let _serverCheck;
let _mcu;
let _confer_ape;
let _chat_ape;
let _video_ape;
let _audio_ape;
let _doc_ape;
let _whiteboard_ape;
////初始化成功回调函数
//let _initSuccessCallBackFun;
//
////加入会议成功回调函数
//let _joinClassSuccessCallBackFun;
//
////监听mcu所有错误异常回调函数
//let _mcuErrorCallBackFun;
let _parseBuf;
//MCUClient 外部实例化主类
export default class MessageEntrance extends Emiter {
... ... @@ -61,27 +58,38 @@ export default class MessageEntrance extends Emiter {
_sass = Sass;
_sass.on('*', (type, data) => this._emit(type, data));
_sass.on(_sass.SUCCESS, this._sassJoinSuccessHandler.bind(this));//通过SASS平台验证(密码和MD5)
_sass.on(_sass.CLASS_INIT_SUCCESS, this._sassInitSuccessHandler.bind(this));//获取会议初始化信息
_sass.on(_sass.CLASS_GET_CLASS_DETAIL, this._sassGetClassDetailSuccessHandler.bind(this));//获取会议的基本信息
_sass.on(_sass.CLASS_GET_CLASS_PARAM, this._sassGetClassParamSuccessHandler.bind(this));//获取会议的最全信息和历史保存的数据
_sass.on(_sass.CLASS_SAVE_STATUS_INFO_SUCCESS, this._sassSaveClassStatusInfoSuccessHandler.bind(this));//保存会议状态信息
_sass.on(_sass.CLASS_SAVE_RECORD_INFO_SUCCESS, this._sassSaveClassRecordInfoSuccessHandler.bind(this));//保存会议录制信息
_sass.on(_sass.CLASS_INIT_SUCCESS, this._sassInitSuccessHandler.bind(this));//获取课堂初始化信息
//_sass.on(_sass.CLASS_GET_CLASS_DETAIL, this._sassGetClassDetailSuccessHandler.bind(this));//获取课堂的基本信息
_sass.on(_sass.CLASS_GET_CLASS_PARAM, this._sassGetClassParamSuccessHandler.bind(this));//获取课堂的最全信息和历史保存的数据
_sass.on(_sass.CLASS_SAVE_STATUS_INFO_SUCCESS, this._sassSaveClassStatusInfoSuccessHandler.bind(this));//保存课堂状态信息
_sass.on(_sass.CLASS_SAVE_RECORD_INFO_SUCCESS, this._sassSaveClassRecordInfoSuccessHandler.bind(this));//保存课堂录制信息
_sass.on(_sass.DELETE_DOCUMENT_SUCCESS, this._sassDeleteDocumentSuccess.bind(this));//sass删除文档成功
//ServerCheck ip
_serverCheck = ServerCheck;
_serverCheck.on(_serverCheck.SEVER_CHECK_BEST_IP_SUCCESS, this._serverCheckBestIpSuccessHandler.bind(this));//ip选点,获取最佳ip完成
// 底层MCU消息层
_mcu = Mcu;
_mcu.on('*', (type, data) => this._emit(type, data));
_mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuJoinMCUClassSuccessHandler.bind(this));//加入MCU会议完成
_mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuJoinMCUClassSuccessHandler.bind(this));//加入MCU课堂完成
//录制回放
_parseBuf = RecordPlayBackParse;
_parseBuf.on('*', (type, data) => this._emit(type, data));
_parseBuf.on(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, this._joinRecordPlaybackSuccessHandler.bind(this));//加入录制回放完成
// 注册所有应用Ape
_confer_ape = new ConferApe();
_confer_ape.on('*', (type, data) => this._emit(type, data));
_confer_ape.on(MessageTypes.CLASS_EXIT, this._doClassExit.bind(this));//监听自己的关闭事件
_confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前会议状态信息发生改变
_confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前会议人员离开
_confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER,this._onClassNonentityRoster.bind(this));//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在
_confer_ape.on(MessageTypes.CLASS_RECORD_START,this._onClassRecordStart.bind(this));//会议开始录制
_confer_ape.on(MessageTypes.CLASS_STATUS_INFO_CHANGE, this._onClassStatusInfoChange.bind(this));//当前课堂状态信息发生改变
_confer_ape.on(MessageTypes.CLASS_DELETE_ROSTER, this._onClassDeleteRoster.bind(this));//当前课堂人员离开
_confer_ape.on(MessageTypes.CLASS_NONENTITY_ROSTER, this._onClassNonentityRoster.bind(this));//当前课堂中视频或音频占用channel的nodeId ,在人员列表中不存在
_confer_ape.on(MessageTypes.CLASS_RECORD_START, this._onClassRecordStart.bind(this));//课堂开始录制
_chat_ape = new ChatApe();
... ... @@ -89,11 +97,12 @@ export default class MessageEntrance extends Emiter {
_video_ape = new VideoApe();
_video_ape.on('*', (type, data) => this._emit(type, data));
//_video_ape.on(MessageTypes.VIDEO_UPDATE, this.videoUpdate.bind(this));
_video_ape.on(MessageTypes.VIDEO_UPDATE, this.videoUpdate.bind(this));//这个监听事件不能删除,需要通知课堂模块,检查channel占用
_audio_ape= new AudioApe();
_audio_ape = new AudioApe();
_audio_ape.on('*', (type, data) => this._emit(type, data));
//_audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this));
_audio_ape.on(MessageTypes.AUDIO_UPDATE, this.audioUpdate.bind(this));//这个监听事件不能删除,需要通知课堂模块,检查channel占用
_whiteboard_ape = new WhiteBoardApe();
_whiteboard_ape.on('*', (type, data) => this._emit(type, data));
... ... @@ -105,8 +114,6 @@ export default class MessageEntrance extends Emiter {
_doc_ape.on(MessageTypes.DOC_DELETE, this.docDeleteHandler.bind(this));
_doc_ape.on(DocApe.DOC_JOIN_CHANNEL_SUCCESS, this.docJoinChannelSuccess.bind(this));
//公开外部调用的方法
//class
this.init = this._init.bind(this);
... ... @@ -119,24 +126,32 @@ export default class MessageEntrance extends Emiter {
this.sendPauseClass = this._sendPauseClass.bind(this);
this.sendCloseClass = this._sendCloseClass.bind(this);
//录制回放
this.initRecordPlayback = this._initRecordPlayback.bind(this);
this.startRecordPlayback = this._startRecordPlayback.bind(this);
this.stopRecordPlayback = this._stopRecordPlayback.bind(this);
this.pauseRecordPlayback = this._pauseRecordPlayback.bind(this);
this.seekRecordPlayback = this._seekRecordPlayback.bind(this);
//chatApe
this.sendChatMsg = this._sendChatMsg.bind(this);
//videoApe
this.getVideoPlayPath = this._getVideoPlayPath.bind(this);
//this.getVideoPlayPath = this._getVideoPlayPath.bind(this);
this.getVideoPublishPath = this._getVideoPublishPath.bind(this);
this.getVideoAllChannelInfo = this._getVideoAllChannelInfo.bind(this);
this.publishVideo = this._publishVideo.bind(this);
this.stopPublishVideo = this._stopPublishVideo.bind(this);
this.sendVideoBroadcastMsg=this._sendVideoBroadcastMsg.bind(this);
this.sendVideoBroadcastMsg = this._sendVideoBroadcastMsg.bind(this);
//audioApe
this.getAudioPlayPath = this._getPlayAudioPath.bind(this);
//this.getAudioPlayPath = this._getPlayAudioPath.bind(this);
this.getAudioPublishPath = this._getPublishAudioPath.bind(this);
this.getAudioAllChannelInfo = this._getAudioAllChannelInfo.bind(this);
this.publishAudio = this._publishAudio.bind(this);
this.stopPublishAudio = this._stopPublishAudio.bind(this);
this.sendAudioBroadcastMsg=this.sendAudioCommandMsg.bind(this);
this.sendAudioBroadcastMsg = this.sendAudioCommandMsg.bind(this);
//whiteBoradApe
this.sendInsertAnnotaion = this._sendInsertAnnotaion.bind(this);
... ... @@ -146,16 +161,19 @@ export default class MessageEntrance extends Emiter {
this.sendGotoPrev = this._sendGotoPrev.bind(this);
//DocApe
this.sendDocumentUpload = this._sendDocumentUpload.bind(this);;//上传文档
this.sendDocumentSwitchDoc = this._sendDocumentSwitchDoc.bind(this);; //切换文档
this.sendDocumentSwitchPage = this._sendDocumentSwitchPage.bind(this);;//翻页
this.sendDocumentDelete = this._sassDeleteDocument.bind(this);;//删除文档,先通过Sass删除,sass删除成功之后再同步mcu
this.sendDocumentUpload = this._sendDocumentUpload.bind(this);//上传文档
this.sendDocumentSwitchDoc = this._sendDocumentSwitchDoc.bind(this); //切换文档
this.sendDocumentSwitchPage = this._sendDocumentSwitchPage.bind(this);//翻页
this.sendDocumentDelete = this._sassDeleteDocument.bind(this);
//删除文档,先通过Sass删除,sass删除成功之后再同步mcu
//this.sendDocumentDeleteAll= this._documentDeleteAll;//删除所有文档
this.sendDocumentCommand = this._sendDocumentCommand.bind(this);;//操作文档(翻页、缩放、滚动...)
this.getDocImageFullPath=this._getDocImageFullPath.bind(this);;//获取文档图片的完整路径
this.getDocPDFFullPath=this._getDocPDFFullPath.bind(this);;//获取文档的完整路径
}
this.sendDocumentCommand = this._sendDocumentCommand.bind(this);
//操作文档(翻页、缩放、滚动...)
this.getDocImageFullPath = this._getDocImageFullPath.bind(this);
//获取文档图片的完整路径
this.getDocPDFFullPath = this._getDocPDFFullPath.bind(this);//获取文档的完整路径
}
//mcu异常监听
_mcuErrorHandler(_data, _option) {
... ... @@ -163,9 +181,9 @@ export default class MessageEntrance extends Emiter {
let errorMessage = {"code": _data, "reson": MessageTypes.ErrorReson[_data] + " " + option};
loger.error("MCU_ERROR", errorMessage);
this._emit(MessageTypes.ERROR_EVENT,errorMessage);
this._emit(MessageTypes.ERROR_EVENT, errorMessage);
/* if (_mcuErrorCallBackFun) {
/* if (_mcuErrorCallBackFun) {
_mcuErrorCallBackFun(errorMessage);
}*/
}
... ... @@ -175,53 +193,55 @@ export default class MessageEntrance extends Emiter {
return GlobalConfig.getCurrentStatus();
}
//获取会议信息
//获取课堂信息
_getClassDetail() {
return GlobalConfig.getClassDetail();
}
//获取当前会议的状态信息
_getClassStatusInfo(){
//获取当前课堂的状态信息
_getClassStatusInfo() {
return GlobalConfig.classStatusInfo;
}
//关闭会议,所有人都退出
//关闭课堂,所有人都退出
_doClassClose(_param) {
this._leaveClass();
}
//离开会议,断开连接
//离开课堂,断开连接
_doClassExit() {
this._leaveClass();
}
//当前的会议状态信息发生改变,需要保存会议状态到Sass
//当前的课堂状态信息发生改变,需要保存课堂状态到Sass
_onClassStatusInfoChange(_param) {
//如果MCU连接已经断开,不发送
if(GlobalConfig.getCurrentStatus().code!=GlobalConfig.statusCode_2.code){
loger.warn("不能保存会议状态",GlobalConfig.getCurrentStatus());
if (GlobalConfig.getCurrentStatus().code != GlobalConfig.statusCode_2.code) {
loger.warn("不能保存课堂状态", GlobalConfig.getCurrentStatus());
return;
}
this._sassSaveClassStatusInfo();
}
//如果是第一次点击开始上课,需要创建录制时的文件名
_onClassRecordStart(_param){
if(GlobalConfig.getCurrentStatus().code!=GlobalConfig.statusCode_2.code){
loger.warn("不能保存会议状态",GlobalConfig.getCurrentStatus());
_onClassRecordStart(_param) {
if (GlobalConfig.getCurrentStatus().code != GlobalConfig.statusCode_2.code) {
loger.warn("不能保存课堂状态", GlobalConfig.getCurrentStatus());
return;
}
if(_sass){
if (_sass) {
_sass.saveClassRecordContrlInfo(_param);
}
}
//有人员离开
_onClassDeleteRoster(_data){
_onClassDeleteRoster(_data) {
//在conferApe中做处理,这里不需要再处理
//{"nodeId":nodeId}
//当有人员离开的时候,如果离开的人员已经推流,那么需要停止推流,然后释放channel;
//只有自己是主持人的时候出才处理下面的事情
if(_data!=null&&_data.nodeId!=null&&GlobalConfig.isHost){
/* if(_data!=null&&_data.nodeId!=null){
loger.log("有人员离开,检查一下离开的人员是否关闭推流");
if(_video_ape){
_video_ape.stopPublishVideo(_data);
... ... @@ -229,21 +249,26 @@ export default class MessageEntrance extends Emiter {
if(_audio_ape){
_audio_ape.stopPublishAudio(_data);
}
}
}*/
}
//当前会议中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
//当前课堂中视频或音频占用channel的nodeId ,在人员列表中不存在,这种情况是占用channel的人员掉线或离开的时候没有释放channel
//的占用状态导致,对于这种情况,需要释放掉
_onClassNonentityRoster(_param){
if(_param==null||_param.nodeId==null){
_onClassNonentityRoster(_param) {
if(GlobalConfig.isRecordPlayBack){
loger.warn("录制回放中,不处理")
return;
}
if (_param == null || _param.nodeId == null) {
loger.warn("onClassNonentityRoster.参数错误")
return;
}
let data={"nodeId":_param.nodeId};
if(_video_ape){
let data = {"nodeId": _param.nodeId};
if (_video_ape) {
_video_ape.stopPublishVideo(data);
}
if(_audio_ape){
if (_audio_ape) {
_audio_ape.stopPublishAudio(data);
}
}
... ... @@ -268,11 +293,17 @@ export default class MessageEntrance extends Emiter {
loger.log('init', _param);
//保存参数
GlobalConfig.isRecordPlayBack=false;//设置为非录制回放状态
GlobalConfig.classId = parseInt(_param.classId);
GlobalConfig.portal = _param.portal;
GlobalConfig.userRole = _param.userRole || ApeConsts.normal;
GlobalConfig.userId = _param.userId || "0";
GlobalConfig.userName=_param.userName || "";
GlobalConfig.userName = _param.userName || "";
//最长允许录制的时间
if(_param.allowRecordMaxTime){
GlobalConfig.allowRecordMaxTime=parseInt(_param.allowRecordMaxTime);
}
//获取课堂校验信息
if (_sass) {
... ... @@ -280,34 +311,45 @@ export default class MessageEntrance extends Emiter {
}
}
//外部请求加入会议
//外部请求加入课堂
_joinClass(_param) {
//_joinClassSuccessCallBackFun = _onSuccess;
//{"userName":"名字","password":""}
if (_param == null || EngineUtils.isEmptyObject(_param)) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PARAM);
loger.log('不能进入会议,传递的参数不对.', _param);
loger.log('不能进入课堂,传递的参数不对.', _param);
return;
}
//判断userName
if (_param.userName == null || _param.userName == "") {
loger.log('不能进入会议,传递的参数不对.名字不能为空');
loger.log('不能进入课堂,传递的参数不对.名字不能为空');
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PARAM);
return;
}
if(GlobalConfig.userName==null||GlobalConfig.userName==""){
if (GlobalConfig.userName == null || GlobalConfig.userName == "") {
GlobalConfig.userName = _param.userName;
}
GlobalConfig.autoLogin=_param.autoLogin||"";
GlobalConfig.password = _param.password || "";
GlobalConfig.hasCamera=(typeof _param.hasCamera=="boolean")? _param.hasCamera:false;
GlobalConfig.hasMicrophone=(typeof _param.hasMicrophone=="boolean")? _param.hasMicrophone:false;
//debugger;
//开始校验
GlobalConfig.hasCamera = (typeof _param.hasCamera == "boolean") ? _param.hasCamera : false;
GlobalConfig.hasMicrophone = (typeof _param.hasMicrophone == "boolean") ? _param.hasMicrophone : false;
loger.log("autoLoginMd5",GlobalConfig.classId,GlobalConfig.userId,GlobalConfig.userRole);
let autoLoginMd5=MD5(""+GlobalConfig.classId+GlobalConfig.userId+GlobalConfig.userRole);
loger.log("joinClass-GlobalConfig.autoLogin",GlobalConfig.autoLogin,"autoLoginMd5-",autoLoginMd5);
if(GlobalConfig.autoLogin&&autoLoginMd5==GlobalConfig.autoLogin){
// MD5(classId+userId+userRole)==m
//自动登录,跳过验证流程
loger.log("自动登录");
this._sassJoinSuccessHandler();
}else {
//不能自动登录,开始校验
if (_sass) {
_sass.passwordAndMd5Checking(GlobalConfig.getClassInfo());
}
}
}
// 用classId向SASS平台获取入会验证信息成功
_sassInitSuccessHandler(_data) {
... ... @@ -323,7 +365,7 @@ export default class MessageEntrance extends Emiter {
loger.log('SASS平台获取入会验证信息成功.');
//设置当前的会议状态
//设置当前的课堂状态
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_1);
//返回给客户端初始化成功的数据
let initSuccessCallBackData = {};
... ... @@ -331,21 +373,17 @@ export default class MessageEntrance extends Emiter {
initSuccessCallBackData.classId = GlobalConfig.classId;
initSuccessCallBackData.userRole = GlobalConfig.userRole;
initSuccessCallBackData.userId = GlobalConfig.userId;
initSuccessCallBackData.userName = GlobalConfig.userName;
initSuccessCallBackData.classType = GlobalConfig.classType;
//host默认需要密码,Sass服务器只判断学生是否需要密码,没有判断老师的
if (GlobalConfig.userRole== ApeConsts.host) {
initSuccessCallBackData.passwordRequired =true;
if (GlobalConfig.userRole == ApeConsts.host) {
initSuccessCallBackData.passwordRequired = true;
} else {
initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
}
this._emit(MessageTypes.CLASS_INIT_SUCCESS,initSuccessCallBackData);
/* if (_initSuccessCallBackFun) {
_initSuccessCallBackFun(initSuccessCallBackData);
}*/
this._emit(MessageTypes.CLASS_INIT_SUCCESS, initSuccessCallBackData);
}
// 通过SASS平台验证(密码和MD5)
... ... @@ -361,117 +399,24 @@ export default class MessageEntrance extends Emiter {
mcu 字符串 Mcu列表
rs 字符串 Rs列表
doc 字符串 Doc列表*/
/* {
"record": "112.126.80.182:80",
"flag": "true",
"h5Module": 1,
"maxVideoChannels": 1,
"mcu": "123.56.73.119:7000;123.56.69.230:7000;112.126.80.182:7000",
"ms": "pubms.3mang.com:1935",
"doc": "101.200.150.192:80",
"rs": "pubms.3mang.com:1935",
"type": 1,
"maxAudioChannels": 1,
"h5_mcu_list": "123.56.73.119:7001;123.56.69.230:7001;112.126.80.182:7001"
}*/
/*
if (_data.h5_mcu_list) {
//MCU地址默认使用第一个
let server = _data.h5_mcu_list.split(";")[0];
GlobalConfig.MCUServerIP = server.split(":")[0];
GlobalConfig.MCUServerPort = server.split(":")[1];
}
//视频推流播流地址
if (_data.ms) {
//MS地址默认使用第一个
let server = _data.ms.split(";")[0];
GlobalConfig.MSServerIP = server.split(":")[0];
GlobalConfig.MSServerPort = server.split(":")[1];
}
//m3u8播流地址
if(_data.rs){
//RS地址默认使用第一个
let server = _data.rs.split(";")[0];
GlobalConfig.RSServerIP = server.split(":")[0];
GlobalConfig.RSServerPort = server.split(":")[1];
}
GlobalConfig.docServer = _data.doc;
GlobalConfig.h5_mcu_list = _data.h5_mcu_list;
GlobalConfig.h5Module = _data.h5Module;
GlobalConfig.mcu = _data.mcu;
GlobalConfig.ms = _data.ms;
GlobalConfig.record = _data.record;
GlobalConfig.rs = _data.rs;
GlobalConfig.maxVideoChannels = _data.maxVideoChannels;
GlobalConfig.maxAudioChannels = _data.maxAudioChannels;
*/
/*
//这个接口获取的数据在getClassParam接口的数据中都有,内容重复,这个接口废弃
//获取会议基本信息
if (_sass) {
_sass.getClassDetail();
}
*/
//获取会议最完整的数据
//获取课堂最完整的数据
if (_sass) {
_sass.getClassParam();
}
}
//获取会议基本信息getClassH5
_sassGetClassDetailSuccessHandler(_data) {
loger.log('获取getClassDetail完成.');
/* {
"cycle": 0,
"repeatmonthweekweek": 0,
"status": 1,
"repeatmonthday": 0,
"repeatmode": 0,
"beginTime": "2017-02-03 09:00:00",
"frequency": 1,
"endmode": 0,
"meetingContent": "",
"endTime": "2017-03-31 11:00:00",
"repeatweek": "",
"category": "",
"finalenddate": "",
"repeatday": 0,
"meetingName": "mcu1",
"errorCode": 0,
"monthType": 0,
"repeatmonthweekday": 0,
"endcount": 1
}*/
GlobalConfig.classDetail = _data;
GlobalConfig.className = _data.meetingName || "";
GlobalConfig.classBeginTime = _data.beginTime || "";
GlobalConfig.classEndTime = _data.endTime || "";
//获取会议所有信息和以前保存的会议状态信息(最全的信息)
if (_sass) {
_sass.getClassParam();
}
}
//获取会议所有参数 api/meeting/detail.do? flash中的接口文件是 getClassParam.do
//获取课堂所有参数 api/meeting/detail.do? flash中的接口文件是 getClassParam.do
_sassGetClassParamSuccessHandler(_data) {
//console.log(GlobalConfig.classStatusInfo)
loger.log('获取课堂会议的完整信息完成.');
loger.log('获取课堂课堂的完整信息完成.');
// console.log(_data);
//包含整个会议最全的信息,储存数据
//包含整个课堂最全的信息,储存数据
if (_data) {
GlobalConfig.mcuDelay = _data.mcuDelay || 60;//mcu消息延迟,用于文档模块
GlobalConfig.className = _data.meetingName || "";
GlobalConfig.classBeginTime = _data.beginTime || "";
GlobalConfig.classEndTime = _data.endTime || "";
GlobalConfig.userIp = _data.userIp || "";
GlobalConfig.maxVideoChannels = _data.maxVideoChannels;
GlobalConfig.maxAudioChannels = _data.maxAudioChannels;
... ... @@ -486,142 +431,177 @@ export default class MessageEntrance extends Emiter {
GlobalConfig.setMusicListPrepare(_data.musicListPrepare);//提前上传的声音文件列表
if (_data.mcuList) {
if (_data.mcuList&&_data.mcuList.length>0) {
//MCU地址默认使用第一个
GlobalConfig.MCUServerIP =_data.mcuList[0].ip||"";
GlobalConfig.MCUServerPort =_data.mcuList[0].port||"";
GlobalConfig.MCUServerIP = _data.mcuList[0].ip || "";
GlobalConfig.MCUServerPort = _data.mcuList[0].port || "";
}
//视频推流播流地址
if (_data.msList) {
//上课中视频推流播流地址
if (_data.msList&&_data.msList.length>0) {
//MS地址默认使用第一个
GlobalConfig.MSServerIP =_data.msList[0].ip||"";
GlobalConfig.MSServerPort =_data.msList[0].port||"";
GlobalConfig.MSServerIP = _data.msList[0].ip || "";
GlobalConfig.MSServerPort = _data.msList[0].port || "";
}
//m3u8播流地址
if(_data.rsList){
//录制回放时m3u8播流地址
if (_data.rsList&&_data.rsList.length>0) {
//RS地址默认使用第一个
GlobalConfig.RSServerIP =_data.rsList[0].ip||"";
GlobalConfig.RSServerPort =_data.rsList[0].port||"";
GlobalConfig.RSServerIP = _data.rsList[0].ip || "";
GlobalConfig.RSServerPort = _data.rsList[0].port || "";
}
//文档地址
if(_data.docList){
if (_data.docList&&_data.docList.length>0) {
//doc地址默认使用第一个
GlobalConfig.DOCServerIP =_data.docList[0].ip||"";
GlobalConfig.DOCServerPort =_data.docList[0].port||"";
GlobalConfig.DOCServerIP = _data.docList[0].ip || "";
GlobalConfig.DOCServerPort = _data.docList[0].port || "";
}
//record
if(_data.recordList){
if (_data.recordList&&_data.recordList.length>0) {
//地址默认使用第一个
GlobalConfig.RecordServerIP =_data.recordList[0].ip||"";
GlobalConfig.RecordServerPort =_data.recordList[0].port||"";
GlobalConfig.RecordServerIP = _data.recordList[0].ip || "";
GlobalConfig.RecordServerPort = _data.recordList[0].port || "";
}
}
if (_data.currentInfo) {
//根据从Sass获取的数据信息,同步最后一次保存的会议状态信息
loger.log("同步最后一次保存过的会议状态信息");
//根据从Sass获取的数据信息,同步最后一次保存的课堂状态信息
loger.log("本地同步最后一次保存过的课堂状态信息");
try {
GlobalConfig.setClassStatusInfo(JSON.parse(_data.currentInfo));
}catch (err){
GlobalConfig.setClassStatusInfo(_data.currentInfo);
console.log(GlobalConfig.classStatusInfo);
}
loger.log(GlobalConfig.classStatusInfo);
} else {
loger.log("还没有保存过会议状信息");
loger.log("还没有保存过课堂状信息");
}
//所有Sass流程完成,开始MCU连接
//录制回放不需要选点
if(GlobalConfig.isRecordPlayBack){
if (_parseBuf) {
//开启录制回放流程
loger.log("开启录制回放流程");
_parseBuf.readyRecordPlay();
}else {
loger.warn("开启录制回放流程失败,还未创建模块");
}
}else {
//根据用户的userIp获取信息
this.getUserIpInfo();
}
}
//根据UserIp获取ip信息
getUserIpInfo() {
if (_serverCheck) {
_serverCheck.getUserIpInfo("", GlobalConfig.userIp);
}
}
//MCU MS ip选点完成,开加入MCU
_serverCheckBestIpSuccessHandler(_data) {
loger.log("_serverCheckBestIpSuccessHandler,IP选点结束");
this._joinMCU();
}
//保存会议状态信息
//保存课堂状态信息
_sassSaveClassStatusInfo() {
if (GlobalConfig.isHost) {
//只有加入会议之后才能保存数据
//只有加入课堂之后才能保存数据
if (GlobalConfig.getCurrentStatus().code == GlobalConfig.statusCode_2.code) {
//POST 保存数据
_sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo});//保存会议状态信息
_sass.saveClassStatusInfo({"classStatusInfo": GlobalConfig.classStatusInfo});//保存课堂状态信息
} else {
loger.error("不能保存会议数据", GlobalConfig.getCurrentStatus());
loger.error("不能保存课堂数据", GlobalConfig.getCurrentStatus());
}
} else {
loger.log("没有保存会议状态信息的权限 isHost", GlobalConfig.isHost);
loger.log("没有保存课堂状态信息的权限 isHost", GlobalConfig.isHost);
}
}
//保存会态信息成功
_sassSaveClassStatusInfoSuccessHandler(_data) {
loger.log('保存会议状态信息成功.');
console.log(_data);
loger.log('保存课堂状态信息成功.');
loger.log(_data);
}
_sassSaveClassRecordInfoSuccessHandler(_data){
loger.log('保存会议录制信息成功.');
console.log(_data);
_sassSaveClassRecordInfoSuccessHandler(_data) {
loger.log('保存课堂录制信息成功.');
loger.log(_data);
}
//Sass校验流程结束之后,开始加入MCU
_joinMCU() {
loger.log('加入底层MCU会议.');
loger.log('加入底层MCU课堂.');
if (_mcu) {
_mcu.joinMCU(GlobalConfig.getClassInfo());
}
}
// MCU 会议成功
// MCU 课堂成功
_mcuJoinMCUClassSuccessHandler(_data) {
loger.log('MCU 会议成功.');
loger.log('MCU 课堂成功.');
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);
//返回给客户端初始化成功的数据
let initSuccessCallBackData = {};
let joinClassSuccessCallBackData = {};
initSuccessCallBackData.DOCServerIP =GlobalConfig.DOCServerIP;
initSuccessCallBackData.DOCServerPort =GlobalConfig.DOCServerPort;
joinClassSuccessCallBackData.isRecordPlayBack=GlobalConfig.isRecordPlayBack;
initSuccessCallBackData.classId = GlobalConfig.classId;
initSuccessCallBackData.className = GlobalConfig.className;
initSuccessCallBackData.h5Module = GlobalConfig.h5Module;
initSuccessCallBackData.isHost = GlobalConfig.isHost;
initSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels;
initSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels;
initSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay;
initSuccessCallBackData.msType = GlobalConfig.msType;
initSuccessCallBackData.nodeId = GlobalConfig.nodeId;
initSuccessCallBackData.password = GlobalConfig.password;
initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;// 老师的默认是true
//GlobalConfig.passwordRequired 老师的默认是true
//GlobalConfig.portal=_data.portal;
initSuccessCallBackData.role = GlobalConfig.role;
initSuccessCallBackData.siteId = GlobalConfig.siteId;
initSuccessCallBackData.topNodeID = GlobalConfig.topNodeID;
initSuccessCallBackData.userId = GlobalConfig.userId;
initSuccessCallBackData.userName = GlobalConfig.userName;
initSuccessCallBackData.userRole = GlobalConfig.userRole;
initSuccessCallBackData.userType = GlobalConfig.userType;
joinClassSuccessCallBackData.DOCServerIP = GlobalConfig.DOCServerIP;
joinClassSuccessCallBackData.DOCServerPort = GlobalConfig.DOCServerPort;
initSuccessCallBackData.siteId = GlobalConfig.siteId;
initSuccessCallBackData.classId = GlobalConfig.classId;
initSuccessCallBackData.userRole = GlobalConfig.userRole;
initSuccessCallBackData.userId = GlobalConfig.userId;
initSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
initSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT;
loger.log('加入会议成功');
console.log(initSuccessCallBackData);
joinClassSuccessCallBackData.classId = GlobalConfig.classId;
joinClassSuccessCallBackData.className = GlobalConfig.className;
joinClassSuccessCallBackData.h5Module = GlobalConfig.h5Module;
joinClassSuccessCallBackData.isHost = GlobalConfig.isHost;
joinClassSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels;
joinClassSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels;
joinClassSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay;
//加入会议成功,广播消息
this._emit(MessageTypes.CLASS_JOIN_SUCCESS,initSuccessCallBackData);
/* //返回给客户数据
if (_joinClassSuccessCallBackFun) {
_joinClassSuccessCallBackFun(initSuccessCallBackData);
}*/
joinClassSuccessCallBackData.msType = GlobalConfig.msType;
joinClassSuccessCallBackData.nodeId = GlobalConfig.nodeId;
joinClassSuccessCallBackData.password = GlobalConfig.password;
joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;// 老师的默认是true
//GlobalConfig.passwordRequired 老师的默认是true
//GlobalConfig.portal=_data.portal;
joinClassSuccessCallBackData.role = GlobalConfig.role;
joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
joinClassSuccessCallBackData.topNodeID = GlobalConfig.topNodeID;
joinClassSuccessCallBackData.userId = GlobalConfig.userId;
joinClassSuccessCallBackData.userName = GlobalConfig.userName;
joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
joinClassSuccessCallBackData.userType = GlobalConfig.userType;
joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
joinClassSuccessCallBackData.classId = GlobalConfig.classId;
joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
joinClassSuccessCallBackData.userId = GlobalConfig.userId;
joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT;
joinClassSuccessCallBackData.country = GlobalConfig.country;//国家
joinClassSuccessCallBackData.city = GlobalConfig.city;//城市
joinClassSuccessCallBackData.province = GlobalConfig.province;//服务商
joinClassSuccessCallBackData.isp = GlobalConfig.isp;//服务商
joinClassSuccessCallBackData.classTimestamp=GlobalConfig.classTimestamp;//课堂进行的累积时间
joinClassSuccessCallBackData.recordPlaybackMaxTime=GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间
loger.log('加入课堂成功');
loger.log(joinClassSuccessCallBackData);
//加入课堂成功,广播消息
this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
}
//Sass删除文档数据
_sassDeleteDocument(_param) {
if(!_mcu.connected){
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
... ... @@ -653,57 +633,60 @@ export default class MessageEntrance extends Emiter {
//ConferApe
//开始上课
_sendStartClass(_param){
if(!_mcu.connected){
_sendStartClass(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_confer_ape){
if (_confer_ape) {
_confer_ape.startClass(_param);
}
}
//暂停上课
_sendPauseClass(_param){
if(!_mcu.connected){
_sendPauseClass(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_confer_ape){
if (_confer_ape) {
_confer_ape.pauseClass(_param);
}
}
//停止上课
_sendCloseClass(_param){
if(!_mcu.connected){
_sendCloseClass(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_confer_ape){
if (_confer_ape) {
_confer_ape.closeClass(_param);
}
}
// 离开会议
// 离开课堂
_leaveClass() {
if(!_mcu.connected){
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
//停止推流
if(_video_ape){
if (_video_ape) {
_video_ape.stopPublishVideo();
}
if(_audio_ape){
if (_audio_ape) {
_audio_ape.stopPublishAudio();
}
//离开会议
if(_confer_ape){
//离开课堂
if (_confer_ape) {
_confer_ape.stopRecord();
_confer_ape.leaveClass();
}
//断开MCU连接
if(_mcu){
if (_mcu) {
_mcu.leaveMCU();
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_3);
}
... ... @@ -713,13 +696,13 @@ export default class MessageEntrance extends Emiter {
//ChatApe
// 发送聊天消息
_sendChatMsg(_messageInfo) {
if(!_mcu.connected){
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_messageInfo===null||EngineUtils.isEmptyObject(_messageInfo)){
loger.log('sendChatMsg 传递的参数不对',_messageInfo);
return ;
if (_messageInfo === null || EngineUtils.isEmptyObject(_messageInfo)) {
loger.log('sendChatMsg 传递的参数不对', _messageInfo);
return;
}
if (_chat_ape) {
_chat_ape.sendChatMsg(_messageInfo);
... ... @@ -727,101 +710,113 @@ export default class MessageEntrance extends Emiter {
}
//VidoeApe
videoUpdate(_data){
videoUpdate(_data) {
//视频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
if(_confer_ape){
if (_confer_ape) {
_confer_ape.updaterRosterStatus(_data);
}
}
_sendVideoBroadcastMsg(_param){
if(!_mcu.connected){
_sendVideoBroadcastMsg(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_video_ape){
if (_video_ape) {
return _video_ape.sendVideoBroadcastMsg(_param);
}
}
_getVideoPlayPath(_param){
if(_video_ape){
_getVideoPlayPath(_param) {
if (_video_ape) {
return _video_ape.getPlayVideoPath(_param);
}
}
_getVideoPublishPath(_param){
if(_video_ape){
_getVideoPublishPath(_param) {
if (_video_ape) {
return _video_ape.getPublishVideoPath(_param);
}
}
_publishVideo(_param){
if(!_mcu.connected){
_getVideoAllChannelInfo(_param) {
if (_video_ape) {
return _video_ape.getAllChannelInfo(_param);
}
}
_publishVideo(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_video_ape){
if (_video_ape) {
return _video_ape.publishVideo(_param);
}
}
_stopPublishVideo(_param){
if(!_mcu.connected){
_stopPublishVideo(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_video_ape){
if (_video_ape) {
return _video_ape.stopPublishVideo(_param);
}
}
//AudioApe
audioUpdate(_data){
audioUpdate(_data) {
//音频同步的消息发送改变,需要通知ferApe模块中的用户更新状态
if(_confer_ape){
if (_confer_ape) {
_confer_ape.updaterRosterStatus(_data);
}
}
sendAudioCommandMsg(_param){
if(!_mcu.connected){
sendAudioCommandMsg(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_audio_ape){
if (_audio_ape) {
return _audio_ape.sendAudioBroadcastMsg(_param);
}
}
_getPlayAudioPath(_param){
if(_audio_ape){
_getPlayAudioPath(_param) {
if (_audio_ape) {
return _audio_ape.getAudioPlayPath(_param);
}
}
_getPublishAudioPath(_param){
if(_audio_ape){
_getPublishAudioPath(_param) {
if (_audio_ape) {
return _audio_ape.getAudioPublishPath(_param);
}
}
_publishAudio(_param){
if(!_mcu.connected){
_getAudioAllChannelInfo(_param) {
if (_audio_ape) {
return _audio_ape.getAllChannelInfo(_param);
}
}
_publishAudio(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_audio_ape){
if (_audio_ape) {
return _audio_ape.publishAudio(_param);
}
}
_stopPublishAudio(_param){
if(!_mcu.connected){
_stopPublishAudio(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_audio_ape){
if (_audio_ape) {
return _audio_ape.stopPublishAudio(_param);
}
}
... ... @@ -829,49 +824,52 @@ export default class MessageEntrance extends Emiter {
//WhiteBoardApe
// 添加标注,发送信息
_sendInsertAnnotaion(_param){
if(!_mcu.connected){
_sendInsertAnnotaion(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_whiteboard_ape){
if (_whiteboard_ape) {
_whiteboard_ape.sendInsetAnnotaion(_param);
}
}
//删除标注,发送信息
_sendDeleteAnnotaion(_param){
if(!_mcu.connected){
_sendDeleteAnnotaion(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_whiteboard_ape){
if (_whiteboard_ape) {
_whiteboard_ape.sendDeleteAnnotaion(_param);
}
}
//删除当前页面上的所有标注
_sendDeleteCurPageAnnotation(_param){
if(!_mcu.connected){
_sendDeleteCurPageAnnotation(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_whiteboard_ape){
if (_whiteboard_ape) {
_whiteboard_ape.sendDeleteCurPageAnnotation(_param);
}
}
//删除所有标注
_sendDeleteAllAnnotation(_param){
if(!_mcu.connected){
_sendDeleteAllAnnotation(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_whiteboard_ape){
if (_whiteboard_ape) {
_whiteboard_ape.sendDeleteAllAnnotation(_param);
}
}
//返回上一步标注
_sendGotoPrev(_param){
if(_whiteboard_ape){
_sendGotoPrev(_param) {
if (_whiteboard_ape) {
_whiteboard_ape.sendGotoPrev(_param);
}
}
... ... @@ -879,112 +877,119 @@ export default class MessageEntrance extends Emiter {
//DocApe
//获取文档完整路径
_getDocImageFullPath(_param){
if(_doc_ape){
_getDocImageFullPath(_param) {
if (_doc_ape) {
return _doc_ape.getDocImageFullPath(_param);
}else {
} else {
loger.error("文档模块还没有创建,无法获取");
return [];
}
}
_getDocPDFFullPath(_param){
if(_doc_ape){
_getDocPDFFullPath(_param) {
if (_doc_ape) {
return _doc_ape.getDocPDFFullPath(_param);
}else {
} else {
loger.error("文档模块还没有创建,无法获取");
return [];
}
}
//上传文档
_sendDocumentUpload(_param){
if(!_mcu.connected){
_sendDocumentUpload(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentUpload(_param);
}
}
//切换文档
_sendDocumentSwitchDoc(_param){
if(!_mcu.connected){
_sendDocumentSwitchDoc(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentSwitchDoc(_param);
}
}
//操作文档(翻页)
_sendDocumentSwitchPage(_param){
if(!_mcu.connected){
_sendDocumentSwitchPage(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentSwitchPage(_param);
}
}
//操作文档(缩放、滚动...)
_sendDocumentCommand(_param){
if(!_mcu.connected){
_sendDocumentCommand(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentCommand(_param);
}
}
//删除文档
_sendDocumentDelete(_param){
if(!_mcu.connected){
_sendDocumentDelete(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentDelete(_param);
}
}
//删除所有文档
_documentDeleteAll(_param){
if(!_mcu.connected){
_documentDeleteAll(_param) {
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
if(_doc_ape){
if (_doc_ape) {
_doc_ape.documentDeleteAll(_param);
}
}
//// 文档变更,白板也需要做处理
docUpdateHandler(_data) {
if(!_mcu.connected){
if (!_mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return;
}
loger.log('Doc UpdateId ->');
console.log(_data);
if(_whiteboard_ape){
loger.log(_data);
if (_whiteboard_ape) {
_whiteboard_ape.docUpdateHandler(_data);
}
}
//文档删除,白板也需要做处理
docDeleteHandler(_data){
if(_whiteboard_ape){
docDeleteHandler(_data) {
if (_whiteboard_ape) {
_whiteboard_ape.docDeleteHandler(_data);
}
}
//文档加入频道成功,同步到MCU服务器上的数据
docJoinChannelSuccess(){
loger.log("docJoinChannelSuccess isHost=",GlobalConfig.isHost);
console.log(GlobalConfig.docListPrepare);
docJoinChannelSuccess() {
loger.log("docJoinChannelSuccess isHost=", GlobalConfig.isHost);
loger.log(GlobalConfig.docListPrepare);
loger.log("docJoinChannelSuccess docListPrepare=");
//如果是主持人,那么需要判断一下文档模块同步的数据和从sass获取的文档数据是否相同,如果mcu服务器不存在的,需要上传
if(GlobalConfig.isHost){
for (let value of GlobalConfig.docListPrepare){
if(value){
if (GlobalConfig.isHost) {
for (let value of GlobalConfig.docListPrepare) {
if (value) {
/* //提前上传的文档文档信息的结构
{
"MD5": "f3feb3fac8cd3a953bded00e07a0c66b",
... ... @@ -1011,16 +1016,16 @@ export default class MessageEntrance extends Emiter {
"uploadStartTime": "2017-02-03 11:54:27"
}*/
loger.log("判断是否需要把提前上传的文档上传到mcu",value);
let paramInfo={
loger.log("判断是否需要把提前上传的文档上传到mcu", value);
let paramInfo = {
"pageNum": value.pdfSize,
"fileName": value.name,
"fileType": value.type,
"relativeUrl": value.relativeLocation,
"url": value.absoluteLocation,
"creatUserId":value.createUserID,
"creatUserId": value.createUserID,
"docId": value.id,
"md5":value.MD5,
"md5": value.MD5,
"visible": false
};
... ... @@ -1029,4 +1034,116 @@ export default class MessageEntrance extends Emiter {
}
}
}
//录制回放相关的处理------------------------------------------------
//录制回放初始化
_initRecordPlayback(_param){
//{"classId":"1653304953","portal":"112.126.80.182:80","userRole":"normal","userId":0}
if (_param == null) {
loger.error('录制回放初始化失败,参数错误');
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED);
return;
}
//判断必要的参数字段值
if (_param.classId == null || isNaN(_param.classId) || _param.portal == null || _param.portal == "") {
loger.error('录制回放初始化失败', _param);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED);
return;
}
loger.log('录制回放', _param);
//保存参数
GlobalConfig.isRecordPlayBack=true;//设置为录制回放状态
GlobalConfig.classId = parseInt(_param.classId);
GlobalConfig.portal = _param.portal;
GlobalConfig.userRole =ApeConsts.normal;//*************很重要,录制回放的时候,身份模式是普通人********
GlobalConfig.userId = _param.userId || "0";
GlobalConfig.userName = _param.userName || "";
//获取课堂最完整的数据,录制回放需要获取课堂数据
if (_sass) {
_sass.getClassParam();
}
}
//开始录制回放
_startRecordPlayback(_param) {
if (_parseBuf) {
_parseBuf.startRecordPlayback(_param);
}
}
//停止录制回放
_stopRecordPlayback(_param) {
if (_parseBuf) {
_parseBuf.stopRecordPlayback(_param);
}
}
//暂停录制回放
_pauseRecordPlayback(_param) {
if (_parseBuf) {
_parseBuf.pauseRecordPlayback(_param);
}
}
//seek录制回放
_seekRecordPlayback(_param) {
if (_parseBuf) {
_parseBuf.seekRecordPlayback(_param);
}
}
//录制回放加入 课堂成功
_joinRecordPlaybackSuccessHandler(_data) {
loger.log('加入录制回放成功.');
GlobalConfig.setCurrentStatus(GlobalConfig.statusCode_2);
//返回给客户端初始化成功的数据
let joinClassSuccessCallBackData = {};
joinClassSuccessCallBackData.isRecordPlayBack=GlobalConfig.isRecordPlayBack;
joinClassSuccessCallBackData.DOCServerIP = GlobalConfig.DOCServerIP;
joinClassSuccessCallBackData.DOCServerPort = GlobalConfig.DOCServerPort;
joinClassSuccessCallBackData.classId = GlobalConfig.classId;
joinClassSuccessCallBackData.className = GlobalConfig.className;
joinClassSuccessCallBackData.h5Module = GlobalConfig.h5Module;
joinClassSuccessCallBackData.isHost = GlobalConfig.isHost;//
joinClassSuccessCallBackData.maxAudioChannels = GlobalConfig.maxAudioChannels;
joinClassSuccessCallBackData.maxVideoChannels = GlobalConfig.maxVideoChannels;
joinClassSuccessCallBackData.mcuDelay = GlobalConfig.mcuDelay;
joinClassSuccessCallBackData.msType = GlobalConfig.msType;
joinClassSuccessCallBackData.nodeId = GlobalConfig.nodeId;
joinClassSuccessCallBackData.password = GlobalConfig.password;
joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;// 老师的默认是true
//GlobalConfig.passwordRequired 老师的默认是true
//GlobalConfig.portal=_data.portal;
joinClassSuccessCallBackData.role = GlobalConfig.role;
joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
joinClassSuccessCallBackData.topNodeID = GlobalConfig.topNodeID;
joinClassSuccessCallBackData.userId = GlobalConfig.userId;
joinClassSuccessCallBackData.userName = GlobalConfig.userName;
joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
joinClassSuccessCallBackData.userType = GlobalConfig.userType;
joinClassSuccessCallBackData.siteId = GlobalConfig.siteId;
joinClassSuccessCallBackData.classId = GlobalConfig.classId;
joinClassSuccessCallBackData.userRole = GlobalConfig.userRole;
joinClassSuccessCallBackData.userId = GlobalConfig.userId;
joinClassSuccessCallBackData.passwordRequired = GlobalConfig.passwordRequired;
joinClassSuccessCallBackData.classType = GlobalConfig.classType || ApeConsts.CLASS_TYPE_INTERACT;
joinClassSuccessCallBackData.country = GlobalConfig.country;//国家
joinClassSuccessCallBackData.city = GlobalConfig.city;//城市
joinClassSuccessCallBackData.province = GlobalConfig.province;//服务商
joinClassSuccessCallBackData.isp = GlobalConfig.isp;//服务商
joinClassSuccessCallBackData.classTimestamp=GlobalConfig.classTimestamp;//课堂进行的累积时间
joinClassSuccessCallBackData.recordPlaybackMaxTime=GlobalConfig.recordPlaybackMaxTime;//录制回放的总时间
loger.log(joinClassSuccessCallBackData);
//和加入课堂成功使用同样的消息处理
this._emit(MessageTypes.CLASS_JOIN_SUCCESS, joinClassSuccessCallBackData);
}
}
... ...
... ... @@ -85,11 +85,13 @@ class EverSocket extends Emiter {
loger.log('WebSocket,Timers销毁');
window.clearInterval(this.pingTimer);
window.clearInterval(this.pongTimer);
window.clearInterval(this.reConnectionTimeout);
this._setConnected(false);//先设置状态
this._enableEverSocket = false;
if(this.websocket==null){
loger.log('WebSocket,Timers已经销毁');
return;
}
this._setConnected(false);//先设置状态
this.websocket.onopen = undefined;
this.websocket.onclose = undefined;
this.websocket.onerror = undefined;
... ... @@ -100,7 +102,7 @@ class EverSocket extends Emiter {
loger.log('ignore errors');
}
this.websocket = undefined;
this._enableEverSocket = false;
}
_onOpen() {
... ...
... ... @@ -70,6 +70,7 @@ class GlobalConfig {
classStatusInfo.classStartTime=this.classStartTime;//课堂点击开始时间
classStatusInfo.classStopTime=this.classStopTime;//最后一次停止的时间(点暂停或结束),每次发送数据都获取当前时间戳
classStatusInfo.classTimestamp=this.classTimestamp;//相对于点开始课堂的时间戳
classStatusInfo.recordPlaybackMaxTime=this.recordPlaybackMaxTime;//相对于点开始课堂的时间戳
classStatusInfo.classBeginTime=this.classBeginTime;//课堂创建的时间,这个是Sass返回的
classStatusInfo.classEndTime=this.classEndTime;//课堂结束的时间,这个是Sass返回的
... ... @@ -234,14 +235,14 @@ class GlobalConfig {
}
GlobalConfig.statusCode_0={"code":0,message:"SDK 未初始化"};
GlobalConfig.statusCode_1={"code":1,message:"未加入会议"};
GlobalConfig.statusCode_2={"code":2,message:"已经加入会议"};
GlobalConfig.statusCode_3={"code":3,message:"已经离开会议"};
GlobalConfig.statusCode_1={"code":1,message:"未加入课堂"};
GlobalConfig.statusCode_2={"code":2,message:"已经加入课堂"};
GlobalConfig.statusCode_3={"code":3,message:"已经离开课堂"};
GlobalConfig.statusCode_4={"code":4,message:"未知状态"};
GlobalConfig.md5="";
GlobalConfig.msType=1;//目前固定用这个
GlobalConfig.mcuDelay=3000;//默认的延迟时间
GlobalConfig.mcuDelay=60;//默认的延迟时间 flash中使用的是3000毫秒
GlobalConfig.docDelay=1600;//文档模块加入成功之后延迟发送送成功的消息给主模块
GlobalConfig.portal="112.126.80.182:80";//Sass IP
... ... @@ -272,7 +273,7 @@ GlobalConfig.hasCamera=false;//摄像头是否可用
GlobalConfig.hasMicrophone=false;//麦克风是否可用
GlobalConfig.deviceType=0; //设备类型 0:电脑 1:安卓 2:ios
GlobalConfig.userIP="";//用户当前IP
GlobalConfig.userIp="";//用户当前IP
GlobalConfig.userId=0;
GlobalConfig.userName="";
... ... @@ -297,13 +298,14 @@ GlobalConfig.classBeginTime="";//课堂创建的时间,这个是Sass返回的
GlobalConfig.classEndTime="";//课堂结束的时间,这个是Sass返回的
GlobalConfig.classTimestamp=0;//从课堂开始到现在的时
GlobalConfig.recordPlaybackMaxTime=0;//录制回放的总时间
GlobalConfig.recordStatus=false;//当前录制状态
GlobalConfig.recordTimestamp=0;//相对于首次开始录制的进行时间
GlobalConfig.recordFileName="";//录制的文件名,如 果为空就创建一个
GlobalConfig.recordDownloadUrl="";//下载地址
GlobalConfig.recordReplaytickValues={}; // 滚动条关键点,用于快进快退
GlobalConfig.updateClassInfoDelay=30;//(秒),每隔30秒同步一次会议状态的并保存到Sass
GlobalConfig.updateClassInfoDelay=30;//(秒),每隔30秒同步一次课堂状态的并保存到Sass
//GlobalConfig.serverTimestamp=0;//当前的系统时间戳 用get set 获取
... ... @@ -313,7 +315,7 @@ GlobalConfig.activeDocCurPage=1;//当前激活的文档的当前页
GlobalConfig.classAllParam={};//Sass直接返回的所有会议信息(最全)
GlobalConfig.classAllParam={};//Sass直接返回的所有课堂信息(最全)
GlobalConfig.classDetail={};//Sass直接返回的当前课堂基本信息
GlobalConfig.docListPrepare=[]; // 已经提前上传的文档,进入课堂后需要自动加载
... ... @@ -323,7 +325,14 @@ GlobalConfig.mcuList=[];//录制服务器地址集合
GlobalConfig.msList=[];//ms服务器地址集合
GlobalConfig.musicList=[];//music服务器地址集合
GlobalConfig.musicListPrepare=[];//提提前上传的music集合
GlobalConfig.rsList=[];
GlobalConfig.rsList=[];//录制回放中视频点播地址
GlobalConfig.country ="";//国家
GlobalConfig.city ="";//城市
GlobalConfig.province = "";//服务商
GlobalConfig.isp ="";//服务商
GlobalConfig.isRecordPlayBack=false;//是否是录制回放,默认是否
GlobalConfig.allowRecordMaxTime=14400;//(秒)允许录制的最长时间,默认是4小时
export default GlobalConfig;
... ...
... ... @@ -9,11 +9,11 @@ function MessageTypes() {}
MessageTypes.CLASS_INIT_SUCCESS="class_init_success";//'class.init.success';//初始化成功
//MessageTypes.CLASS_INIT_FAILED='class.init.failed';//初始化失败
//加入会议相关事件定义
//加入课堂相关事件定义
MessageTypes.CLASS_JOIN_MCU_SUCCESS ="class_join_mcu_success"// 'join.mcu.success';
//MessageTypes.CLASS_JOIN_FAILED = 'join.class.failed';
//会议信息和操作事件定义
//课堂信息和操作事件定义
//MessageTypes.CLASS_SHOW_DETAIL = 'class_detail.message';
MessageTypes.CLASS_JOIN_SUCCESS ="class_join_success"// 'join.class.success';
MessageTypes.CLASS_UPDATE_ROSTER_NUM ="class_update_roster_num";// 'roster_num.message';
... ... @@ -21,9 +21,9 @@ MessageTypes.CLASS_INSERT_ROSTER ="class_insert_roster";// 'roster.insert.messag
MessageTypes.CLASS_DELETE_ROSTER ="class_delete_roster"// 'roster.delete.message';
MessageTypes.CLASS_NONENTITY_ROSTER ="class_nonenetity_roster";// 'roster.nonentity.message';
MessageTypes.CLASS_EXIT ="class_exit";// 'class.exit';//退出 关闭会议
MessageTypes.CLASS_UPTATE_STATUS ="class_update_status";// 'class.update.status';//更新会议状态信息
MessageTypes.CLASS_STATUS_INFO_CHANGE="class_status_info_change";// 'class.status.info.change';//会议状态信息发生改变,需要保存数据到sass和同步MCU
MessageTypes.CLASS_EXIT ="class_exit";// 'class.exit';//退出 关闭课堂
MessageTypes.CLASS_UPTATE_STATUS ="class_update_status";// 'class.update.status';//更新课堂状态信息
MessageTypes.CLASS_STATUS_INFO_CHANGE="class_status_info_change";// 'class.status.info.change';//课堂状态信息发生改变,需要保存数据到sass和同步MCU
MessageTypes.CLASS_UPDATE_TIMER="class_update_timer";//'class.update.timer';//更新当前上课的时间
... ... @@ -37,13 +37,13 @@ MessageTypes.CHAT_RECEIVE ="chat_receive_message";// 'chat.receive';
//视频模块事件定义
MessageTypes.VIDEO_PLAY ="video_play";// 'video.play';//播放视频
MessageTypes.VIDEO_STOP ="video_stop"; //'video.stop';//停止视频
//MessageTypes.VIDEO_UPDATE ="video.update";// 'video.update';//废弃,400、401取代
MessageTypes.VIDEO_UPDATE ="video_update";// //这个监听事件不能删除,需要通知课堂模块,检查channel占用(内部使用)
MessageTypes.VIDEO_BROADCAST= "video_broadcast";//'video.broadcast';
//音频模块事件定义
MessageTypes.AUDIO_PLAY ="audio_play";// 'audio.play';//播放
MessageTypes.AUDIO_STOP = "audio_stop";//'audio.stop';//停止
//MessageTypes.AUDIO_UPDATE = "502";//'audio.update';
MessageTypes.AUDIO_UPDATE = "audio_update";//这个监听事件不能删除,需要通知课堂模块,检查channel占用(内部使用)
MessageTypes.AUDIO_BROADCAST= "audio_broadcast";//'audio.broadcast';
... ... @@ -57,8 +57,6 @@ MessageTypes.DOC_UPDATE ="document_update";// 'document.update';//更新文档(
//MessageTypes.DOC_DELETE='document.delete';//删除文档
//MessageTypes.DOC_ANNOTATION = 'document.annotation';//笔记
//白板笔记事件定义
MessageTypes.WHITEBOARD_ANNOTATION_UPDATE ="whiteboard_annotation_update";// 'whiteboard.annotation.update';
//MessageTypes.WHITEBOARD_ANNOTAION_INSERT = 'whiteboard.annotation.insert';
... ... @@ -66,6 +64,9 @@ MessageTypes.WHITEBOARD_ANNOTATION_UPDATE ="whiteboard_annotation_update";// 'wh
//MessageTypes.WHITEBOARD_ANNOTATION_CLEAR = 'whiteboard.annotation.clear';
//录制回放
MessageTypes.RECORD_PLAYBACK_UPDATE ="record_playback_update";//录制回放更新信息
//错误事件定义
MessageTypes.MCU_ERROR ="mcu_error";//"mcuError";//MCU错误(内部使用)
MessageTypes.ERROR_EVENT="error_event";//外部监听错误的消息ID(外部使用)
... ... @@ -73,7 +74,7 @@ MessageTypes.ERROR_EVENT="error_event";//外部监听错误的消息ID(外部使
//---------------错误消息 ErrorCode 定义-------------------------------------------------
//会议初始化失败的几种情况
//课堂初始化失败的几种情况
MessageTypes.ERR_CLASS_INIT_PARAM=100;//初始化参数错误
MessageTypes.ERR_CLASS_INIT_NETWORK=101;//初始化网络错误
MessageTypes.ERR_CLASS_INIT_PROTOCOL=102;//初始化协议错误
... ... @@ -83,22 +84,22 @@ MessageTypes.ERR_CLASS_INIT_FAILED_2=105;//初始化验证失败,无效的课堂
MessageTypes.ERR_CLASS_INIT_FAILED_3=106;//初始化验证失败,没有对应的站点
MessageTypes.ERR_CLASS_INIT_FAILED_4=107;//初始化验证失败,站点已过期
//加入会议失败的几种情况
MessageTypes.ERR_CLASS_JOIN_NETWORK=200;//加入会议网络错误
MessageTypes.ERR_CLASS_JOIN_PROTOCOL=201;//加入会议化协议错误
MessageTypes.ERR_CLASS_JOIN_FAILED=202;//加入会议化异常错误
MessageTypes.ERR_CLASS_JOIN_PARAM=203;//加入会议参数错误
//加入课堂失败的几种情况
MessageTypes.ERR_CLASS_JOIN_NETWORK=200;//加入课堂网络错误
MessageTypes.ERR_CLASS_JOIN_PROTOCOL=201;//加入课堂化协议错误
MessageTypes.ERR_CLASS_JOIN_FAILED=202;//加入课堂化异常错误
MessageTypes.ERR_CLASS_JOIN_PARAM=203;//加入课堂参数错误
MessageTypes.ERR_CLASS_JOIN_FULL=204;//人数已满
MessageTypes.ERR_CLASS_MD5_WRONG=205;//MD5验证失败
MessageTypes.ERR_CLASS_PASSWORD_WRONG=206;//密码错误
MessageTypes.ERR_CLASS_JOIN_CONFILICT=207;//已经在其它地方登陆
MessageTypes.ERR_CLASS_KICK_OUT=208;//有相同身份的人员加入课堂,自己被踢出;
MessageTypes.ERR_GET_CLASS_DETAIL=300;//获取classDetail失败
MessageTypes.ERR_GET_CLASS_PARAML=301;//获取ClassParam失败
//APE
MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN=500;//APE在sdk为初始化或未加入会议之前调用发送数据接口
MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN=500;//APE在sdk为初始化或未加入课堂之前调用发送数据接口
MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG=501;//APE在接口调用时参数错误
//DOC
... ... @@ -110,10 +111,15 @@ MessageTypes.ERR_SDK_FAILED=700;// sdk还没初始化
MessageTypes.ERR_INTERFACE_NONE=701;//调用的接口不存在
MessageTypes.ERR_INTERFACE_PARAMS_ERROR=702;//调用的接口,传递的参数不正确
MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED=910;//初始化录制回放失败
MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED=911;//获取录制回放数据失败
MessageTypes.ERR_NETWORK=10000;//网络错误
MessageTypes.ERR_UNKNOWN=10001;//未知错误
MessageTypes.ERR_SOCKET_DISCONNECT=20000;//MCU断开连接,已经离开会议
MessageTypes.ERR_SOCKET_DISCONNECT=20000;//MCU断开连接,已经离开课堂
//---------------错误消息 Error Reson 定义-------------------------------------------------
MessageTypes.ErrorReson={};
... ... @@ -128,22 +134,23 @@ MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_INIT_FAILED_3]="初始化验证
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_INIT_FAILED_4]="初始化验证失败,站点已过期";
//加入会议失败的几种情况
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_NETWORK]="加入会议网络错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_PROTOCOL]="加入会议化协议错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_FAILED]="加入会议化异常错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_PARAM]="加入会议参数错误";
//加入课堂失败的几种情况
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_NETWORK]="加入课堂网络错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_PROTOCOL]="加入课堂化协议错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_FAILED]="加入课堂化异常错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_PARAM]="加入课堂参数错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_FULL]="人数已满";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_MD5_WRONG]="MD5验证失败";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_PASSWORD_WRONG]="密码错误";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_JOIN_CONFILICT]="已经在其它地方登陆";
MessageTypes.ErrorReson[MessageTypes.ERR_CLASS_KICK_OUT]="有相同身份的人员加入课堂,自己被踢出课堂";
MessageTypes.ErrorReson[MessageTypes.ERR_GET_CLASS_DETAIL]="获取classDetail失败";
MessageTypes.ErrorReson[MessageTypes.ERR_GET_CLASS_PARAML]="获取ClassParam失败";
//APE
MessageTypes.ErrorReson[MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN]="APE在sdk为初始化或未加入会议之前调用发送数据接口";
MessageTypes.ErrorReson[MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN]="APE在sdk为初始化或未加入课堂之前调用发送数据接口";
MessageTypes.ErrorReson[MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG]="APE在接口调用时参数错误";
//DOC
... ... @@ -154,10 +161,16 @@ MessageTypes.ErrorReson[MessageTypes.ERR_SDK_FAILED]="sdk还没初始化";
MessageTypes.ErrorReson[MessageTypes.ERR_INTERFACE_NONE]="调用的接口不存在";
MessageTypes.ErrorReson[MessageTypes.ERR_INTERFACE_PARAMS_ERROR]="调用的接口,传递的参数不正确";
MessageTypes.ErrorReson[MessageTypes.ERR_INIT_RECORD_PLAY_BACK_FAILED]="初始化录制回放失败";
MessageTypes.ErrorReson[MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED]="获取录制回放数据失败";
MessageTypes.ErrorReson[MessageTypes.ERR_NETWORK]="网络错误";
MessageTypes.ErrorReson[MessageTypes.ERR_UNKNOWN]="未知错误";
MessageTypes.ErrorReson[MessageTypes.ERR_SOCKET_DISCONNECT]="MCU断开连接,已经离开会议";
MessageTypes.ErrorReson[MessageTypes.ERR_SOCKET_DISCONNECT]="MCU断开连接,已经离开课堂";
... ...
import ByteBuffer from 'libs/bytebuffer.min';
import Emiter from 'Emiter';
import MessageTypes from 'MessageTypes';
import Loger from 'Loger';
import pdu from 'pdus/index';
import PduType from 'pdus/PduType';
import PduConsts from 'pdus/PduConsts';
import ApeConsts from 'apes/ApeConsts';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import Base64 from 'base64-js';
import GlobalConfig from 'GlobalConfig';
import EngineUtils from 'EngineUtils';
import TimerCounter from "TimerCounter";
let parseBuffer;
// 日志对象
const loger = Loger.getLoger('RecordPlayBackParse');
const Default = 0;//未开始
const PLAY = 1;//播放中
const PAUSE = 2;//暂停
const SEEK = 3;//seek
const STOP = 4;//停止
class RecordPlayBackParse extends Emiter {
constructor() {
super();
loger.log("RecordPlayBackParse");
parseBuffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
parseBuffer.clear();
//console.log(parseBuffer);
this._recordPlaybackTimestamp = 0;//回放的时间
this._recordPlaybackMaxTime = 0;//录制回放的总时间
this._isReady = false;//录制回放是否已经准备完成
this._apes = {};
//this._messages = {};
this._conferApeMssages = {};//会议数据
this._chatApeMssages = {};//聊天数据
this._videoApeMssages = {};//视频数据
this._audioApeMssages = {};//音频数据
this._docApeMssages = {};//文档数据
this._whiteApeMssages = {};//白板数据
this._timerCounter = new TimerCounter();//计时器
this._timerCounter.addTimerCallBack(this._timerCounterUptate.bind(this), 1);
}
//method--------------------内部---------------------------------------------
// 注册Ape
registerApe(ape) {
this._apes[ape._session_id] = ape;
}
initReplay() {
this._stopTimerCounter();
this._recordPlaybackTimestamp = 0;//回放的时间
this._recordPlaybackMaxTime = 0;//录制回放的总时间
this._isReady = false;//录制回放是否已经准备完成
this._conferApeMssages = {};//会议数据
this._chatApeMssages = {};//聊天数据
this._videoApeMssages = {};//视频数据
this._audioApeMssages = {};//音频数据
this._docApeMssages = {};//文档数据
this._whiteApeMssages = {};//白板数据
}
//发送数据个各个APE模块处理,data是数据,seekTime是当前数据需要seek的时间长度(针对音视频的seek)
_everSocketMsgReceivedHandler(data, seekTime) {
let pduMsg = pdu.decode_pdu(data);
let pduType = pduMsg.get("type");
let pduData = pduMsg.get("data");
//*************非常重要******************
//客户端发送的所有125消息,MCU收到之后会痛120把消息返回给客户端,
//所以需要把125消息type转换为120,因为MCU在录制的时候是直接录制客户端发送的消息而不是MCU转换之后的
if (pduType == PduType.RCPDU_UNIFORM_SEND_DATA_REQUEST) {
pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST;
pduType = PduType.RCPDU_SEND_DATA_REQUEST;
}
loger.log('_everSocketMsgReceivedHandler->pduType', pduType, "seekTime->", seekTime);
switch (pduType) {
case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
//加入课堂请求返回数据处理
let joinConfPdu = pdu['RCConferenceJoinResponsePdu'].decode(pduData);
let pduResultCode = joinConfPdu.result;
loger.warn('RCPDU_CONNECT_PROVIDER_RESPONSE ->pduResultCode:' + pduResultCode);
switch (pduResultCode) {
case PduConsts.RET_SUCCESS:
//加入成功
//this._updateMCUConfInfoDescription(joinConfPdu.classDescription);
this._emit(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this.classInfo);
break;
case PduConsts.RET_FULL_CAPACITY:
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FULL);
break;
default:
loger.warn('JoinConfPdu-未知类型-等待处理.', pduResultCode);
break
}
break;
case PduType.RCPDU_SEND_DATA_REQUEST:
//先判断当前消息属于哪个APE 根据 sessionId来判断
let ape = this._apes[pduMsg.sessionId];
let sessionLabel = ApeConsts(pduMsg.sessionId);
//对方发送消息
if (ape) {
let subTypeLabel = pdu.id2type(pduMsg.subType);
//loger.log('MCU-SecondLayer封装消息', 'sessionId', sessionLabel, pduMsg.sessionId, 'subtype', subTypeLabel, pduMsg.subType);
//ape广播事件,只要ape中监听就能收到
ape._emit(pduMsg.subType, pduMsg.data, seekTime);//seekTime是音视频模块seek的时间长度
} else {
loger.warn(sessionLabel + '尚未注册');
}
break;
default:
loger.warn('PDU-未知类型-等待处理.', pduType);
}
}
//解析和储存,录制回放EverSocket底层消息处理 data-数据;timestamp-数据对应的时间戳
_parseSaveSocketMsgReceivedHandler(data, timestamp) {
let pduMsg = pdu.decode_pdu(data);
let pduType = pduMsg.get("type");
let pduData = pduMsg.get("data");
//*************非常重要******************
//客户端发送的所有125消息,MCU收到之后会痛120把消息返回给客户端,
//所以需要把125消息type转换为120,因为MCU在录制的时候是直接录制客户端发送的消息而不是MCU转换之后的
if (pduType == PduType.RCPDU_UNIFORM_SEND_DATA_REQUEST) {
pduMsg.type = PduType.RCPDU_SEND_DATA_REQUEST;
pduType = PduType.RCPDU_SEND_DATA_REQUEST;
}
loger.log('pduType', pduType);
switch (pduType) {
case PduType.RCPDU_CONNECT_PROVIDER_RESPONSE:
//加入课堂请求返回数据处理
let joinConfPdu = pdu['RCConferenceJoinResponsePdu'].decode(pduData);
let pduResultCode = joinConfPdu.result;
loger.warn('RCPDU_CONNECT_PROVIDER_RESPONSE ->pduResultCode:' + pduResultCode);
switch (pduResultCode) {
case PduConsts.RET_SUCCESS:
//加入成功
//this._updateMCUConfInfoDescription(joinConfPdu.classDescription);
this._emit(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this.classInfo);
break;
case PduConsts.RET_FULL_CAPACITY:
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FULL);
break;
default:
loger.warn('JoinConfPdu-未知类型-等待处理.', pduResultCode);
break
}
break;
case PduType.RCPDU_SEND_DATA_REQUEST:
//先判断当前消息属于哪个APE 根据 sessionId来判断
let ape = this._apes[pduMsg.sessionId];
let sessionLabel = ApeConsts(pduMsg.sessionId);
//只做解析存储,不对外发送
loger.log('解析数据-timestamp->', timestamp, 'sessionId->', pduMsg.sessionId, 'sessionLabel->', sessionLabel);
switch (pduMsg.sessionId) {
case ApeConsts.CONFERENCE_SESSION_ID:
this.saveParseData(data, timestamp, this._conferApeMssages);
break;
case ApeConsts.CHAT_SESSION_ID:
this.saveParseData(data, timestamp, this._chatApeMssages);
break;
case ApeConsts.DOCSHARING_SESSION_ID:
this.saveParseData(data, timestamp, this._docApeMssages);
break;
case ApeConsts.WHITEBOARD_SESSION_ID:
this.saveParseData(data, timestamp, this._whiteApeMssages);
break;
case ApeConsts.VIDEO_SESSION_ID:
this.saveParseData(data, timestamp, this._videoApeMssages);
break;
case ApeConsts.AUDIO_SESSION_ID:
this.saveParseData(data, timestamp, this._audioApeMssages);
break;
default:
break;
}
break;
default:
loger.warn('PDU-未知类型-等待处理.', pduType);
}
}
//保存数据
saveParseData(data, timestamp, apeMessages) {
let messageItem = apeMessages[timestamp];
if (!messageItem) {
apeMessages[timestamp] = [];//数组存数据,因为有1秒内收到多个消息的情况,timestamp是按秒记录的
messageItem = apeMessages[timestamp];
}
messageItem.push({"timestamp": timestamp, "byteData": data});
}
//开启计时器
_startTimerCounter() {
if (this._timerCounter) {
this._timerCounter.startTimer();
}
}
//停止计时器
_stopTimerCounter() {
if (this._timerCounter) {
this._timerCounter.stopTimer();
}
}
_timerCounterUptate() {
this._recordPlaybackTimestamp = this._recordPlaybackTimestamp + 1;//计时
if (this._recordPlaybackTimestamp >= this._recordPlaybackMaxTime) {
this._stopTimerCounter();
loger.log("录制回放结束...当前时间->", this._recordPlaybackTimestamp, " 总时间->", this._recordPlaybackMaxTime);
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": STOP});
return;
}
loger.log("录制回放中...", this._recordPlaybackTimestamp);
this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": this._recordPlaybackTimestamp});
//各个APE模块根据时间查找消息数据
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._conferApeMssages);
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._chatApeMssages);
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._docApeMssages);
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._whiteApeMssages);
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._videoApeMssages);
this._searchMessageFromTime(this._recordPlaybackTimestamp, this._audioApeMssages);
}
//加载录制文件
readyRecordPlay() {
this.initReplay();
loger.log("读取回放数据");
//let url = `http://123.56.73.119:80/h5dev/20170306/1357644520_20170306.rec`;
let url = `http://${ GlobalConfig.RecordServerIP}:${ GlobalConfig.RecordServerPort}/${GlobalConfig.recordFileName}`;
loger.log(url);
fetch(url, {
timeout: 90000 //加载文件超时时间1分30秒
})
.then(ret => {
if (ret.ok) {
return ret.arrayBuffer();
} else {
loger.error(`读取回放数据-网络异常.状态码:${ret.status}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
throw '';
}
})
.then(ret => {
if (ret) {
loger.log('读取回放数据-完成');
this._loadRecordDataSuccess(ret);
} else {
loger.warn('读取回放数据-失败.');
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
}
})
.catch(err => {
loger.error(`读取回放数据.状态码:${err}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_RECORD_PLAY_BACK_DATA_FAILED);
});
}
_loadRecordDataSuccess(arrayBuffer) {
loger.log("获取录制回放数据的长度", arrayBuffer.byteLength);
if (parseBuffer) {
parseBuffer.clear();
parseBuffer.append(arrayBuffer);
//解析数据
this.parseArrayBuf();
}
}
//解析数据
parseArrayBuf() {
//this._messages = {};
let byteLength = parseBuffer.offset;
parseBuffer.byteOffset = 0;
var position = 0;
while (position < byteLength) {
let timestamp = parseBuffer.readUInt32(position);
position += 4;//4字节
let byteLen = parseBuffer.readUInt32(position);
position += 4;//4字节
let byteData = parseBuffer.buffer.slice(position, (position + byteLen));
position += byteLen;
this._parseSaveSocketMsgReceivedHandler(byteData, timestamp);
//记录最后一个数据的时间戳作为整个录制回放的总时间戳
this._recordPlaybackMaxTime = timestamp;
}
this._recordPlaybackTimestamp = 0;
this._isReady = true;
this._stopTimerCounter();
GlobalConfig.recordPlaybackMaxTime = this._recordPlaybackMaxTime;
loger.log("录制回放数据解析完成,录制回放的总时间长为->", this._recordPlaybackMaxTime);
//console.log("_messages", this._messages);
loger.log("_conferApeMssages", this._conferApeMssages);
loger.log("_chatApeMssages", this._chatApeMssages);
loger.log("_docApeMssages", this._docApeMssages);
loger.log("_whiteApeMssages", this._whiteApeMssages);
loger.log("_videoApeMssages", this._videoApeMssages);
loger.log("_audioApeMssages", this._audioApeMssages);
this._emit(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, {"recordPlaybackMaxTime": this._recordPlaybackMaxTime});
}
//根据时间查找数据
_searchMessageFromTime(_timestamp, _apeMessages) {
let msgDataArr = _apeMessages[_timestamp];
if (!msgDataArr) {
//没有数据,需要查找当前时间点属于哪一个时间戳关键帧
} else {
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let i = 0; i < msgDataArr.length; i++) {
this._everSocketMsgReceivedHandler(msgDataArr[i].byteData, 0);
}
}
}
/*_searchMessageFromTime(_timestamp,_apeMessages){
let msgDataArr=this._messages[_timestamp];
if(!msgDataArr){
//没有数据,需要查找当前时间点属于哪一个时间戳关键帧
}else {
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for(let i=0;i<msgDataArr.length;i++){
this._everSocketMsgReceivedHandler(msgDataArr[i].byteData);
}
}
}*/
//method------------外部接口-------------------------------------
//开始播放
startRecordPlayback(_param) {
if (!this._isReady) {
return {"code": ApeConsts.RETURN_FAILED, "data": "录制回放还未准备完成"};
}
this._startTimerCounter();
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": PLAY});
}
//停止播放
stopRecordPlayback(_param) {
this._recordPlaybackTimestamp = 0;
this._stopTimerCounter();
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": STOP});
}
//暂停播放
pauseRecordPlayback(_param) {
this._stopTimerCounter();
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {"status": PAUSE});
}
//跳转到指定时间点播放
seekRecordPlayback(_param) {
if (!this._isReady) {
return {"code": ApeConsts.RETURN_FAILED, "data": "录制回放还未准备完成"};
}
if (!_param || !_param.time) {
return {"code": ApeConsts.RETURN_FAILED, "data": "参数不正确"};
}
//先暂停,更改进行的时间
this._stopTimerCounter()
this._recordPlaybackTimestamp = _param.time || 0;
//各个ape模块查找关键帧数据
this._searchKeyfram();
}
_searchKeyfram() {
//查找关键帧,找到关键帧后再继续播放
this._searchApeMessageKeyfram(this._conferApeMssages, ApeConsts.CONFERENCE_SESSION_ID);
this._searchApeMessageKeyfram(this._docApeMssages, ApeConsts.DOCSHARING_SESSION_ID);
this._searchApeMessageKeyfram(this._whiteApeMssages, ApeConsts.WHITEBOARD_SESSION_ID);
this._searchApeMessageKeyfram(this._videoApeMssages, ApeConsts.VIDEO_SESSION_ID);
this._searchApeMessageKeyfram(this._audioApeMssages, ApeConsts.AUDIO_SESSION_ID);
//聊天模块的比较特殊,消息是累计的
this._searchChatApeMessageKeyfram(this._chatApeMssages, ApeConsts.CHAT_SESSION_ID);
//各个ape模块无论有没有找到关键帧数据,都继续播放
this._startTimerCounter();
}
//查找ape关键帧数据
_searchApeMessageKeyfram(_apeMessages, _apeId) {
let messageItem;
let keyFrameSeekTime = 0;
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
messageItem = _apeMessages[i];
if (messageItem) {
keyFrameSeekTime = (this._recordPlaybackTimestamp - i)
loger.log("SEEK->APE", ApeConsts(_apeId), this._recordPlaybackTimestamp, "查找到相连的timestamp->", i, '需要seek->', keyFrameSeekTime, "秒");
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let k = 0; k < messageItem.length; k++) {
this._everSocketMsgReceivedHandler(messageItem[k].byteData, keyFrameSeekTime);
}
if (_apeId == ApeConsts.AUDIO_SESSION_ID || _apeId == ApeConsts.VIDEO_SESSION_ID) {
this._emit(MessageTypes.RECORD_PLAYBACK_UPDATE, {
"status": SEEK,
"keyFrameSeekTime": keyFrameSeekTime
});
}
return;
}
}
loger.log("SEEK->APE", ApeConsts(_apeId), this._recordPlaybackTimestamp, "没有查找到相连的数据");
}
//查找聊天模块ape关键帧数据,聊天模块比较特殊,消息是累积的,当前时间戳之前的都需要显示
_searchChatApeMessageKeyfram(_apeMessages) {
let messageItem;
let keyFrameSeek = 0;
for (let i = this._recordPlaybackTimestamp; i > 0; i--) {
messageItem = _apeMessages[i];
if (messageItem) {
//把时间点对应的数据发送,同一秒内有存在多个数据的情况
for (let i = 0; i < messageItem.length; i++) {
this._everSocketMsgReceivedHandler(messageItem[i].byteData, 0);
}
}
}
}
}
RecordPlayBackParse.prototype.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS = RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS = 'class_join_recordPlayback_success';//加入录制回放成功
export default new RecordPlayBackParse;
... ...
... ... @@ -4,6 +4,9 @@ import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import MD5 from "md5";
import ApeConsts from 'apes/ApeConsts';
import iphunter from 'iphunter';
import fetchJsonp from 'fetch-jsonp';
// 日志对象
const loger = Loger.getLoger('Sass');
... ... @@ -37,8 +40,8 @@ class Sass extends Emiter {
*/
let url = `http://${_initInfo.portal}/3m/api/meeting/joinParams.do?meetingNumber=${_initInfo.classId}&userID=${_initInfo.userId}`;
loger.log('1.初始化init获取课堂校验信息.');
console.log(url);
console.log(_initInfo);
loger.log(url);
loger.log(_initInfo);
fetch(url, {
timeout: 5000
})
... ... @@ -85,7 +88,7 @@ class Sass extends Emiter {
// Sass校验开始-->密码校验(如果需要密码)--->MD5校验----------------------------------------------------
passwordAndMd5Checking(_param) {
loger.log('2.开始Sass校验');
console.log(_param);
loger.log(_param);
confInfo = _param;
// 密码校验
if (confInfo.passwordRequired === 'true' || confInfo.passwordRequired === true) {
... ... @@ -114,7 +117,7 @@ class Sass extends Emiter {
}
let url = `http://${confInfo.portal}/3m/api/meeting/signIn.do?siteId=${confInfo.siteId}&classId=${confInfo.classId}&isTeacher=${isTeacher}&password=${confInfo.password}`;
loger.log('3.会议密码校验', url);
loger.log('3.课堂密码校验', url);
fetch(url, {
timeout: 5000
})
... ... @@ -122,7 +125,7 @@ class Sass extends Emiter {
if (ret.status === 200) {
return ret.text();
} else {
loger.error(`会议密码校验-网络异常.状态码:${ret.status}`);
loger.error(`课堂密码校验-网络异常.状态码:${ret.status}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_NETWORK);
throw '';
}
... ... @@ -130,20 +133,20 @@ class Sass extends Emiter {
.then(ret => {
let rectObj = JSON.parse(ret);
if (rectObj.flag === 'false' || rectObj.flag === false) {
loger.error(`会议密码校验-失败.`);
loger.error(`课堂密码校验-失败.`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_PASSWORD_WRONG);
return;
}
if (rectObj.flag === 'true' || rectObj.flag === true) {
loger.log(`会议密码校验-成功.`);
loger.log(`课堂密码校验-成功.`);
this.sendMD5Checking();
return;
}
loger.error(`会议密码校验-协议异常.`, rectObj);
loger.error(`课堂密码校验-协议异常.`, rectObj);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_PROTOCOL);
})
.catch(err => {
loger.error(`会议密码校验-异常.状态码:${err}`);
loger.error(`课堂密码校验-异常.状态码:${err}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_JOIN_FAILED);
});
}
... ... @@ -182,7 +185,7 @@ class Sass extends Emiter {
GlobalConfig.maxAudioChannels=confInfo.maxAudioChannels;
GlobalConfig.maxMediaChannels=confInfo.maxMediaChannels;*/
loger.log('MD5校验完成');
console.log(ret);
loger.log(ret);
this._emit(Sass.SUCCESS, ret);
} else {
loger.log('MD5校验-失败.');
... ... @@ -196,7 +199,7 @@ class Sass extends Emiter {
});
}
// 获取会议基本详情------------------------------------------------------------------------------------
// 获取课堂基本详情------------------------------------------------------------------------------------
getClassDetail() {
let url = `http://${confInfo.portal}/3m/meeting/getClassH5.do?classNumber=${confInfo.classId}`;
loger.log('获取Class详情.', url);
... ... @@ -227,7 +230,7 @@ class Sass extends Emiter {
});
}
//获取课堂会议的完整信息--------------------------------------------------------------------------------
//获取课堂课堂的完整信息--------------------------------------------------------------------------------
getClassParam() {
/*
参数 (application/x-www-form-urlencoded):
... ... @@ -246,10 +249,10 @@ class Sass extends Emiter {
meetingNumber String 课堂号 对应的是classId
*/
var timestamp = new Date().getTime();
var authId = MD5(confInfo.classId + "" + timestamp);//课堂号+时间戳 的字符串,转成MD5
let url = `http://${confInfo.portal}/3m/api/meeting/detail.do?meetingNumber=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;
loger.log('5.获取课堂会议的完整信息 ');
console.log(url);
var authId = MD5(GlobalConfig.classId + "" + timestamp);//课堂号+时间戳 的字符串,转成MD5
let url = `http://${GlobalConfig.portal}/3m/api/meeting/detail.do?meetingNumber=${GlobalConfig.classId}&timestamp=${timestamp}&authId=${authId}`;
loger.log('5.获取课堂课堂的完整信息 ');
loger.log(url);
fetch(url, {
timeout: 5000
})
... ... @@ -257,7 +260,7 @@ class Sass extends Emiter {
if (ret.ok) {
return ret.json();
} else {
loger.error(`获取课堂会议的完整信息-网络异常.状态码:${ret.status}`);
loger.error(`获取课堂课堂的完整信息-网络异常.状态码:${ret.status}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
throw '';
... ... @@ -265,15 +268,15 @@ class Sass extends Emiter {
})
.then(ret => {
if (ret.code === 0) {
loger.log('获取课堂会议的完整信息完成');
loger.log('获取课堂课堂的完整信息完成');
this._emit(Sass.CLASS_GET_CLASS_PARAM, ret);
} else {
loger.warn('获取课堂会议的完整信息 失败.');
loger.warn('获取课堂课堂的完整信息 失败.');
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
}
})
.catch(err => {
loger.error(`获取课堂会议的完整信息异常.状态码:${err}`);
loger.error(`获取课堂课堂的完整信息异常.状态码:${err}`);
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_GET_CLASS_PARAML);
});
}
... ... @@ -291,6 +294,10 @@ class Sass extends Emiter {
0 成功, 1 验证信息错误
*/
sassDeleteDocument(_param) {
if(GlobalConfig.isRecordPlayBack){
loger.log('录制回放中,能删除文档');
return;
}
var timestamp = new Date().getTime();
var authId = MD5(_param.docId + "" + _param.classId + "" + timestamp);// docId+classId+timestamp的字符串,转成MD5
let url = `http://${confInfo.portal}/3m/api/document/deleteRelation.do?docId=${_param.docId}&classId=${confInfo.classId}&timestamp=${timestamp}&authId=${authId}`;
... ... @@ -337,6 +344,10 @@ class Sass extends Emiter {
code 0 成功 1 课堂号为空 2 无效的课堂号 3 验证信息错误*/
saveClassStatusInfo(_param) {
if(GlobalConfig.isRecordPlayBack){
loger.log('录制回放中,不需要保存课堂信息');
return;
}
//{"classStatusInfo":classStatusInfo}
var timestamp = new Date().getTime();
var authId = MD5(confInfo.classId + "" + timestamp);// (classId+timestamp)的字符串,转成MD5
... ... @@ -383,6 +394,10 @@ class Sass extends Emiter {
//保存录制的信息,主要是录制文件的名称,必须和MCU录制的文件名相同
saveClassRecordContrlInfo(_param) {
if(GlobalConfig.isRecordPlayBack){
loger.log('录制回放中,不需要保存');
return;
}
loger.log('保存开始录制信息');
let key = "3mang123A";
let siteID = GlobalConfig.siteId;
... ... @@ -390,16 +405,16 @@ class Sass extends Emiter {
let userID = GlobalConfig.userId;
let userName = GlobalConfig.userName;
let meetingName = GlobalConfig.className;
let startTime =GlobalConfig.classBeginTime;
let startTime = GlobalConfig.classBeginTime;
let endTime = GlobalConfig.classEndTime;
let playUrl = "";
let streamName = GlobalConfig.recordFileName;
let confRecordFileName=GlobalConfig.recordFileName;
let confRecordFileName = GlobalConfig.recordFileName;
let downloadUrl = "";
let recordStatus = GlobalConfig.classStatus;
let recordTimestamp =GlobalConfig.classTimestamp;
let recordTimestamp = GlobalConfig.classTimestamp;
let timestamp = new Date().getTime();;
let timestamp = new Date().getTime();
let authId = MD5(key + siteID + meetingID + timestamp);
let url = `http://${confInfo.portal}/3m/recordingMeeting/insertRecordingMeeting.do?siteID=${siteID}&meetingID=${meetingID}&userID=${userID}&userName=${userName}&meetingName=${meetingName}&startTime=${startTime}&endTime=${endTime}&playUrl=${playUrl}&streamName=${streamName}&downloadUrl=${downloadUrl}&configFile=${confRecordFileName}&timestamp=${timestamp}&recordTimestamp=${recordTimestamp}&authId=${authId}`;
loger.log('saveClassRecordContrlInfo', url);
... ... @@ -420,7 +435,7 @@ class Sass extends Emiter {
loger.log('保存开始录制信息 完成');
this._emit(Sass.CLASS_SAVE_RECORD_INFO_SUCCESS, _param);
} else {
loger.warn('保存开始录制信息 失败.',ret);
loger.warn('保存开始录制信息 失败.', ret);
}
})
.catch(err => {
... ... @@ -428,7 +443,6 @@ class Sass extends Emiter {
});
}
}
Sass.prototype.SUCCESS = Sass.SUCCESS = 'Sass_success';
... ... @@ -437,8 +451,8 @@ Sass.prototype.CLASS_GET_CLASS_PARAM = Sass.CLASS_GET_CLASS_PARAM = 'sass_class_
Sass.prototype.CLASS_GET_CLASS_DETAIL = Sass.CLASS_GET_CLASS_DETAIL = 'sass_class_getClassDetail_message';
Sass.prototype.DELETE_DOCUMENT_SUCCESS = Sass.DELETE_DOCUMENT_SUCCESS = 'sass_class_deleteDocumentSuccess_message';//删除文档成功
Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS = Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'sass_class_saveClassStatusInfoSuccess_message';//保存会议状态信息
Sass.prototype.CLASS_SAVE_RECORD_INFO_SUCCESS = Sass.CLASS_SAVE_RECORD_INFO_SUCCESS = 'sass_class_saveClassRecordInfoSuccess_message';//保存录制会议信息
Sass.prototype.CLASS_SAVE_STATUS_INFO_SUCCESS = Sass.CLASS_SAVE_STATUS_INFO_SUCCESS = 'sass_class_saveClassStatusInfoSuccess_message';//保存课堂状态信息
Sass.prototype.CLASS_SAVE_RECORD_INFO_SUCCESS = Sass.CLASS_SAVE_RECORD_INFO_SUCCESS = 'sass_class_saveClassRecordInfoSuccess_message';//保存录制课堂信息
export default new Sass;
... ...
import Emiter from 'Emiter';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import GlobalConfig from 'GlobalConfig';
import MD5 from "md5";
import ApeConsts from 'apes/ApeConsts';
import iphunter from 'iphunter';
import Server from "config/Server";
import fetchJsonp from 'fetch-jsonp';
// 日志对象
const loger = Loger.getLoger('ServerCheck');
//ip选点流程的状态
let isRequestMcuCallback = false;//是否获取最佳mcu返回
let isRequestMsCallback = false;//是否获取ms最佳返回
let isTestFromSass=false;
let isTestFromServer=false;
let tempMcuIp="";
let tempMcuPort="";
let tempMsIp="";
let tempMsPort="";
let msDefaultPort=":1935";
let mcuDefaultPort="7777";
let speedTestPort = ':5555';//测速端口统一
let checkMcuIpGroup =[];//储存MCU需要查询的ip数组
let checkMsIpGroup =[];//储存MCU需要查询的ip数组
class ServerCheck extends Emiter {
constructor() {
super();
}
//根据userIp获取ip相关的信息,参数是userIp
getUserIpInfo(token, userIp) {
//重置ip选点流程状态
isRequestMcuCallback = false;
isRequestMsCallback = false;
isTestFromSass=false;
isTestFromServer=false;
checkMcuIpGroup =[];
checkMsIpGroup =[];
let userIpInfo = new Object;
userIpInfo.ret = -1;
let ip = userIp;
let md5Str = MD5("addr=" + ip + "&token=b657c3507b324353e09c1958ee956a98efceb3e3");//("addr=" + ip + "&token=b657c3507b324353e09c1958ee956a98efceb3e3"),转成MD5
let timestamp = new Date().getTime();
let location = `http://ipapi.ipip.net/find?addr=${ip}&sid=14&uid=5237&sig=${md5Str}&_=${timestamp}`;
loger.log('获取IP信息 ', userIp, location);
fetchJsonp(location, {
timeout: 3000,
}).then(function (response) {
return response.json()
}).then(function (json) {
loger.log('获取IP信息返回', json)
if (json) {
userIpInfo.ret = json.ret;
userIpInfo.country = json.data[0];//国家
userIpInfo.province = json.data[1];//省份
userIpInfo.city = json.data[2];//城市
userIpInfo.isp = json.data[4];//运营商
}
this.serverGetUserIpInfoCallback(userIpInfo);
}.bind(this)).catch(function (ex) {
loger.log('获取IP信息失败', ex.message)
this.serverGetUserIpInfoCallback(userIpInfo);
}.bind(this));
}
//获取ip信息返回
serverGetUserIpInfoCallback(userIpInfo) {
loger.log("获取IP详情,开始处理", userIpInfo);
if (userIpInfo.ret == "ok") {
GlobalConfig.country = userIpInfo.country;//国家
GlobalConfig.city = userIpInfo.city;//城市
GlobalConfig.province = userIpInfo.province;//服务商
GlobalConfig.isp = userIpInfo.isp;//服务商
loger.log("获取ip详情成功,country:" + GlobalConfig.country + ",city:" + GlobalConfig.city + ",isp:" + GlobalConfig.isp);
this._chooseBestIpFromServer();
}
else {
loger.log("获取ip详情失败");
this._chooseBestIpFromSassParam();
}
}
//从IPIP服务列表中选择最快的IP
_chooseBestIpFromServer() {
loger.log("从Server服务列表中选择最快的IP");
isRequestMcuCallback=false;
isRequestMsCallback=false;
isTestFromServer=true;
isTestFromSass=false;
//country, province, ctiy, isp, jsona
checkMcuIpGroup =this._returnServerMCU(
GlobalConfig.country,
GlobalConfig.province,
GlobalConfig.city,
GlobalConfig.isp,
Server.serverList);
checkMsIpGroup = this._returnServerMS(
GlobalConfig.country,
GlobalConfig.province,
GlobalConfig.city,
GlobalConfig.isp,
Server.serverList);
let mcuArr=[];
let msArr=[];
for(let i in checkMcuIpGroup){
if(checkMcuIpGroup[i]){
mcuArr.push(checkMcuIpGroup[i].ip+speedTestPort);
}
}
for(let k in checkMsIpGroup){
if(checkMsIpGroup[k]){
msArr.push(checkMsIpGroup[k].ip+speedTestPort);
}
}
this.getBestMcuServer(mcuArr);
this.getBestMsServer(msArr);
}
//从Sass返回的msList mcuList中选点
_chooseBestIpFromSassParam() {
loger.log("从Sass服务列表中选择最快的IP");
isRequestMcuCallback = false;
isRequestMsCallback = false;
isTestFromSass=false;
isTestFromServer=false;
checkMcuIpGroup =GlobalConfig.mcuList;
checkMsIpGroup =GlobalConfig.msList;
//MCU
let mcuIpGroup = [];
for (let i = 0; i < checkMcuIpGroup.length; i++) {
let ipPort = checkMcuIpGroup[i].ip+speedTestPort;
mcuIpGroup.push(ipPort)
}
this.getBestMcuServer(mcuIpGroup);
//MS
let msIpGroup = [];
for (let k = 0; k < checkMsIpGroup.length; k++) {
let ipPort = checkMsIpGroup[k].ip+speedTestPort;
msIpGroup.push(ipPort)
}
this.getBestMsServer(msIpGroup);
}
//获取最快的MCU服务器地址,参数是一个ip数组
getBestMcuServer(_param) {
loger.log('开始MCU选点 ', _param);
if(_param==null||_param.length<1){
this._getBestMcuServerCallbackHandler("")
return;
}
iphunter(_param, function (fatest_ip_response) {
if (!fatest_ip_response) {
loger.warn('getBestMcuServer -> nothing!');
this._getBestMcuServerCallbackHandler("")
} else {
//loger.log('getBestMcuServer done -> ', fatest_ip_response);
this._getBestMcuServerCallbackHandler(fatest_ip_response)
}
}.bind(this), 3000);
}
//获取最快的MS服务器地址,参数是一个ip数组
getBestMsServer(_param) {
loger.log('开始MS选点 ', _param);
if(_param==null||_param.length<1){
this._getBestMsServerCallbackHandler("")
return;
}
iphunter(_param, function (fatest_ip_response) {
if (!fatest_ip_response) {
loger.warn('getBestMsServer -> nothing!');
this._getBestMsServerCallbackHandler("");
} else {
//loger.log('getBestMsServer done -> ', fatest_ip_response);
this._getBestMsServerCallbackHandler(fatest_ip_response);
}
}.bind(this), 3000);
}
_getBestMcuServerCallbackHandler(_data) {
loger.log("MCU选点返回1", _data);
if (isRequestMcuCallback) {
loger.log("MCU选点,已经有返回");
return;
}
isRequestMcuCallback = true;
if (_data) {
let server = _data.split(":");
if (server[0]) {
tempMcuIp= server[0];
}
tempMcuPort=mcuDefaultPort;
for(let i=0;i<checkMcuIpGroup.length;i++){
if(tempMcuIp==checkMcuIpGroup[i].ip){
tempMcuPort=checkMcuIpGroup[i].port||mcuDefaultPort;
break;
}
}
}
loger.log("MCU选点返回2",tempMcuIp,tempMcuPort);
this._startConnectMcu();
}
_getBestMsServerCallbackHandler(_data) {
loger.log("MS选点返回1", _data);
if (isRequestMsCallback) {
loger.log("_getBestMsServerCallbackHandler,已经有返回");
return;
}
isRequestMsCallback = true;
if (_data) {
let server = _data.split(":");
if (server[0]) {
tempMsIp= server[0];
}
tempMsPort=msDefaultPort;
for(let i=0;i<checkMsIpGroup.length;i++){
if(tempMsPort==checkMsIpGroup[i].ip){
tempMsPort=checkMsIpGroup[i].port||msDefaultPort;
break;
}
}
}
loger.log("MS选点返回2", tempMsIp,tempMsPort);
this._startConnectMcu();
}
//ip选点结束,开始连接MCU
_startConnectMcu() {
if (isRequestMcuCallback && isRequestMsCallback) {
if (isTestFromServer && !isTestFromSass) {
//从Server服务列表中选点结束,如果没有选到合适的,从Sass的列表中获取
if(!tempMcuIp||!tempMsIp){
this._chooseBestIpFromSassParam();
}else {
GlobalConfig.MCUServerIP=tempMcuIp;
GlobalConfig.MCUServerPort=tempMcuPort;
GlobalConfig.MSServerIP=tempMsIp;
GlobalConfig.MSServerPort=tempMsPort;
loger.log("Server选点完成", "mcu-->",GlobalConfig.MCUServerIP,GlobalConfig.MCUServerPort,"ms---->",GlobalConfig.MSServerIP,GlobalConfig.MSServerPort);
this._emit(ServerCheck.SEVER_CHECK_BEST_IP_SUCCESS);
}
} else {
//从Sass返回的服务列表中选点结束
if(tempMcuIp){
GlobalConfig.MCUServerIP=tempMcuIp;
GlobalConfig.MCUServerPort=tempMcuPort;
}
if(tempMsIp){
GlobalConfig.MSServerIP=tempMsIp;
GlobalConfig.MSServerPort=tempMsPort;
}
loger.log("Sass选点完成", "mcu-->",GlobalConfig.MCUServerIP,GlobalConfig.MCUServerPort,"ms---->",GlobalConfig.MSServerIP,GlobalConfig.MSServerPort);
this._emit(ServerCheck.SEVER_CHECK_BEST_IP_SUCCESS);
}
} else {
loger.warn("_startConnectMcu->正在选点", isRequestMcuCallback, isRequestMsCallback);
}
}
//检测MCU连接地址
_returnServerMCU(country, province, ctiy, isp, jsona) {
let countryData=jsona.MCU[country];
//按country没有查找到就返回default
if(!countryData){
countryData=jsona.MCU.default;
loger.log("_returnServerMCU->countryData->default",countryData);
return countryData;
}
if(country!="中国"){
loger.log("_returnServerMCU->countryData",countryData);
return countryData;
}
//中国的需要细分
//按isp查找
let ispData=countryData.isp[isp];
//isp查找到就返回
if(ispData){
loger.log("_returnServerMCU->ispData",ispData);
return ispData;
}
//isp没查找到,用province
let provinceData=countryData.province[province];
//用province查找到就返回
if(provinceData){
loger.log("_returnServerMCU->provinceData",provinceData);
return provinceData;
}
//isp province都没有,使用default
let defaultData=countryData.default
if(defaultData){
loger.log("_returnServerMCU->defaultData",defaultData);
return defaultData;
}else {
loger.log("_returnServerMCU->defaultData","");
return [];
}
return [];
}
//检测MS连接地址
//Config.ipInfo
_returnServerMS(country, province, ctiy, isp, jsona) {
let countryData=jsona.MS[country];
//按country没有查找到就返回default
if(!countryData){
countryData=jsona.MS.default;
loger.log("_returnServerMS->countryData->default",countryData);
return countryData;
}
if(country!="中国"){
loger.log("_returnServerMS->countryData",countryData);
return countryData;
}
//中国的需要细分
//按isp查找
let ispData=countryData.isp[isp];
//isp查找到就返回
if(ispData){
loger.log("_returnServerMS->ispData",ispData);
return ispData;
}
//isp没查找到,用province
let provinceData=countryData.province[province];
//用province查找到就返回
if(provinceData){
loger.log("_returnServerMS->provinceData",provinceData);
return provinceData;
}
//isp province都没有,使用default
let defaultData=countryData.default
if(defaultData){
loger.log("_returnServerMS->defaultData",defaultData);
return defaultData;
}else {
loger.log("_returnServerMS->defaultData","");
return [];
}
return [];
}
}
ServerCheck.prototype.SEVER_CHECK_BEST_IP_SUCCESS = ServerCheck.SEVER_CHECK_BEST_IP_SUCCESS = 'severCheck_checkBestIpSuccess_message';//获取最快的MS地址
export default new ServerCheck;
... ...
... ... @@ -32,6 +32,7 @@ class TimerCounter {
}
//停止
stopTimer(){
if(!this.isStart) return;
console.log("stopTimer",this.counter);
this.isStart=false;
this.timerClear();
... ...
... ... @@ -15,23 +15,22 @@
import pdu from 'pdus';
import Emiter from 'Emiter';
import mcu from 'mcu';
import McuObj from 'mcu';
import Loger from 'Loger';
import MessageTypes from 'MessageTypes';
import ApeConsts from './ApeConsts';
import ArrayBufferUtil from 'libs/ArrayBufferUtil';
import PduConsts from 'pdus/PduConsts';
import GlobalConfig from 'GlobalConfig';
import RecordPlayBackParse from 'RecordPlayBackParse';
// 日志对象
const loger = Loger.getLoger('Ape');
export default class Ape extends Emiter {
constructor(
session_id,
constructor(session_id,
session_name,
session_tag
) {
session_tag) {
super();
this._session_id = session_id;
this._channel_id = session_id; // session_id === channel_id
... ... @@ -52,58 +51,49 @@ export default class Ape extends Emiter {
//先收到onJoinSessionHandlerSuccess 后收到 onJoinChannelHandlerSuccess
// 监听底层MCU会议
this.mcu = mcu;
// 监听底层MCU课堂
this.mcu = McuObj;
this.mcu.on(MessageTypes.CLASS_JOIN_MCU_SUCCESS, this._mcuConferenceJoinSuccessHandler.bind(this));
this.mcu.registerApe(this);
//录制回放
this.recordPlayBackParse = RecordPlayBackParse;
this.recordPlayBackParse.on(RecordPlayBackParse.CLASS_JOIN_RECORD_PLAYBACK_SUCCESS, this._joinRecordPlaybackSuccessHandler.bind(this));
this.recordPlayBackParse.registerApe(this);
}
regResponsePduHandler() {
}
//停止APE一切操作
stopApe() {
loger.log("stopApe==============================");
}
// 消息处理
_pduMessageHandler(regBuffer) {
//loger.log("RCPDU_REG_ADAPTER==============================");
_pduMessageHandler(regBuffer,_seekTime) {
let seekTime=_seekTime||0;//这个只有在录制回放的时候才有
//loger.log("RCPDU_REG_ADAPTER============seekTime",seekTime);
if (this._apeDelayed) {
// this._apeDelayedMsgs.push(regBuffer);
// this._apeDelayedStart();
setTimeout(() => {
this._pduRegAdapterHandler(regBuffer);
},GlobalConfig.mcuDelay|| 12000);
this._pduRegAdapterHandler(regBuffer,seekTime);
}, GlobalConfig.mcuDelay || 2000);
return;
}
this._pduRegAdapterHandler(regBuffer);
this._pduRegAdapterHandler(regBuffer,seekTime);
}
// _apeDelayedStart() {
// if (this._apeDelayed && !this._apeDelayedTimer) {
// this._apeDelayedTimer = setInterval(this._delayedMsgHandler.bind(this), this._classInfo['mcuDelay'] || 10000);
// }
// }
// _apeDelayedStop() {
// clearInterval(this._apeDelayedTimer);
// this._apeDelayedTimer = 0;
// }
// // 延迟消息处理
// _delayedMsgHandler() {
// if (this._apeDelayedMsgs.length) {
// this._pduRegAdapterHandler(this._apeDelayedMsgs.pop());
// if (!this._apeDelayedMsgs.length) this._apeDelayedStop();
// }
// }
// 数据同步处理
_pduRegAdapterHandler(regBuffer) {
_pduRegAdapterHandler(regBuffer,seekTime) {
let regPdu = pdu['RCAdapterPdu'].decode(regBuffer);
let regItems = regPdu.item;
let regItemSize = regItems.length;
//loger.log(this._session_name + '数据同步消息');
loger.log(this._session_name + '数据同步消息.同步条数', regItemSize);
//console.log(regPdu);
//loger.log(this._session_name + '数据同步消息.同步条数', regItemSize,"seekTime->",seekTime);
for (var i = 0; i < regItemSize; ++i) {
let regItem = regItems[i];
let regItemType = regItem.type;
... ... @@ -172,13 +162,13 @@ export default class Ape extends Emiter {
case pdu.RCPDU_REG_TABLE_UPDATE_PDU:
let tableUpdateData = pdu['RCRegistryTableUpdateItemPdu'].decode(user_data);
let tableUpdateItems = tableUpdateData.items;
let tableUpdateItemsLen= tableUpdateItems.length;
loger.log("RCRegistryTableUpdateItemPdu "+tableUpdateItemsLen);
console.log(tableUpdateData);
let tableUpdateItemsLen = tableUpdateItems.length;
//loger.log("RCRegistryTableUpdateItemPdu " + tableUpdateItemsLen);
loger.log(tableUpdateData);
for (let i = 0; i < tableUpdateItemsLen; ++i) {
let tableItem = tableUpdateItems[i];
this.tableUpdateHandler(tableItem.owner, tableItem.itemIdx, tableItem.itemData);
this.tableUpdateHandler(tableItem.owner, tableItem.itemIdx, tableItem.itemData,seekTime);
}
break;
case pdu.RCPDU_REG_QUEUE_UPDATE_PDU:
... ... @@ -194,27 +184,35 @@ export default class Ape extends Emiter {
rosterInsertHandler(recordId, recordData) {
loger.warn(this._session_name + ' rosterInsertHandler 应有子类具体覆盖处理.');
}
rosterUpdateHandler(nodeId, nodeData) {
loger.warn(this._session_name + ' rosterUpdateHandler 应有子类具体覆盖处理.');
}
rosterDelHandler(recordData) {
loger.warn(this._session_name + ' rosterDelHandler 应有子类具体覆盖处理.');
}
tableInsertHandler(tableId, record) {
loger.warn(this._session_name + ' tableInsertHandler 应有子类具体覆盖处理.');
}
tableUpdateHandler(ownerId, recordId, recordData) {
tableUpdateHandler(ownerId, recordId, recordData,seekTime) {
loger.warn(this._session_name + ' tableUpdateHandler 应有子类具体覆盖处理.');
}
tableDeleteHandler(tableId, record) {
loger.warn(this._session_name + ' tableDelHandler 应有子类具体覆盖处理.');
}
onJoinChannelHandlerSuccess(){
onJoinChannelHandlerSuccess() {
loger.warn(this._session_name + ' onJoinChannelHandlerSuccess 应有子类具体覆盖处理.');
}
onJoinSessionHandlerSuccess(){
onJoinSessionHandlerSuccess() {
loger.warn(this._session_name + ' onJoinSessionHandlerSuccess 应有子类具体覆盖处理.');
}
// 加入Session处理
_joinSessionHandler(data) {
loger.log(this._session_name, ' -> 加入Session');
... ... @@ -233,7 +231,7 @@ export default class Ape extends Emiter {
}
}
// 依赖的会议创建完毕 - 发起Ape加入
// 依赖的课堂创建完毕 - 发起Ape加入
_mcuConferenceJoinSuccessHandler(_data) {
loger.log('创建Ape->',
'SessionId',
... ... @@ -243,7 +241,7 @@ export default class Ape extends Emiter {
'SessionTag',
this._session_tag);
// 会议依赖底层会议信息
// 课堂依赖底层课堂信息
//this._classInfo = classInfo;
this._classInfo = GlobalConfig.getClassInfo();
... ... @@ -260,6 +258,17 @@ export default class Ape extends Emiter {
this.send(joinChannelPdu);
}
// 依赖的录制回放创建完毕 - 发起Ape加入
_joinRecordPlaybackSuccessHandler(_data) {
loger.log('录制回放->Ape已经创建完毕->',
'SessionId',
this._session_id,
'SessionName',
this._session_name,
'SessionTag',
this._session_tag);
}
// 注册Key对象
registerKey(id, name, tag, user_data) {
let adapterItemPdu = new pdu['RCAdapterItemPdu'];
... ... @@ -301,10 +310,10 @@ export default class Ape extends Emiter {
send(appPdu) {
loger.log('Ape发送数据NORMAL PDU');
console.log(appPdu);
//console.log(appPdu);
//loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
return;
}
let normalPdu = pdu.create_normal_pdu(
... ... @@ -327,10 +336,10 @@ export default class Ape extends Emiter {
// 发送当前APE(session uniform包)
sendUniform(appPdu, top) {
loger.log('Ape发送数据UNIFORM PDU');
console.log(appPdu);
//console.log(appPdu);
//loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
return;
}
... ... @@ -352,10 +361,10 @@ export default class Ape extends Emiter {
sendChatUniform(appPdu, top) {
loger.log('Ape发送数据UNIFORM PDU');
console.log(appPdu);
//console.log(appPdu);
//loger.log('当前的状态============',GlobalConfig.getCurrentStatus().code);
if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
return;
}
... ...
... ... @@ -11,7 +11,7 @@ export default function ApeConsts(id) {
ApeConsts.CLASS_STATUS_WAIT= 0;//课堂还未开始
ApeConsts.CLASS_STATUS_STARTED= 1;//直播中
ApeConsts.CLASS_STATUS_PAUSE= 2;//暂停
ApeConsts.CLASS_STATUS_CLOSE= 3;//结束//这个是点击结束会议,把所有人踢出课堂,然后把状态值还原为0*************
ApeConsts.CLASS_STATUS_CLOSE= 3;//结束//这个是点击结束课堂,把所有人踢出课堂,然后把状态值还原为0*************
ApeConsts.CLASS_STATUS_UPTATE= 4;//更新课堂状态信息
ApeConsts.CLASS_WAIT_START = "class.wait.start";//课堂还未开始
... ... @@ -22,7 +22,7 @@ ApeConsts.CLASS_PAUSING = "class.update";//更新当前的状态信息
//课堂控制
ApeConsts.CLASS_ACTION_CLOSE_ALL=1;//所有人关闭会议
ApeConsts.CLASS_ACTION_CLOSE_ALL=1;//所有人关闭课堂
//课堂类型
ApeConsts.CLASS_TYPE_INTERACT= 1; // 互动课堂,通过MS转发音视频,不能进行H5观看
... ... @@ -35,7 +35,7 @@ public static const NR_GUEST:uint = 0; // 客人
public static const NR_NORMAL:uint = 1; // 普通与会者
public static const NR_ADMIN:uint = 2; // 管理员
public static const NR_MASTER:uint = 4; // 主持人
public static const NR_SLAVE:uint = 8; // 主讲人
public static const NR_PRESENTER:uint = 8; // 主讲人
public static const NR_ASSISTANT:uint = 16; // 助教
public static const NR_INVISIBLE:uint = 32; // 隐身用户
*/
... ... @@ -45,8 +45,8 @@ public static const NR_INVISIBLE:uint = 32; // 隐身用户
//ApeConsts.NR_GUEST = 0; // 客人
ApeConsts.NR_NORMAL = 1;// 普通与会者
ApeConsts.NR_ADMIN = 2;// 管理员
ApeConsts.NR_MASTER = 4; // 主持人
ApeConsts.NR_SLAVE = 8; // 主讲人
ApeConsts.NR_HOST = 4; // 主持人
ApeConsts.NR_PRESENTER = 8; // 主讲人
ApeConsts.NR_ASSISTANT = 16; // 助教
ApeConsts.NR_INVISIBLE = 32; // 隐身用户
... ... @@ -58,6 +58,23 @@ ApeConsts.normal="normal";//(普通角色/学生)
ApeConsts.record="record";//(暂时没用.
ApeConsts.invisible="invisible";//隐身用户
//下面做身份的数字和字符串对应关系
ApeConsts.userTypes={};
ApeConsts.userTypes[ApeConsts.NR_NORMAL]=ApeConsts.normal;
ApeConsts.userTypes[ApeConsts.NR_ADMIN]=ApeConsts.record;
ApeConsts.userTypes[ApeConsts.NR_HOST]=ApeConsts.host;
ApeConsts.userTypes[ApeConsts.NR_PRESENTER]=ApeConsts.presenter;
ApeConsts.userTypes[ApeConsts.NR_ASSISTANT]=ApeConsts.assistant;
ApeConsts.userTypes[ApeConsts.NR_INVISIBLE]=ApeConsts.invisible;
ApeConsts.userTypesToId={};
ApeConsts.userTypesToId[ApeConsts.normal]=ApeConsts.NR_NORMAL;
ApeConsts.userTypesToId[ApeConsts.record]=ApeConsts.NR_ADMIN;
ApeConsts.userTypesToId[ApeConsts.host]=ApeConsts.NR_HOST;
ApeConsts.userTypesToId[ApeConsts.presenter]=ApeConsts.NR_PRESENTER;
ApeConsts.userTypesToId[ApeConsts.assistant]=ApeConsts.NR_ASSISTANT;
ApeConsts.userTypesToId[ApeConsts.invisible]=ApeConsts.NR_INVISIBLE;
////最新定义的角色身份 20170220
//ApeConsts.USER_TYPE_HOST=1;//(主持人/老师)
//ApeConsts.USER_TYPE_ASSISTANT=2;//(助教)
... ...
... ... @@ -21,6 +21,7 @@ class AudioApe extends Ape {
ApeConsts.AUDIO_SESSION_TAG
);
this.releaseTimeId=0
this.mediaModule=new MediaModule();
this.mediaModule.MEDIA_OBJ_TABLE_ID=ApeConsts.AUDIO_OBJ_TABLE_ID;
this.mediaModule.mediaChannels={};
... ... @@ -47,9 +48,19 @@ class AudioApe extends Ape {
//获取推流地址
getAudioPublishPath(_param) {
loger.log('getAudioPublishPath');
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};;
}
return this.mediaModule.getMediaPublishPath(_param);
}
//获取当前所有频道信息
getAllChannelInfo(_param){
loger.log('getAllChannelInfo');
return this.mediaModule.getAllMediaChannelInfo();
}
//推流
publishAudio(_param) {
if(!this.mcu.connected){
... ... @@ -71,18 +82,19 @@ class AudioApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data": "推流数据已经无效"};
}
/* //20170302 修改频道占用规则,同一个人可以推多路流,暂停下面的限制
//同一个nodeId只允许推一个流,如果已经推了就不能再推
if(this.mediaModule.getOpeningMediaChannel(GlobalConfig.nodeId)!=0){
loger.warn("publishAudio,已经存在一个流,不能再推");
return {"code": ApeConsts.RETURN_FAILED, "data": "已经存在一个流,不能再推"};
}
return {"code": ApeConsts.RETURN_FAILED, "data": "已经存在一个流,不能再推","mediaChannels":this.mediaModule.mediaChannels};
}*/
//判断当前是否还有空闲的channle
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn("publishAudio,没有空闲的channel ");
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"};
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
//判断当前的频道是否已经占用
... ... @@ -91,33 +103,73 @@ class AudioApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data":"频道已经被占用!"};
}
let channelInfo={};
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.owner=GlobalConfig.nodeId;
channelInfo.status=ApeConsts.CHANNEL_STATUS_OPENING;
channelInfo.fromNodeId=GlobalConfig.nodeId;
channelInfo.channelId=needPublishChannelInfo.channelId;//freeChannel
channelInfo.streamId=needPublishChannelInfo.streamId;//按规则拼接的流名称
channelInfo.timestamp=needPublishChannelInfo.timestamp;//EngineUtils.creatTimestamp();
channelInfo.classId=GlobalConfig.classId;//GlobalConfig.classId;
channelInfo.siteId=GlobalConfig.siteId;//GlobalConfig.siteId;
channelInfo.toNodeId=0;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_AUDIO;
this.sendTableUpdateHandler(channelInfo);
return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!"}
return {"code": ApeConsts.RETURN_SUCCESS, "data":"推流成功!","mediaId":needPublishChannelInfo.channelId};
}
//停止推流,
stopPublishAudio(_param) {
loger.log('stopPublishAudio');
loger.log('stopPublishAudio ->_param',_param);
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
//_param如果为空或者0,那么默认就是当前自己的nodeId,否则用_param
let nodeId;
//默认为自己的nodeId,_param如果为空,那么默认就是当前自己的nodeId,否则用_param
let nodeId=GlobalConfig.nodeId;
if(_param&&parseInt(_param.nodeId)>0){
nodeId=parseInt(_param.nodeId);
}
//默认为0,如果releaseChannelId 存在就释放releaseChannelId通道
let releaseChannelId=0;
if(_param&&parseInt(_param.mediaId)>0){
releaseChannelId=parseInt(_param.mediaId);
}
//释放channelId 的占用
if(releaseChannelId>0){
//第一种情况,释放nodeId占用的指定mediaId (channelId)
this._releaseChannelForNodeId(nodeId,releaseChannelId);
}else {
nodeId=GlobalConfig.nodeId;
//第二种情况,释放nodeId占用的所有channelId
this._releaseNodeIdAllChannel(nodeId);
}
}
//释放nodeId占用的指定的channelId频道
_releaseChannelForNodeId(nodeId,channelId){
loger.log(nodeId,"_releaseChannelForNodeId-->channelId",channelId);
let channelInfo=this.mediaModule.mediaChannels[channelId];
if(channelInfo&&channelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
if(channelInfo.fromNodeId==nodeId){
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
channelInfo.channelId=channelId;
this.sendTableUpdateHandler(channelInfo);
}else {
loger.warn(channelId,"不属于nodeId",nodeId,"不能释放",channelInfo);
}
}else {
loger.warn(nodeId,"要释放的channel不存在或者已经释放-->channelId",channelInfo);
}
}
//释放nodeId占用的所有频道
_releaseNodeIdAllChannel(nodeId){
loger.log(nodeId,"_releaseNodeIdAllChannel",this.mcu.connected);
if(!this.mcu.connected){
clearTimeout(this.releaseTimeId);
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
let openingChannel = this.mediaModule.getOpeningMediaChannel(nodeId);
... ... @@ -126,18 +178,19 @@ class AudioApe extends Ape {
return {"code": ApeConsts.RETURN_FAILED, "data": "没有占用channel不需要处理"};
}
let channelInfo={};
let channelInfo=this.mediaModule.getDefaultChannelInfo();
channelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
channelInfo.fromNodeId=0;
channelInfo.channelId=openingChannel;
channelInfo.timestamp=0;
channelInfo.classId=GlobalConfig.classId;
channelInfo.toNodeId=0;
channelInfo.mediaType=ApeConsts.MEDIA_TYPE_DEFAULT;
this.sendTableUpdateHandler(channelInfo);
//递归检查,800毫秒之后执行
this.releaseTimeId=setTimeout(function(){
loger.warn(nodeId,"递归检查频道是否占用");
this._releaseNodeIdAllChannel(nodeId);
}.bind(this),800);
}
sendAudioBroadcastMsg(_param) {
loger.log('sendAudioBroadcastMsg',_param);
if(!this.mcu.connected){
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
... ... @@ -163,7 +216,7 @@ class AudioApe extends Ape {
let freeChannel = this.mediaModule.getFreeMediaChannel();
if (freeChannel == 0) {
loger.warn('sendAudioBroadcastMsg,不能再打开更多的设备', _param);
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备"};
return {"code": ApeConsts.RETURN_FAILED, "data": "不能再打开更多的设备","mediaChannels":this.mediaModule.mediaChannels};
}
}
... ... @@ -173,7 +226,7 @@ class AudioApe extends Ape {
audioSendPdu.isPublic = true;
audioSendPdu.fromNodeId = GlobalConfig.nodeId;//发起人
audioSendPdu.toNodeId = parseInt(_param.toNodeID) || 0;//接收者,0就是所有人
audioSendPdu.toNodeId = parseInt(_param.toNodeId) || 0;//接收者,0就是所有人
audioSendPdu.actionType = parseInt(_param.actionType) || ApeConsts.MEDIA_ACTION_DEFAULT;
audioSendPdu.data = this._rCArrayBufferUtil.strToUint8Array("h5" + _param.data);//开头两个字会乱码
... ... @@ -200,14 +253,12 @@ class AudioApe extends Ape {
let tableItemPdu = new pdu['RCRegistryTableItemPdu'];
tableItemPdu.itemIdx = _channelInfo.channelId;
tableItemPdu.owner = 0;//收到flash的是这个值,不清楚先写固定
tableItemPdu.owner = _channelInfo.owner;//0收到flash的是这个值,MCU做了了用户掉线处理,30秒之后会清理owner为0
tableItemPdu.itemData = updateModelPdu.toArrayBuffer();
//insert
let tableInsertItemPdu = new pdu['RCRegistryTableUpdateItemPdu'];
//optional RCPduType_E type = 1 [default = RCPDU_REG_TABLE_UPDATE_PDU];
//repeated RCRegistryTableItemPdu items = 2;
tableInsertItemPdu.type = pdu.RCPDU_REG_TABLE_UPDATE_PDU;//
tableInsertItemPdu.type = pdu.RCPDU_REG_TABLE_UPDATE_PDU;
tableInsertItemPdu.items.push(tableItemPdu);
let updateObjPdu = new pdu['RCRegistryUpdateObjPdu'];
... ... @@ -248,27 +299,36 @@ class AudioApe extends Ape {
}
}
tableUpdateHandler(owner, itemIdx, itemData) {
// debugger;
/* let updateChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
this.mediaModule.mediaChannels[itemIdx] = updateChannelInfo;
this._emit(MessageTypes.AUDIO_UPDATE, updateChannelInfo);*/
tableUpdateHandler(owner, itemIdx, itemData,seek) {
let unpackChannelInfo = this.unPackPdu(owner, itemIdx, itemData);
loger.log("tableUpdateHandler->channel",itemIdx,'status->',unpackChannelInfo.status,"seek->",seek);
//****很重要********
//如果owner的值为0,代表的是这个歌频道已经被释放了(mcu服务端对于占用channel的掉线用户,就是把owner设置为0)
if(owner==0){
loger.log("释放占用的频道,channel",itemIdx);
unpackChannelInfo.status=ApeConsts.CHANNEL_STATUS_RELEASED;
unpackChannelInfo.streamId="";
}
this.mediaModule.mediaChannels[itemIdx] = unpackChannelInfo;
if(unpackChannelInfo&&unpackChannelInfo.fromNodeId!=GlobalConfig.nodeId){
let receiveChannelInfo={};
receiveChannelInfo.mediaId=unpackChannelInfo.channelId;
receiveChannelInfo.fromNodeId=unpackChannelInfo.fromNodeId;
//消息不是自己同步的,需要处理
if(unpackChannelInfo.status==ApeConsts.CHANNEL_STATUS_OPENING){
//正在推流
receiveChannelInfo.m3u8Url="";
receiveChannelInfo.rtmpUrl="";
receiveChannelInfo.replay="";
receiveChannelInfo.seek=seek||0;//这个是录制回放时使用的seek
let m3u8Stream=this.mediaModule.getMediaPlayPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
let rtmpStream=this.mediaModule.getMediaPlayPath({"type":"rtmp","streamId": unpackChannelInfo.streamId});
let replay=this.mediaModule.getMediaRecordPlaybackPath({"type":"m3u8","streamId": unpackChannelInfo.streamId});
if(m3u8Stream.code==0){
receiveChannelInfo.m3u8Url=m3u8Stream.playUrl;
... ... @@ -276,21 +336,23 @@ class AudioApe extends Ape {
if(rtmpStream.code==0){
receiveChannelInfo.rtmpUrl=rtmpStream.playUrl;
}
loger.log("AUDIO_PLAY");
console.log(receiveChannelInfo);
if(replay.code==0){
receiveChannelInfo.replay=replay.playUrl;
}
loger.log("AUDIO_PLAY",receiveChannelInfo);
//广播播放视频的消息
this._emit(MessageTypes.AUDIO_PLAY, receiveChannelInfo);
}else {
loger.log("AUDIO_STOP");
console.log(receiveChannelInfo);
loger.log("AUDIO_STOP",receiveChannelInfo);
//流已经停止
this._emit(MessageTypes.AUDIO_STOP, receiveChannelInfo);
}
}else {
loger.warn("消息是自己发送的或者是消息无效,不需要处理,消息内容如下:");
console.log(unpackChannelInfo);
loger.log(unpackChannelInfo);
}
this._emit(MessageTypes.AUDIO_UPDATE, unpackChannelInfo);
}
///////数据的封包和解包/////////////////////////////////////////
... ... @@ -314,7 +376,7 @@ class AudioApe extends Ape {
packPduModel.timestamp =_param.timestamp||EngineUtils.creatTimestamp();
packPduModel.fromNodeId = GlobalConfig.nodeId;
packPduModel.toNodeId = 0;
console.log("packPdu",packPduModel);
loger.log("packPdu",packPduModel);
return packPduModel;
}
... ... @@ -326,7 +388,7 @@ class AudioApe extends Ape {
}
try {
let packChannelInfo = pdu['RCAudioChannelInfoPdu'].decode(itemData);
console.log(packChannelInfo);
loger.log(packChannelInfo);
return packChannelInfo;
} catch (err) {
loger.log("unPackPdu error,itemIdx=" + itemIdx + " err:" + err.message);
... ...
... ... @@ -65,11 +65,11 @@ class ChatApe extends Ape {
// if (!(chatSendPdu.isPublic || 0 === chatSendPdu.peer)) {
if (!chatSendPdu.isPublic && 0!=chatSendPdu.peer) {
//发送给制定的人
loger.log('发送私聊消息.');
//loger.log('发送私聊消息.');
this.send(chatSendPdu);
} else {
//发送给所有人
loger.log('发送公聊消息.');
//loger.log('发送公聊消息.');
//this.sendUniform(chatSendPdu);
this.sendChatUniform(chatSendPdu);
}
... ... @@ -79,8 +79,8 @@ class ChatApe extends Ape {
var chatReceivePdu = pdu['RCChatSendDataRequestPdu'].decode(chatBuffer);
var chatMsg = {};
chatMsg.fromNodeID = chatReceivePdu.initiator;
chatMsg.toNodeID = chatReceivePdu.peer;
chatMsg.fromNodeId = chatReceivePdu.initiator;
chatMsg.toNodeId = chatReceivePdu.peer;
chatMsg.message = this._rCArrayBufferUtil.uint8ArrayToStr(chatReceivePdu.userData, 2);
chatMsg.fromName = this._rCArrayBufferUtil.uint8ArrayToStr(chatReceivePdu.fromName, 2);
chatMsg.fromRole = chatReceivePdu.fromRole;
... ...
// //////////////////////////////////////////////////////////////////////////////
//会议控制APE
//课堂控制APE
// //////////////////////////////////////////////////////////////////////////////
import Ape from './Ape';
... ... @@ -14,7 +14,7 @@ import EngineUtils from 'EngineUtils';
import TimerCounter from "TimerCounter";
let loger = Loger.getLoger('ConferApe');
let itemIdx=0;//table插入新数据的计数id,目前用时间戳
let itemIdx = 0;//table插入新数据的计数id,目前用时间戳
class ConferApe extends Ape {
constructor() {
... ... @@ -23,7 +23,7 @@ class ConferApe extends Ape {
ApeConsts.CONFERENCE_SESSION_NAME,
ApeConsts.CONFERENCE_SESSION_TAG
);
/*
// Attribures
this.hostNodeId = -1;//主持人的nodeId
// 用户的身份,5种类型:
... ... @@ -34,8 +34,10 @@ class ConferApe extends Ape {
// record(暂时没用.
// 默认值: normal
this.hostUserId = '';//主持人的 第三方userId
*/
this.rosters = {};//用户列表
this.timerCounter=new TimerCounter();//计时器
this.timerCounter = new TimerCounter();//计时器
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
... ... @@ -54,21 +56,21 @@ class ConferApe extends Ape {
this.on(pdu.RCPDU_SESSION_JOIN_RESPONSE, this._joinSessionHandler.bind(this));
this.on(pdu.RCPDU_SEND_CONFERENCE_DATA_REQUEST, this.conferMsgComingHandler.bind(this));//这个是会议消息类型,flash里在使用这里不再使用,各个模块的消息由模块自己来处理
this.on(pdu.RCPDU_CONFERENCE_RECORD_REQUEST,this.onSendConferRecordRequestHandler.bind(this));//发送录制和停止录制消息
this.on(pdu.RCPDU_SEND_CONFERENCE_DATA_REQUEST, this.conferMsgComingHandler.bind(this));//这个是课堂消息类型,flash里在使用这里不再使用,各个模块的消息由模块自己来处理
this.on(pdu.RCPDU_CONFERENCE_RECORD_REQUEST, this.onSendConferRecordRequestHandler.bind(this));//发送录制和停止录制消息
}
//加入会议
//加入课堂
_joinSessionHandler(_data) {
let nodeInfoRecordPdu = this.mcu.mcuClassInfo.self;
loger.log("_joinSessionHandler nodeInfoRecordPdu=");
console.log(nodeInfoRecordPdu);
loger.log(nodeInfoRecordPdu);
let userDataPdu = new pdu['RCNodeInfoUserDataPdu'];
userDataPdu.qq = '';
userDataPdu.skype = '';
nodeInfoRecordPdu.userData = userDataPdu.toArrayBuffer();
nodeInfoRecordPdu.deviceType =GlobalConfig.deviceType;//设备类型
nodeInfoRecordPdu.deviceType = GlobalConfig.deviceType;//设备类型
let item = new pdu['RCRegistryRosterItemPdu'];
item.nodeId = nodeInfoRecordPdu.nodeId;
... ... @@ -95,17 +97,17 @@ class ConferApe extends Ape {
}
sendConferMsg(_messageInfo) {
if(this._classInfo==null||EngineUtils.isEmptyObject(this._classInfo)){
loger.log('不能发送会议消息.McuClient还未初始化数据!');
if(GlobalConfig.getCurrentStatus().code==0||GlobalConfig.getCurrentStatus().code==1){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
if (this._classInfo == null || EngineUtils.isEmptyObject(this._classInfo)) {
loger.log('不能发送课堂消息.McuClient还未初始化数据!');
if (GlobalConfig.getCurrentStatus().code == 0 || GlobalConfig.getCurrentStatus().code == 1) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_SEND_FAILED_NO_JOIN);
return;
}
return ;
return;
}
// to, message
loger.log('发送会议消息.', _messageInfo);
loger.log('发送课堂消息.', _messageInfo);
/* message RCConferenceSendDataRequestPdu {
optional uint32 initiator = 1;
... ... @@ -123,30 +125,30 @@ class ConferApe extends Ape {
conferSendPdu.userData = this._rCArrayBufferUtil.strToUint8Array("h5" + _messageInfo.message);
//conferSendPdu.userData =UTF8.setBytesFromString(_messageInfo.message);
conferSendPdu.isPublic = true;
conferSendPdu.actionType=_messageInfo.actionType;
conferSendPdu.actionType = _messageInfo.actionType;
// if (!(conferSendPdu.isPublic || 0 === conferSendPdu.peer)) {
if (!conferSendPdu.isPublic && 0!=conferSendPdu.peer) {
if (!conferSendPdu.isPublic && 0 != conferSendPdu.peer) {
//发送给制定的人
loger.log('发送私聊会议消息.');
loger.log('发送私聊课堂消息.');
this.send(conferSendPdu);
} else {
//发送给所有人
loger.log('发送公聊会议消息.');
loger.log('发送公聊课堂消息.');
this.sendChatUniform(conferSendPdu);
}
}
//发送录制或停止录制的消息,{"recordStatus":true};true为开始录制,false为停止录制
sendConferRecordMsg(_param) {
if(!this.mcu.connected){
if (!this.mcu.connected) {
loger.warn(GlobalConfig.getCurrentStatus());
return {"code": ApeConsts.RETURN_FAILED, "data": "已经断开连接"};
}
// to, message
loger.log('发送录制消息.', _param);
if(_param==null){
loger.warn("控制录制状的消息发送失败,参数错误",_param);
if (_param == null) {
loger.warn("控制录制状的消息发送失败,参数错误", _param);
return;
}
... ... @@ -158,7 +160,7 @@ class ConferApe extends Ape {
}*/
//保存当前的录制状态
GlobalConfig.recordStatus=_param.recordStatus||false;
GlobalConfig.recordStatus = _param.recordStatus || false;
let conferRecordSendPdu = new pdu['RCConferenceRecordRequestPdu'];
conferRecordSendPdu.type = pdu.RCPDU_CONFERENCE_RECORD_REQUEST;
... ... @@ -166,38 +168,44 @@ class ConferApe extends Ape {
conferRecordSendPdu.isPublic = true;
conferRecordSendPdu.initiator = this._classInfo.nodeId;//发起人
conferRecordSendPdu.record =GlobalConfig.recordStatus;
conferRecordSendPdu.classTime=GlobalConfig.classTimestamp;
conferRecordSendPdu.filename=GlobalConfig.recordFileName||GlobalConfig.classId+"_"+EngineUtils.creatTimestampYMD()+".rec";
conferRecordSendPdu.record = GlobalConfig.recordStatus;
conferRecordSendPdu.classTime = GlobalConfig.classTimestamp;
conferRecordSendPdu.filename = GlobalConfig.recordFileName || GlobalConfig.classId + "_" + EngineUtils.creatTimestampYMD() + ".rec";
this.sendChatUniform(conferRecordSendPdu);
}
//开启录制
startRecord(){
loger.log('startRecord',"isHost",GlobalConfig.isHost,"recordStatus",GlobalConfig.recordStatus);
startRecord() {
//如果录制的时间长超出设定的最大录制时间就不再录制
if(GlobalConfig.classTimestamp>=GlobalConfig.allowRecordMaxTime){
loger.warn('不能再录制,录制时间已经达到最大限制',GlobalConfig.classTimestamp);
return;
}
loger.log('startRecord', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
//如果是host
if(GlobalConfig.isHost){
GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
this.sendConferRecordMsg({"recordStatus":true});
if (GlobalConfig.isHost) {
GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
this.sendConferRecordMsg({"recordStatus": true});
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
this._emit(MessageTypes.CLASS_RECORD_START);//会议开始录制
this._emit(MessageTypes.CLASS_RECORD_START);//课堂开始录制
}
}
//停止录制
stopRecord(){
loger.log('stopRecord',"isHost",GlobalConfig.isHost,"recordStatus",GlobalConfig.recordStatus);
stopRecord() {
loger.log('stopRecord', "isHost", GlobalConfig.isHost, "recordStatus", GlobalConfig.recordStatus);
//如果是host,并且当前正在录制中
if(GlobalConfig.isHost&&GlobalConfig.recordStatus){
GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
this.sendConferRecordMsg({"recordStatus":false});
if (GlobalConfig.isHost && GlobalConfig.recordStatus) {
GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
this.sendConferRecordMsg({"recordStatus": false});
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
}
}
//主动离开会议,发送通知到服务器
leaveClass(){
//主动离开课堂,发送通知到服务器
leaveClass() {
let nodeInfoRecordPdu = this.mcu.mcuClassInfo.self;
let userDataPdu = new pdu['RCNodeInfoUserDataPdu'];
userDataPdu.qq = '';
... ... @@ -212,7 +220,7 @@ class ConferApe extends Ape {
let rosterUpdateItem = new pdu['RCRegistryRosterDeleteItemPdu'];
rosterUpdateItem.type = pdu.RCPDU_REG_ROSTER_DELETE_PDU;
rosterUpdateItem.nodeId=GlobalConfig.nodeId;
rosterUpdateItem.nodeId = GlobalConfig.nodeId;
let updateObjPdu = new pdu['RCRegistryUpdateObjPdu'];
updateObjPdu.objId = ApeConsts.CONFERENCE_OBJ_ROSTER_ID;
... ... @@ -231,66 +239,68 @@ class ConferApe extends Ape {
}
//还原课堂状态
restorClass(){
GlobalConfig.classTimestamp=0;
GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_WAIT;
GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
restorClass() {
GlobalConfig.classTimestamp = 0;
GlobalConfig.classStatus = ApeConsts.CLASS_STATUS_WAIT;
GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
this.stopRecord();
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
this.sendUpdaterClassStatusInfo({"actionType":0});
this.sendUpdaterClassStatusInfo({"actionType": 0});
loger.log('restorClass');
}
//开始上课
startClass(_param){
if(GlobalConfig.isHost){
startClass(_param) {
if (GlobalConfig.isHost) {
let timestamp=EngineUtils.creatTimestampStr();
GlobalConfig.classStopTime=timestamp;
let timestamp = EngineUtils.creatTimestampStr();
GlobalConfig.classStopTime = timestamp;
//如果录制的文件名不存在,需要创建一个名字
let timestampYMD=EngineUtils.creatTimestampYMD();
GlobalConfig.recordFileName=GlobalConfig.recordFileName||
GlobalConfig.siteId+"/"+timestampYMD+"/"
+GlobalConfig.classId+"_"+timestampYMD+".rec";//4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename`
let timestampYMD = EngineUtils.creatTimestampYMD();
GlobalConfig.recordFileName = GlobalConfig.recordFileName ||
GlobalConfig.siteId + "/" + timestampYMD + "/"
+ GlobalConfig.classId + "_" + timestampYMD + ".rec";//4、文件名称 $RECORD_HOME/`site id`/`日期`/`filename` 例:/data/record/su/20161216/`filename`
if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_WAIT){
if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) {
//之前是为开始状态,第一次点开始
GlobalConfig.classStartTime=timestamp;
GlobalConfig.classStartTime = timestamp;
}
GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_STARTED;
GlobalConfig.classStatus = ApeConsts.CLASS_STATUS_STARTED;
//开始录制
this.startRecord();
//会议状态改变
//课堂状态改变
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
//同步会议状态
this.sendUpdaterClassStatusInfo({"actionType":1});
//同步课堂状态
this.sendUpdaterClassStatusInfo({"actionType": 1});
//开始计时
this.startTimerCounter();
}else {
} else {
loger.warn('没有权限');
}
}
//暂停上课
pauseClass(_param){
if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_WAIT){
pauseClass(_param) {
if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) {
loger.warn('还没有开始,不能点暂停');
return;
}
GlobalConfig.classStatus=ApeConsts.CLASS_STATUS_PAUSE;
GlobalConfig.classStopTime=EngineUtils.creatTimestampStr();
GlobalConfig.classStatus = ApeConsts.CLASS_STATUS_PAUSE;
GlobalConfig.classStopTime = EngineUtils.creatTimestampStr();
this.stopRecord();
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
this.sendUpdaterClassStatusInfo({"actionType":2});
this.sendUpdaterClassStatusInfo({"actionType": 2});
this.stopTimerCounter();
}
//关闭课堂
closeClass(_param){
if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_WAIT){
closeClass(_param) {
if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_WAIT) {
loger.warn('还没有开始,不能点关闭');
return;
}
... ... @@ -298,34 +308,34 @@ class ConferApe extends Ape {
this.stopTimerCounter();
this.restorClass();
//把所有人都踢出课堂
this.sendConferMsg({"to":0,"message":"所有人退出会议","actionType":ApeConsts.CLASS_ACTION_CLOSE_ALL});
this.sendConferMsg({"to": 0, "message": "所有人退出课堂", "actionType": ApeConsts.CLASS_ACTION_CLOSE_ALL});
}
//更新会议信息
sendUpdaterClassStatusInfo(_param){
//更新课堂信息
sendUpdaterClassStatusInfo(_param) {
loger.log('sendUpdaterClassStatusInfo');
if(_param==null||EngineUtils.isEmptyObject(_param)){
if (_param == null || EngineUtils.isEmptyObject(_param)) {
loger.log('sendUpdaterClassStatusInfo,参数错误');
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return ;
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return;
}
itemIdx=ApeConsts.CONFERENCE_OBJ_TABLE_ID;// itemIdx=_param.itemIdx;
let modelPdu = this.packPdu(_param,itemIdx);
itemIdx = ApeConsts.CONFERENCE_OBJ_TABLE_ID;// itemIdx=_param.itemIdx;
let modelPdu = this.packPdu(_param, itemIdx);
//loger.log('sendUpdaterClassStatusInfo----2------');
console.log(modelPdu);
loger.log(modelPdu);
if(modelPdu==null){
if (modelPdu == null) {
loger.log('sendUpdaterClassStatusInfo,参数错误');
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return ;
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return;
}
let tableItemPdu = new pdu['RCRegistryTableItemPdu'];
tableItemPdu.itemIdx=itemIdx;
tableItemPdu.itemIdx = itemIdx;
tableItemPdu.owner = 0;//收到flash的是这个值,不清楚先写固定
tableItemPdu.registerObjId=ApeConsts.CONFERENCE_OBJ_TABLE_ID;
tableItemPdu.itemData =modelPdu.toArrayBuffer();
tableItemPdu.registerObjId = ApeConsts.CONFERENCE_OBJ_TABLE_ID;
tableItemPdu.itemData = modelPdu.toArrayBuffer();
//updater
... ... @@ -350,18 +360,18 @@ class ConferApe extends Ape {
adapterPdu.type = pdu.RCPDU_REG_ADAPTER;
adapterPdu.item.push(adapterItemPdu);
console.log("会议发送更新数据============");
this.sendUniform(adapterPdu,true);
loger.log("课堂发送更新数据============");
this.sendUniform(adapterPdu, true);
}
/////收到消息处理/////////////////////////////////////////////////////////////////////////////////
//加入channel成功
onJoinChannelHandlerSuccess(){
loger.log('ConferApe.onJoinChannelHandlerSuccess',GlobalConfig.classStatus);
this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this),1);
//如果当前会议正在进行中,开启计时器
if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_STARTED){
onJoinChannelHandlerSuccess() {
loger.log('ConferApe.onJoinChannelHandlerSuccess', GlobalConfig.classStatus);
this.timerCounter.addTimerCallBack(this.timerCounterUptate.bind(this), 1);
//如果当前课堂正在进行中,开启计时器
if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
//开始计时
this.startTimerCounter();
... ... @@ -369,69 +379,72 @@ class ConferApe extends Ape {
this.startRecord();
}
}
//开启计时器
startTimerCounter(){
startTimerCounter() {
this.timerCounter.startTimer();
}
//停止计时器
stopTimerCounter(){
stopTimerCounter() {
this.timerCounter.stopTimer();
}
timerCounterUptate(){
if(!this.mcu.connected){
timerCounterUptate() {
if (!this.mcu.connected) {
loger.warn('MCU 连接已经断开');
this.stopTimerCounter();
}
//如果还没开始或已经暂停、关闭,不做计时处理
if(GlobalConfig.classStatus!=ApeConsts.CLASS_STATUS_STARTED){
loger.warn('当前课堂已经暂停或者未开始,不计时',"classStatus-->",GlobalConfig.classStatus);
if (GlobalConfig.classStatus != ApeConsts.CLASS_STATUS_STARTED) {
loger.warn('当前课堂已经暂停或者未开始,不计时', "classStatus-->", GlobalConfig.classStatus);
return;
}
GlobalConfig.classTimestamp=GlobalConfig.classTimestamp+1;//计时
GlobalConfig.classTimestamp = GlobalConfig.classTimestamp + 1;//计时
//loger.log('课堂进行时间',GlobalConfig.classTimestamp);
this._emit(MessageTypes.CLASS_UPDATE_TIMER,{"classTimestamp":GlobalConfig.classTimestamp});
this._emit(MessageTypes.CLASS_UPDATE_TIMER, {"classTimestamp": GlobalConfig.classTimestamp});
if(GlobalConfig.classTimestamp%GlobalConfig.updateClassInfoDelay==0){
if (GlobalConfig.classTimestamp % GlobalConfig.updateClassInfoDelay == 0) {
//如果是host身份,需要同步时间给其他人,同时把当前的状态上传到服务器
if(GlobalConfig.isHost){
if (GlobalConfig.isHost) {
//保存数据到Sass
this._emit(MessageTypes.CLASS_STATUS_INFO_CHANGE);
//同步消息给其他人
this.sendUpdaterClassStatusInfo({"actionType":1});
this.sendUpdaterClassStatusInfo({"actionType": 1});
}
}
}
tableUpdateHandler(owner, itemIdx, itemData) {
try {
let model=this.unPackPdu(owner, itemIdx,itemData);
let model = this.unPackPdu(owner, itemIdx, itemData);
loger.log('tableUpdateHandler');
console.log(model);
loger.log(model);
//处理会议更新的信息
if(model&&model.classStatusInfo){
//处理课堂更新的信息
if (model && model.classStatusInfo) {
GlobalConfig.setClassStatusInfo(model.classStatusInfo);
}
//通知应用层更新会议状态
this._emit(MessageTypes.CLASS_UPTATE_STATUS,GlobalConfig.classStatusInfo);
//通知应用层更新课堂状态
this._emit(MessageTypes.CLASS_UPTATE_STATUS, GlobalConfig.classStatusInfo);
//如果MCU已经断开连接,停止计时器
if(!this.mcu.connected){
if (!this.mcu.connected) {
//停止计时
this.stopTimerCounter();
return;
}
if(GlobalConfig.classStatus==ApeConsts.CLASS_STATUS_STARTED){
//如果会议在进行中,开始计时器
if (GlobalConfig.classStatus == ApeConsts.CLASS_STATUS_STARTED) {
//如果课堂在进行中,开始计时器
this.startTimerCounter();
}else {
} else {
//停止计时
this.stopTimerCounter();
}
} catch (e) {
loger.warn('ConferApe table update got exception. itemIdx',itemIdx);
loger.warn('ConferApe table update got exception. itemIdx', itemIdx);
}
}
... ... @@ -448,12 +461,12 @@ class ConferApe extends Ape {
chatMsg.fromNodeID = chatReceivePdu.initiator;
chatMsg.toNodeID = chatReceivePdu.peer;
chatMsg.message = this._rCArrayBufferUtil.uint8ArrayToStr(chatReceivePdu.userData, 2);
chatMsg.actionType=chatReceivePdu.actionType;
loger.log("conferMsgComingHandler",chatMsg);
switch (chatMsg.actionType){
chatMsg.actionType = chatReceivePdu.actionType;
loger.log("conferMsgComingHandler", chatMsg);
switch (chatMsg.actionType) {
case ApeConsts.CLASS_ACTION_CLOSE_ALL:
loger.log(chatMsg.message);
//会议关闭,所有人都退出
//收到课堂关闭,所有人都退出,执行自己关闭的流程
this._emit(MessageTypes.CLASS_EXIT);
break;
default:
... ... @@ -461,88 +474,124 @@ class ConferApe extends Ape {
}
}
onSendConferRecordRequestHandler(_data){
onSendConferRecordRequestHandler(_data) {
loger.log("onSendConferRecordRequestHandler");
try{
let conferRecordSendPdu =pdu['RCConferenceRecordRequestPdu'].decode(_data);
console.log(conferRecordSendPdu);
}catch (err){
loger.warn("onSendConferRecordRequestHandler err",err.message);
try {
let conferRecordSendPdu = pdu['RCConferenceRecordRequestPdu'].decode(_data);
loger.log(conferRecordSendPdu);
} catch (err) {
loger.warn("onSendConferRecordRequestHandler err", err.message);
}
}
rosterInsertHandler(nodeId, nodeData) {
if(GlobalConfig.nodeId==nodeId){
loger.log("自己加入 rosterInsertHandler");
}else {
loger.log("有人加入 rosterInsertHandler");
if (GlobalConfig.nodeId == nodeId) {
// loger.log("自己加入 rosterInsertHandler");
} else {
// loger.log("有人加入 rosterInsertHandler");
this.rosterUpdateHandler(nodeId, nodeData);
}
}
//更新人员列表数据
rosterUpdateHandler(nodeId, nodeData) {
if (nodeData.role === ApeConsts.NR_MASTER ||
nodeData.role === ApeConsts.NR_SLAVE) {
this.hostNodeId = nodeData.nodeId;
this.hostUserId = nodeData.userId;
//如果是自己的信息,不处理跳过
if (nodeId == GlobalConfig.nodeId) {
loger.log("自己加入课堂的消息,不需要处理");
this.rosters[nodeId] = nodeData;
return;
}
if (nodeData.role === ApeConsts.NR_NORMAL &&
this.hostNodeId === nodeData.nodeId) {
this.hostNodeId = -1;
this.hostUserId = '';
loger.log(nodeId, "加入课堂,role-->", nodeData.role, ApeConsts.userTypes[nodeData.role]);
//新加入的人员不是自己
//1.判断进入的用户身份,如果进入的人身份是host,助教,监课,并且和自己的身份冲突,自己会被踢掉
//2.最后进入的人会踢掉之前进入的人,nodeId是按时间戳生成的,最后进入的人nodeId的值比之前进入的人大
if (parseInt(nodeId) > GlobalConfig.nodeId) {
if (nodeData.role == ApeConsts.NR_HOST && GlobalConfig.isHost) {
this.kickOutRoster();
return;
} else if (nodeData.role == ApeConsts.NR_PRESENTER && GlobalConfig.isPresenter) {
this.kickOutRoster();
return;
} else if (nodeData.role == ApeConsts.NR_ASSISTANT && GlobalConfig.isAssistant) {
this.kickOutRoster();
return;
} else if (nodeData.role == ApeConsts.NR_INVISIBLE && GlobalConfig.isInvisible) {
this.kickOutRoster();
return;
}
}
//处理用户信息
let rosterExists = this.rosters[nodeId];
this.rosters[nodeId] = nodeData;
let userDataObj=null;
let userDataObj = null;
if (!rosterExists) {
try{
userDataObj=pdu['RCNodeInfoUserDataPdu'].decode(nodeData.userData);
}catch (err){
loger.log("RCNodeInfoUserDataPdu decode err",err.message);
try {
userDataObj = pdu['RCNodeInfoUserDataPdu'].decode(nodeData.userData);
} catch (err) {
loger.log("RCNodeInfoUserDataPdu decode err", err.message);
}
let newNodeData=nodeData;
newNodeData.userData=userDataObj;
loger.log("更新人员列表数据 rosterUpdateHandler",{"nodeId":nodeId});
this._emit(MessageTypes.CLASS_INSERT_ROSTER, {"nodeId":nodeId,"nodeData":newNodeData});
let newNodeData = nodeData;
newNodeData.userData = userDataObj;
//如果是监课,不告诉其他人
if (nodeData.role == ApeConsts.NR_INVISIBLE) {
loger.log("NR_INVISIBLE");
return;
}
this._emit(MessageTypes.CLASS_INSERT_ROSTER, {"nodeId": nodeId, "nodeData": newNodeData});
this.emitRosterChange();
}else {
} else {
//loger.log("更新人员列表数据,rosterExists已经存在",rosterExists);
}
}
//视频模块发生更新,人员状态需要更新
updaterRosterStatus(_param){
if(_param){
loger.log("媒体模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
loger.log(_param.status,_param.fromNodeId);
//console.log(_param.fromNodeId);
//如果是自己。改变自己的状态同步到MCU
//if(_param.fromNodeId==GlobalConfig.nodeId){
//
//}
//踢出用户
kickOutRoster() {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_CLASS_KICK_OUT);
this._emit(MessageTypes.CLASS_EXIT);
}
//视频模块发生更新,人员状态需要更新
updaterRosterStatus(_param) {
//loger.log("媒体模块发生更新,人员状态需要更新,fromNodeId->",_param.fromNodeId);
//如果视频消息中channel的占用人 fromNodeId在人员列表中不存在,需要释放这channel,因为这个有可能是之前没释放成功的
if(_param.status==ApeConsts.CHANNEL_STATUS_OPENING&&this.rosters[_param.fromNodeId]==null){
loger.log("媒体模块被占用,占有人已经不存在课堂中,释放Channel,_param->",_param);
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER,{"nodeId":_param.fromNodeId});
}
if (_param && _param.status == ApeConsts.CHANNEL_STATUS_OPENING && this.rosters[_param.fromNodeId] == null) {
loger.log("媒体模块被占用,占有人已经不存在课堂中,释放Channel,_param->", _param);
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": _param.fromNodeId});
}
}
//删除用户
rosterDelHandler(nodeId) {
if(GlobalConfig.nodeId==nodeId){
loger.log("自己离开 rosterDelHandler");
if (GlobalConfig.nodeId == nodeId) {
loger.log("自己离开课堂");
// 自己退出
this._emit(MessageTypes.CLASS_EXIT);
}else {
loger.log("有人离开 rosterDelHandler");
} else {
loger.log(nodeId, "离开课堂");
delete this.rosters[nodeId];
this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId":nodeId});
this.emitRosterChange();
this._emit(MessageTypes.CLASS_DELETE_ROSTER, {"nodeId": nodeId});
//当前人员列表中抽一个人来检查离开人员是否占用频道
for (let key in this.rosters) {
let randNodeId = parseInt(key);
if (randNodeId == GlobalConfig.nodeId) {
loger.log(randNodeId, "有权限检查离开的人员是否占用channel");
this._emit(MessageTypes.CLASS_NONENTITY_ROSTER, {"nodeId": nodeId});
} else {
loger.warn(GlobalConfig.nodeId, "没有权限检查离开的人员是否占用channel");
}
return;
}
}
}
... ... @@ -552,36 +601,36 @@ class ConferApe extends Ape {
}
///////数据的封包和解包/////////////////////////////////////////
packPdu(_param,_itemIdx){
loger.log("会议===packPdu ");
packPdu(_param, _itemIdx) {
loger.log("课堂===packPdu ");
//验证坐标点集合数组是否合法
if(_param==null||_itemIdx==null){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
if (_param == null || _itemIdx == null) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}
let classStatusInfo=new pdu['RCClassStatusInfoPdu'];
classStatusInfo.nodeId=GlobalConfig.nodeId;//mcu中的唯一ID
classStatusInfo.userId=GlobalConfig.userId;
classStatusInfo.userName=GlobalConfig.userName;
classStatusInfo.siteId=GlobalConfig.siteId;//站点号
classStatusInfo.classId=GlobalConfig.classId;
classStatusInfo.className=GlobalConfig.className;
classStatusInfo.classType=GlobalConfig.classType;//课堂类型
classStatusInfo.classStatus=GlobalConfig.classStatus;//课堂的状态
classStatusInfo.classStartTime=GlobalConfig.classStartTime;//课堂点击开始时间
classStatusInfo.classStopTime=GlobalConfig.classStopTime;//最后一次停止的时间(点暂停或结束),每次发送数据都获取当前时间戳
classStatusInfo.classTimestamp=GlobalConfig.classTimestamp;//相对于点开始课堂的时间戳
classStatusInfo.classBeginTime=GlobalConfig.classBeginTime;//课堂创建的时间,这个是Sass返回的
classStatusInfo.classEndTime=GlobalConfig.classEndTime;//课堂结束的时间,这个是Sass返回的
classStatusInfo.recordStatus=GlobalConfig.recordStatus;//当前录制状态
classStatusInfo.recordTimestamp=GlobalConfig.recordTimestamp;//相对于首次开始录制的时间戳
classStatusInfo.recordFileName=GlobalConfig.recordFileName;//录制的文件名
classStatusInfo.recordDownloadUrl=GlobalConfig.recordDownloadUrl;//下载地址
classStatusInfo.serverTimestamp=GlobalConfig.serverTimestamp;//当前的系统时间戳
classStatusInfo.activeDocId=GlobalConfig.activeDocId;//当前激活的文档id
classStatusInfo.activeDocCurPage=GlobalConfig.activeDocCurPage;//当前激活的文档的当前页
loger.log("classStatusInfo-------------",classStatusInfo);
let classStatusInfo = new pdu['RCClassStatusInfoPdu'];
classStatusInfo.nodeId = GlobalConfig.nodeId;//mcu中的唯一ID
classStatusInfo.userId = GlobalConfig.userId;
classStatusInfo.userName = GlobalConfig.userName;
classStatusInfo.siteId = GlobalConfig.siteId;//站点号
classStatusInfo.classId = GlobalConfig.classId;
classStatusInfo.className = GlobalConfig.className;
classStatusInfo.classType = GlobalConfig.classType;//课堂类型
classStatusInfo.classStatus = GlobalConfig.classStatus;//课堂的状态
classStatusInfo.classStartTime = GlobalConfig.classStartTime;//课堂点击开始时间
classStatusInfo.classStopTime = GlobalConfig.classStopTime;//最后一次停止的时间(点暂停或结束),每次发送数据都获取当前时间戳
classStatusInfo.classTimestamp = GlobalConfig.classTimestamp;//相对于点开始课堂的时间戳
classStatusInfo.classBeginTime = GlobalConfig.classBeginTime;//课堂创建的时间,这个是Sass返回的
classStatusInfo.classEndTime = GlobalConfig.classEndTime;//课堂结束的时间,这个是Sass返回的
classStatusInfo.recordStatus = GlobalConfig.recordStatus;//当前录制状态
classStatusInfo.recordTimestamp = GlobalConfig.recordTimestamp;//相对于首次开始录制的时间戳
classStatusInfo.recordFileName = GlobalConfig.recordFileName;//录制的文件名
classStatusInfo.recordDownloadUrl = GlobalConfig.recordDownloadUrl;//下载地址
classStatusInfo.serverTimestamp = GlobalConfig.serverTimestamp;//当前的系统时间戳
classStatusInfo.activeDocId = GlobalConfig.activeDocId;//当前激活的文档id
classStatusInfo.activeDocCurPage = GlobalConfig.activeDocCurPage;//当前激活的文档的当前页
loger.log("classStatusInfo-------------", classStatusInfo);
/*
optional uint32 item_idx=1;
... ... @@ -591,27 +640,27 @@ class ConferApe extends Ape {
optional RCClassStatusInfoPdu class_status_info=5;//当前课堂状态的信息
*/
//判断type类型,根据type设置不同的参数
let modelPdu =new pdu['RCClassSendDataModelPdu'];
modelPdu.itemIdx=_itemIdx;
modelPdu.from=GlobalConfig.nodeId;
modelPdu.owner=GlobalConfig.nodeId;
let modelPdu = new pdu['RCClassSendDataModelPdu'];
modelPdu.itemIdx = _itemIdx;
modelPdu.from = GlobalConfig.nodeId;
modelPdu.owner = GlobalConfig.nodeId;
//modelPdu.actionType =_param.actionType;
modelPdu.classStatusInfo=classStatusInfo;
modelPdu.classStatusInfo = classStatusInfo;
return modelPdu;
}
unPackPdu(owner, itemIdx,itemData){
loger.log("会议===unPackPdu ");
if(owner==null||itemIdx==null||itemData==null){
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
unPackPdu(owner, itemIdx, itemData) {
loger.log("课堂===unPackPdu ");
if (owner == null || itemIdx == null || itemData == null) {
this._emit(MessageTypes.MCU_ERROR, MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
return null;
}
try{
let modelPdu= pdu['RCClassSendDataModelPdu'].decode(itemData);
try {
let modelPdu = pdu['RCClassSendDataModelPdu'].decode(itemData);
return modelPdu;
}catch (err){
loger.log("会议收到数据 unPackPdu Pdu解析错误,itemIdx="+itemIdx+" err:"+err.message);
} catch (err) {
loger.log("课堂收到数据 unPackPdu Pdu解析错误,itemIdx=" + itemIdx + " err:" + err.message);
}
return null;
}
... ...
... ... @@ -35,7 +35,7 @@ class DocApe extends Ape {
//this.activeDocItemIdx =0;//当前激活的文档itemIdx
//this.activeDocCurPage=1;//当前激活的文档的当前页
// 延迟
this._apeDelayed = true;
this._apeDelayed = false;
// Ape Models
this.registerKey(this._session_id, this._session_name, this._session_tag, new ArrayBuffer);
... ... @@ -212,7 +212,7 @@ class DocApe extends Ape {
//切换文档
documentSwitchDoc(paramInfo){
loger.log('切换文档,documentSwitchDoc');
console.log(paramInfo);
loger.log(paramInfo);
if(paramInfo==null||paramInfo.itemIdx==null){
loger.warn('documentSwitch失败,参数错误',paramInfo);
this._emit(MessageTypes.MCU_ERROR,MessageTypes.ERR_APE_INTERFACE_PARAM_WRONG);
... ... @@ -246,8 +246,8 @@ class DocApe extends Ape {
docDataModel.action=ApeConsts.DOC_ACTION_SWITCH_DOC;
docDataModel.visible=paramInfo.visible||false;//默认是false
loger.log('切换文档,当前文档和上一个显示的文档都需要更新状态');
console.log({"oldDoc":oldDocModel,"nowDoc":docDataModel});
//loger.log('切换文档,当前文档和上一个显示的文档都需要更新状态');
loger.log({"oldDoc":oldDocModel,"nowDoc":docDataModel});
//更新当前选择的文档
this.updaterDoc(docDataModel,docDataModel.itemIdx);
... ... @@ -261,7 +261,7 @@ class DocApe extends Ape {
//文档翻页
documentSwitchPage(paramInfo){
loger.log('文档翻页,documentSwitchPage');
console.log(paramInfo);
loger.log(paramInfo);
//console.log(this.docList);
//获取已经存在的数据
let docDataModel= this.docList[paramInfo.itemIdx];
... ... @@ -349,7 +349,7 @@ class DocApe extends Ape {
}
loger.log('tableInsertHandler 发送给客户端');
console.log(itemDataInfo);
loger.log(itemDataInfo);
this._emit(MessageTypes.DOC_UPDATE,itemDataInfo);//用添加和更新都统一DOC_UPDATE
}
... ... @@ -401,7 +401,7 @@ class DocApe extends Ape {
loger.log('tableUpdateHandler 设置当前激活的文档id');
}
loger.log('tableUpdateHandler 发送给客户端');
console.log(itemDataInfo);
loger.log(itemDataInfo);
this._emit(MessageTypes.DOC_UPDATE,itemDataInfo);
}else {
... ... @@ -440,7 +440,9 @@ class DocApe extends Ape {
this._emit(DocApe.DOC_JOIN_CHANNEL_SUCCESS);
},(GlobalConfig.mcuDelay+GlobalConfig.docDelay)|| 12000+GlobalConfig.docDelay);
}else {
setTimeout(() => {
this._emit(DocApe.DOC_JOIN_CHANNEL_SUCCESS);
},GlobalConfig.docDelay);
}
}
... ... @@ -502,7 +504,7 @@ class DocApe extends Ape {
docModelPdu.pageNum = _param.pageNum||1;
docModelPdu.fileType=_param.fileType||"";
docModelPdu.creatUserId=_param.creatUserId||"0";
docModelPdu.url =_param.url||"";//"http://101.200.150.192/DocSharing/data/h5test/20170206-171100025/7e9c4178cac1133e0dd9d5b583439122.jpg";
docModelPdu.url ="";//这个地址没用到,数据太长占用资源 暂停使用//"http://101.200.150.192/DocSharing/data/h5test/20170206-171100025/7e9c4178cac1133e0dd9d5b583439122.jpg";
docModelPdu.relativeUrl=_param.relativeUrl||"";//"/DocSharing/data/h5test/20170206-171100025/7e9c4178cac1133e0dd9d5b583439122.jpg";
docModelPdu.curV=_param.curV||0;
docModelPdu.curH=_param.curH||0;
... ... @@ -513,7 +515,7 @@ class DocApe extends Ape {
docModelPdu.md5=_param.md5||"";//MD5
docModelPdu.fileName=_param.fileName||"doc_"+_itemIdx;//文档的名字
docModelPdu.dynamicTS=_param.dynamicTS||"0";//文档上传后返回值中的字段dynamicTransferStatic
console.log(docModelPdu);
loger.log(docModelPdu);
return docModelPdu;
}
... ...