@@ -1057,10 +1067,11 @@
layui.use([
'layedit', 'form', 'layer', 'laytpl', 'upload',
'dropdown', 'carousel', 'util', 'colorpicker',
- 'slider', 'dropdown'
+ 'slider', 'dropdown', 'carousel'
], function () {
window.layer = layui.layer;
window.form = layui.form;
+ window.carousel = layui.carousel;
window.$ = layui.$;
window.layedit = layui.layedit;
window.laytpl = layui.laytpl;
diff --git a/svr/res/js/comm.js b/svr/res/js/comm.js
index ceb4e6c..0a1b4d5 100644
--- a/svr/res/js/comm.js
+++ b/svr/res/js/comm.js
@@ -286,38 +286,8 @@ window.tlrtcfile = {
return false;
}
},
+
getWebrtcStats: async function (peerConnection) {
- // 候选者对
- "candidate-pair" |
- // 证书相关的统计信息
- "certificate" |
- // 当前音视频编解码器的统计信息
- "codec" |
- // CSRC相关的统计信息
- "csrc" |
- // 数据通道的相关统计信息
- "data-channel" |
- // 传入数据流的相关统计信息
- "inbound-rtp" |
- // 本地候选连接的相关统计信息
- "local-candidate" |
- // 媒体源的相关统计信息
- "media-source" |
- // 传出数据流的相关统计信息
- "outbound-rtp" |
- // 对等连接的相关统计信息
- "peer-connection" |
- // 对等连接的相关统计信息
- "remote-candidate" |
- // 远程传入数据流的相关统计信息
- "remote-inbound-rtp" |
- // 远程传出数据流的相关统计信息
- "remote-outbound-rtp" |
- // 媒体轨道的相关统计信息
- "track" |
- // 传输协议的相关统计信息
- "transport";
-
if (!peerConnection) {
return "RTCPeerConnection is not available";
}
@@ -325,23 +295,63 @@ window.tlrtcfile = {
return "RTCStatsReport is not available";
}
- let result = { }
-
- let stats = await peerConnection.getStats(null);
-
- stats.forEach((report) => {
- if (!report.type) return;
- let data = {}
- Object.keys(report).forEach((statName) => {
- data[statName] = report[statName]
- });
- result[report.type] = {
- kind : report.kind,
- data : data
+ function getTypeDescription(type) {
+ switch (type) {
+ case 'candidate-pair':
+ return '候选者对';
+ case 'certificate':
+ return '证书相关的统计信息';
+ case 'codec':
+ return '当前音视频编解码器的统计信息';
+ case 'csrc':
+ return 'CSRC相关的统计信息';
+ case 'data-channel':
+ return '数据通道的相关统计信息';
+ case 'inbound-rtp':
+ return '传入数据流的相关统计信息';
+ case 'local-candidate':
+ return '本地候选连接的相关统计信息';
+ case 'media-source':
+ return '媒体源的相关统计信息';
+ case 'outbound-rtp':
+ return '传出数据流的相关统计信息';
+ case 'peer-connection':
+ return '对等连接的相关统计信息';
+ case 'remote-candidate':
+ return '远程候选连接的相关统计信息';
+ case 'remote-inbound-rtp':
+ return '远程传入数据流的相关统计信息';
+ case 'remote-outbound-rtp':
+ return '远程传出数据流的相关统计信息';
+ case 'track':
+ return '媒体轨道的相关统计信息';
+ case 'transport':
+ return '传输协议的相关统计信息';
+ case 'media-playout':
+ return '音频播放的相关统计数据'
+ default:
+ return '未知类型';
}
- });
+ }
- return result
+ function getRTCStats(peerConnection) {
+ const statsMap = new Map();
+ return new Promise((resolve) => {
+ peerConnection.getStats().then((stats) => {
+ stats.forEach((report) => {
+ const { type } = report;
+ if (!statsMap.has(type)) {
+ statsMap.set(type, []);
+ }
+ statsMap.get(type).push({ report, description: getTypeDescription(type) });
+ });
+
+ resolve(statsMap);
+ });
+ });
+ }
+
+ return await getRTCStats(peerConnection);
},
copyTxt: function (id, content) {
let that = this;
diff --git a/svr/res/js/draw.js b/svr/res/js/draw.js
index 6edc064..eb0205f 100644
--- a/svr/res/js/draw.js
+++ b/svr/res/js/draw.js
@@ -17,6 +17,8 @@ const draw = new Vue({
drawHistoryList: [], // 绘制历史操作列表, 用于回退
drawRollbackPoint: 0, // 绘制回退点
lineWidth: 1, // 画笔线宽
+ lineCap : "round",
+ lineJoin : "round",
strokeStyle: "#000000", // 画笔颜色
//line: 线条, circle: 圆形, rectangle: 矩形, text: 文字, delete: 擦除
drawMode: "line", // 画笔模式
@@ -26,7 +28,7 @@ const draw = new Vue({
starFill : false, //填充星星
rhomboidFill : false, //填充平行四边形
hexagonFill : false, //填充六边形
- circleStarPoint: { x: 0, y: 0 }, //圆形开始点
+ circleStartPoint: { x: 0, y: 0 }, //圆形开始点
triangleStartPoint : { x: 0, y: 0 }, //三角形开始点
starStartPoint : { x: 0, y: 0 }, //星星开始点
rhomboidStartPoint : { x: 0, y: 0 }, //平行四边形开始点
@@ -106,39 +108,66 @@ const draw = new Vue({
if (!this.isOpenDraw) {
return
}
+ const { drawMode, event } = options;
const canvas = document.getElementById('tl-rtc-file-mouse-draw-canvas');
- options.canvas = canvas;
- options.context = canvas.getContext('2d');
- options.fromRemote = true;
-
- const { drawMode } = options;
+ const context = canvas.getContext('2d');
+ options.remote.canvas = canvas;
+ options.remote.context = context;
//收到结束标识,保存当前画板到缓存数据中
- if(options.event === 'end'){
- this.endDrawHandler(options)
+ if(event === 'end'){
+ this.endDrawHandler({canvas, context})
return
}
+ let {
+ width : remoteWidth, height : remoteHeight, lineWidth,
+ curPoint, prePoint, starStartPoint, circleStartPoint, triangleStartPoint, rectangleStartPoint
+ } = options.remote;
+
+ //计算双方画布比例,按比例进行坐标放大/缩小
+ const ratioWidth = canvas.width / remoteWidth;
+ const ratioHeight = canvas.height / remoteHeight;
+
+ //调整画笔
+ options.remote.lineWidth = lineWidth * (ratioWidth + ratioHeight) / 2
+ curPoint.x = curPoint.x * ratioWidth;
+ curPoint.y = curPoint.y * ratioHeight;
+ options.remote.curPoint = curPoint;
+
if (drawMode === 'line') {
+ prePoint.x = prePoint.x * ratioWidth;
+ prePoint.y = prePoint.y * ratioHeight;
+ options.remote.prePoint = prePoint;
this.drawLine(options);
} else if (drawMode === 'circle') {
+ circleStartPoint.x = circleStartPoint.x * ratioWidth;
+ circleStartPoint.y = circleStartPoint.y * ratioHeight;
+ options.remote.circleStartPoint = circleStartPoint;
this.drawCircle(options);
} else if (drawMode === 'rectangle') {
+ rectangleStartPoint.x = rectangleStartPoint.x * ratioWidth;
+ rectangleStartPoint.y = rectangleStartPoint.y * ratioHeight;
+ options.remote.rectangleStartPoint = rectangleStartPoint;
this.drawRectangle(options);
} else if (drawMode === 'text') {
this.drawText(options);
} else if(drawMode === 'triangle'){
+ triangleStartPoint.x = triangleStartPoint.x * ratioWidth;
+ triangleStartPoint.y = triangleStartPoint.y * ratioHeight;
+ options.remote.triangleStartPoint = triangleStartPoint;
this.drawTriangle(options);
} else if(drawMode === 'star'){
+ starStartPoint.x = starStartPoint.x * ratioWidth;
+ starStartPoint.y = starStartPoint.y * ratioHeight;
+ options.remote.starStartPoint = starStartPoint;
this.drawStar(options);
} else {
console.log("收到远程未知的绘制模式")
}
},
// 打开/关闭本地画笔
- openDraw: function ({
- openCallback, closeCallback, localDrawCallback
- }) {
+ openDraw: function ({ openCallback, closeCallback, localDrawCallback }) {
let that = this;
if (this.isOpenDraw) {
@@ -466,126 +495,185 @@ const draw = new Vue({
that.drawing = false;
};
},
+ // 开始绘制
startDrawHandler: function ({ canvas, context, localDrawCallback }) {
//公共参数
- let commOptions = {
- event : "start",
+ let localCommOptions = {
canvas,
context,
localDrawCallback,
- drawMode: this.drawMode,
+ devicePixelRatio : this.devicePixelRatio,
+ width : canvas.width,
+ height: canvas.height,
+ lineCap: this.lineCap,
+ lineJoin: this.lineJoin,
lineWidth: this.lineWidth,
strokeStyle: this.strokeStyle,
fillStyle: this.strokeStyle,
- lineCap: "round",
- lineJoin: "round"
}
-
+
if (this.drawMode === 'delete') {
- this.drawDelete(Object.assign(commOptions, {
- prePoint: this.prePoint,
- curPoint : this.prePoint
- }))
+ this.drawDelete({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ prePoint: this.prePoint,
+ curPoint : this.prePoint
+ }),
+ })
} else if (this.drawMode === 'rectangle') {
//开始的时候固定好矩形的起点
this.rectangleStartPoint = this.prePoint;
- this.drawRectangle(Object.assign(commOptions, {
- rectangleStartPoint: this.rectangleStartPoint,
- curPoint: this.prePoint,
- rectangleFill : this.rectangleFill
- }))
+ this.drawRectangle({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ rectangleStartPoint: this.rectangleStartPoint,
+ curPoint: this.prePoint,
+ rectangleFill : this.rectangleFill
+ }),
+ })
} else if (this.drawMode === 'circle') {
//开始的时候固定好圆的起点
this.circleStartPoint = this.prePoint;
- this.drawCircle(Object.assign(commOptions, {
- circleStartPoint: this.circleStartPoint,
- curPoint: this.prePoint,
- circleFill : this.circleFill,
- }))
+ this.drawCircle({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ circleStartPoint: this.circleStartPoint,
+ curPoint: this.prePoint,
+ circleFill : this.circleFill,
+ }),
+ })
} else if(this.drawMode === 'triangle'){
//开始的时候固定好三角形的起点
this.triangleStartPoint = this.prePoint;
- this.drawTriangle(Object.assign(commOptions, {
- triangleStartPoint: this.triangleStartPoint,
- curPoint: this.prePoint,
- triangleFill : this.triangleFill
- }));
+ this.drawTriangle({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ triangleStartPoint: this.triangleStartPoint,
+ curPoint: this.prePoint,
+ triangleFill : this.triangleFill
+ }),
+ })
} else if(this.drawMode === 'star'){
//开始的时候固定好星星的起点
this.starStartPoint = this.prePoint;
- this.drawStar(Object.assign(commOptions, {
- starStartPoint: this.starStartPoint,
- curPoint: this.prePoint,
- starFill : this.starFill
- }));
+ this.drawStar({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ starStartPoint: this.starStartPoint,
+ curPoint: this.prePoint,
+ starFill : this.starFill
+ }),
+ })
} else if (this.drawMode === 'text') {
- this.drawText(Object.assign(commOptions, {
- curPoint: this.prePoint,
- }))
- this.endDrawHandler(Object.assign(commOptions, {
+ this.drawText({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ curPoint: this.prePoint,
+ }),
+ })
+ this.endDrawHandler(Object.assign(localCommOptions, {
curPoint: this.prePoint,
}))
} else if(this.drawMode === 'line'){
- this.drawLine(Object.assign(commOptions, {
- prePoint: this.prePoint,
- curPoint: this.prePoint,
- }));
+ this.drawLine({
+ event : "start",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ prePoint: this.prePoint,
+ curPoint: this.prePoint,
+ }),
+ })
}
},
+ // 绘制中
drawingHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
if (!this.drawing) {
return
}
+
//公共参数
- let commOptions = {
- event : "move",
+ let localCommOptions = {
canvas,
context,
localDrawCallback,
- drawMode: this.drawMode,
+ devicePixelRatio : this.devicePixelRatio,
+ width : canvas.width,
+ height: canvas.height,
+ lineCap: this.lineCap,
+ lineJoin: this.lineJoin,
lineWidth: this.lineWidth,
strokeStyle: this.strokeStyle,
fillStyle: this.strokeStyle,
- lineCap: "round",
- lineJoin: "round"
}
if (this.drawMode === 'delete') {
- this.drawDelete(Object.assign(commOptions, {
- prePoint: this.prePoint,
- curPoint
- }))
+ this.drawDelete({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ prePoint: this.prePoint,
+ curPoint
+ }),
+ })
} else if (this.drawMode === 'rectangle') {
- this.drawRectangle(Object.assign(commOptions, {
- rectangleStartPoint: this.rectangleStartPoint,
- curPoint,
- rectangleFill : this.rectangleFill
- }));
+ this.drawRectangle({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ rectangleStartPoint: this.rectangleStartPoint,
+ curPoint,
+ rectangleFill : this.rectangleFill
+ }),
+ })
} else if (this.drawMode === 'circle') {
- this.drawCircle(Object.assign(commOptions, {
- circleStartPoint: this.circleStartPoint,
- curPoint,
- circleFill : this.circleFill,
- }))
+ this.drawCircle({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ circleStartPoint: this.circleStartPoint,
+ curPoint,
+ circleFill : this.circleFill,
+ }),
+ })
} else if(this.drawMode === 'triangle'){
- this.drawTriangle(Object.assign(commOptions, {
- triangleStartPoint: this.triangleStartPoint,
- curPoint,
- triangleFill : this.triangleFill
- }));
+ this.drawTriangle({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ triangleStartPoint: this.triangleStartPoint,
+ curPoint,
+ triangleFill : this.triangleFill
+ }),
+
+ })
} else if(this.drawMode === 'star'){
- this.drawStar(Object.assign(commOptions, {
- starStartPoint: this.starStartPoint,
- curPoint,
- starFill : this.starFill
- }));
+ this.drawStar({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ starStartPoint: this.starStartPoint,
+ curPoint,
+ starFill : this.starFill
+ }),
+ })
} else if(this.drawMode === 'line'){
- this.drawLine(Object.assign(commOptions, {
- prePoint: this.prePoint,
- curPoint,
- }));
+ this.drawLine({
+ event : "move",
+ drawMode: this.drawMode,
+ local : Object.assign(localCommOptions, {
+ prePoint: this.prePoint,
+ curPoint,
+ }),
+ })
}
},
+ // 结束绘制
endDrawHandler: function ({ canvas, curPoint, context, localDrawCallback }) {
//图像记录,用于回滚撤销操作
if (
@@ -600,13 +688,12 @@ const draw = new Vue({
//结束的时候通知下远程,可以保存画布到缓存列表中
localDrawCallback && localDrawCallback({
event : "end",
- drawMode : this.drawMode
+ drawMode : this.drawMode,
+ remote : {}
})
},
- //下载画布图片
- drawDownload: function ( options ) {
- const { canvas, context, localDrawCallback } = options;
-
+ // 下载画布图片
+ drawDownload: function ({ canvas, context, localDrawCallback }) {
let image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
let link = document.createElement('a');
link.href = image;
@@ -614,16 +701,13 @@ const draw = new Vue({
link.click();
},
// 画布重置
- drawReset: function (options) {
- const { canvas, context, localDrawCallback } = options;
-
+ drawReset: function ({ canvas, context, localDrawCallback }) {
context.clearRect(0, 0, canvas.width, canvas.height);
this.drawHistoryList = [];
this.drawRollbackPoint = 0;
},
// 回退回滚的绘制
- drawUndoRollback: function (options) {
- const { canvas, context, localDrawCallback } = options;
+ drawUndoRollback: function ({ canvas, context, localDrawCallback }) {
//最多前进到最后一条记录
if (this.drawRollbackPoint < this.drawHistoryList.length - 1) {
this.drawRollbackPoint = this.drawRollbackPoint + 1;
@@ -637,8 +721,7 @@ const draw = new Vue({
}
},
// 画布回退
- drawRollback: async function (options) {
- const { canvas, context, localDrawCallback } = options;
+ drawRollback: async function ({ canvas, context, localDrawCallback }) {
//最多回退到原点
if (this.drawRollbackPoint > 0) {
this.drawRollbackPoint = this.drawRollbackPoint - 1;
@@ -651,9 +734,17 @@ const draw = new Vue({
}
},
// 画笔擦除
- drawDelete: function (options) {
- const { canvas, context, prePoint, curPoint, localDrawCallback } = options;
- context.lineWidth = this.lineWidth;
+ drawDelete: function ({ event, drawMode, local : {
+ canvas, context, lineWidth, curPoint, prePoint, lineCap,
+ width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle
+ }}) {
+ context.lineWidth = lineWidth;
+ context.lineCap = lineCap;
+ context.lineJoin = lineJoin;
+ context.strokeStyle = strokeStyle;
+ context.fillStyle = fillStyle;
+
//防止移动过快,canvas渲染存在间隔,导致线条断层,在这里补充绘制间隔的点
let x = prePoint.x;
let y = prePoint.y;
@@ -666,14 +757,17 @@ const draw = new Vue({
while (i < distance) {
x += xUnit;
y += yUnit;
- context.clearRect(x - 20, y - 20, this.lineWidth, this.lineWidth);
+ context.clearRect(x - 20, y - 20, lineWidth, lineWidth);
i++;
}
},
// 图片渲染处理
- drawImage: function (options) {
+ drawImage: function ({ event, drawMode, local : {
+ canvas, context, lineWidth, curPoint, prePoint, lineCap,
+ width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle, localDrawCallback
+ }}) {
let that = this;
- const { canvas, context, localDrawCallback } = options;
let input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
@@ -695,11 +789,14 @@ const draw = new Vue({
}
},
// 画笔渲染处理, 两点式绘制
- drawLine: function (options) {
- const {
- canvas, context, localDrawCallback, prePoint, curPoint,
- lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote,
- } = options;
+ drawLine: function ({ event, drawMode, fromRemote, local, remote}) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, prePoint, lineCap,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
// 设置画笔样式
context.lineWidth = lineWidth;
@@ -728,16 +825,23 @@ const draw = new Vue({
i++;
}
- if (!fromRemote) { //本地的绘制数据回调给远端
- localDrawCallback && localDrawCallback(options);
+ //如果是本地绘制,完成绘制后数据回调给远端
+ if (!fromRemote) {
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, prePoint, lineCap, width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle,
+ }});
}
},
// 星星渲染处理
- drawStar: function (options) {
- const {
- canvas, context, localDrawCallback, starStartPoint, curPoint,
- lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, starFill
- } = options;
+ drawStar: function ({ event, drawMode, fromRemote, local, remote}) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, starStartPoint, lineCap, starFill,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
// 设置画笔样式
context.lineWidth = lineWidth;
@@ -778,16 +882,23 @@ const draw = new Vue({
}
}
- if (!fromRemote) { //本地的绘制数据回调给远端
- localDrawCallback && localDrawCallback(options);
+ //如果是本地绘制,完成绘制后数据回调给远端
+ if (!fromRemote) {
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, starStartPoint, lineCap, width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle, starFill
+ }});
}
},
// 三角形渲染处理
- drawTriangle: function (options) {
- const {
- canvas, context, localDrawCallback, triangleStartPoint, curPoint,
- lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, triangleFill
- } = options;
+ drawTriangle: function ({ event, drawMode, fromRemote, local, remote }) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, triangleStartPoint, lineCap, triangleFill,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
// 设置画笔样式
context.lineWidth = lineWidth;
@@ -827,16 +938,23 @@ const draw = new Vue({
}
}
- if (!fromRemote) { //本地的绘制数据回调给远端
- localDrawCallback && localDrawCallback(options);
+ //如果是本地绘制,完成绘制后数据回调给远端
+ if (!fromRemote) {
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, triangleStartPoint, lineCap, width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle, triangleFill
+ }});
}
},
// 圆形渲染处理
- drawCircle: function (options) {
- const {
- canvas, context, localDrawCallback, circleStartPoint, curPoint,
- lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, circleFill
- } = options;
+ drawCircle: function ({ event, drawMode, fromRemote, local, remote }) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, circleStartPoint, lineCap, circleFill,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
// 设置画笔样式
context.lineWidth = lineWidth;
@@ -869,16 +987,23 @@ const draw = new Vue({
}
}
- if (!fromRemote) { //本地的绘制数据回调给远端
- localDrawCallback && localDrawCallback(options);
+ //如果是本地绘制,完成绘制后数据回调给远端
+ if (!fromRemote) {
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, circleStartPoint, lineCap, width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle, circleFill
+ }});
}
},
// 矩形渲染处理
- drawRectangle: function (options) {
- const {
- canvas, context, localDrawCallback, rectangleStartPoint, curPoint,
- lineWidth, strokeStyle, fillStyle, lineCap, lineJoin, fromRemote, rectangleFill
- } = options;
+ drawRectangle: function ({ event, drawMode, fromRemote, local, remote }) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, rectangleStartPoint, lineCap, rectangleFill,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
// 设置画笔样式
context.lineWidth = lineWidth;
@@ -890,8 +1015,8 @@ const draw = new Vue({
// 计算矩形的位置和尺寸
const x = Math.min(rectangleStartPoint.x, curPoint.x);
const y = Math.min(rectangleStartPoint.y, curPoint.y);
- const width = Math.abs(curPoint.x - rectangleStartPoint.x);
- const height = Math.abs(curPoint.y - rectangleStartPoint.y);
+ const rwidth = Math.abs(curPoint.x - rectangleStartPoint.x);
+ const rheight = Math.abs(curPoint.y - rectangleStartPoint.y);
if (this.drawRollbackPoint >= 0) {
const img = new Image();
@@ -903,7 +1028,7 @@ const draw = new Vue({
context.drawImage(img, 0, 0, canvas.width, canvas.height);
//绘制新矩形
context.beginPath();
- context.rect(x, y, width, height);
+ context.rect(x, y, rwidth, rheight);
if(rectangleFill){
context.fill();
}
@@ -911,43 +1036,58 @@ const draw = new Vue({
}
}
- if (!fromRemote) { //本地的绘制数据回调给远端
- localDrawCallback && localDrawCallback(options);
+ //如果是本地绘制,完成绘制后数据回调给远端
+ if (!fromRemote) {
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, rectangleStartPoint, lineCap, width, height, devicePixelRatio,
+ lineJoin, strokeStyle, fillStyle, rectangleFill
+ }});
}
},
// 文字渲染处理
- drawText: function (options) {
- let {
- canvas, context, localDrawCallback, curPoint, text, lineWidth, strokeStyle,
- fillStyle, lineCap, lineJoin, fromRemote,
- } = options;
+ drawText: function ({ event, drawMode, fromRemote, local, remote }) {
+ if(fromRemote){
+ local = remote;
+ }
+ let {
+ canvas, context, lineWidth, curPoint, text, lineCap,
+ width, height, devicePixelRatio, lineJoin, strokeStyle, fillStyle, localDrawCallback
+ } = local;
curPoint = {
- x : curPoint.x / window.devicePixelRatio,
- y : curPoint.y / window.devicePixelRatio
+ x : curPoint.x / devicePixelRatio,
+ y : curPoint.y / devicePixelRatio
}
// 设置字体样式
context.strokeStyle = strokeStyle;
- context.font = "28px orbitron";
+ context.font = Math.min(lineWidth * 7, 28) + "px orbitron";
context.textBaseline = "middle";
context.lineCap = lineCap;
context.lineJoin = lineJoin;
- context.lineWidth = 3;
+ context.lineWidth = 1;
const canvasWidth = parseInt(canvas.style.width);
const canvasHeight = parseInt(canvas.style.height);
//文字渲染处理
function drawTextHandler(content){
- const textWidth = context.measureText(content).width;
- // 如果文字超出画布宽度,将文字绘制到画布最右边
- let fixPointX = canvasWidth - textWidth > curPoint.x ? curPoint.x : canvasWidth - textWidth;
- fixPointX = fixPointX < 10 ? 10 : fixPointX;
- // 如果文字超出画布高度,将文字绘制到画布最下边
- let fixPointY = canvasHeight - 20 > curPoint.y ? curPoint.y : canvasHeight - 20;
- fixPointY = fixPointY < 10 ? 10 : fixPointY;
- context.strokeText(content, fixPointX * window.devicePixelRatio, fixPointY * window.devicePixelRatio);
+ let words = content.split("");
+ let subWords = "";
+ let wordHeight = 40;
+ for(let i = 0; i < words.length; i++){
+ let curSubWords = subWords + words[i];
+ const curSubWordsWidth = context.measureText(curSubWords).width;
+
+ if(curPoint.x + curSubWordsWidth > canvasWidth && i > 0){
+ context.fillText(subWords, curPoint.x * devicePixelRatio, curPoint.y * devicePixelRatio);
+ subWords = words[i];
+ curPoint.y += wordHeight;
+ }else{
+ subWords = curSubWords;
+ }
+ }
+ context.fillText(subWords, curPoint.x * devicePixelRatio, curPoint.y * devicePixelRatio);
}
if(fromRemote){
@@ -983,7 +1123,7 @@ const draw = new Vue({
} else if (curPoint.y < 100) {
textarea.style.bottom = (canvasHeight - 100) + 'px';
} else {
- textarea.style.top = (curPoint.y + 70)+ 'px';
+ textarea.style.top = (curPoint.y + 170)+ 'px';
}
parentDom.appendChild(textarea);
textarea.focus();
@@ -992,8 +1132,11 @@ const draw = new Vue({
if (textarea.value !== '') {
drawTextHandler(textarea.value);
document.getElementById("drawLine").click()
- options.text = textarea.value;
- localDrawCallback && localDrawCallback(options);
+
+ localDrawCallback && localDrawCallback({ event, drawMode, fromRemote : true, remote : {
+ lineWidth, curPoint, lineCap, width, height, devicePixelRatio, text : textarea.value,
+ lineJoin, strokeStyle, fillStyle,
+ }});
}
})
}
diff --git a/svr/res/js/index.js b/svr/res/js/index.js
index 00ca647..1474e1b 100644
--- a/svr/res/js/index.js
+++ b/svr/res/js/index.js
@@ -204,8 +204,102 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
}
},
methods: {
+ updateRemoteRtcState : async function(){
+ for(let id in this.remoteMap){
+ let stat = await window.tlrtcfile.getWebrtcStats(
+ this.getOrCreateRtcConnect(id)
+ );
+ let remoteCandidate = stat.get("remote-candidate") || [];
+ let p2pModes = remoteCandidate.map(item => {
+ if(['host','srflx','prflx'].includes(item.report.candidateType)){
+ return "直连"
+ }else if(item.report.candidateType === 'relay'){
+ return "中继"
+ }else{
+ return "未知"
+ }
+ })
+ this.setRemoteInfo(id, {
+ //p2p连接模式: host, srflx, prflx, relay
+ p2pMode : Array.from(new Set(p2pModes)).join(",")
+ })
+ }
+ this.$forceUpdate()
+ },
+ showRemoteUser : async function(remote){
+ let stat = await window.tlrtcfile.getWebrtcStats(this.getOrCreateRtcConnect(remote.id));
+ const rtcStatList = [];
+ stat.forEach((value, key)=>{
+ rtcStatList.push(
+ ...value.map(item => {
+ return Object.assign(item.report, {
+ description_zh: item.description
+ })
+ })
+ )
+ })
+ let rtcStatDomList = '';
+ rtcStatList.forEach(statItem => {
+ let rtcStatDomVal = `
description_zh: ${statItem.description_zh}
`;
+ for(let key in statItem){
+ if(key === 'description_zh'){
+ continue
+ }
+ rtcStatDomVal += `
${key}: ${statItem[key]}
`;
+ }
+ rtcStatDomList += `
${rtcStatDomVal}
`;
+ })
+
+ let that = this;
+ layer.closeAll(function () {
+ layer.open({
+ type: 1,
+ closeBtn: 0,
+ fixed: true,
+ maxmin: false,
+ shadeClose: true,
+ area: ['350px', '380px'],
+ title: `rtc连接实时统计信息`,
+ success: function (layero, index) {
+ document.querySelector(".layui-layer-title").style.borderTopRightRadius = "8px";
+ document.querySelector(".layui-layer-title").style.borderTopLeftRadius = "8px";
+ document.querySelector(".layui-layer").style.borderRadius = "8px";
+ document.querySelector(".layui-layer").style.background = "#f8f8f8";
+
+ carousel.render({
+ elem: '#tl-rtc-file-rtcinfo',
+ width: '100%',
+ autoplay : false,
+ indicator: 'outside'
+ });
+ },
+ content: `
+
+
+
+
${that.lang.userid}: ${remote.id}
+
${that.lang.nickname}: ${remote.nickName}
+
${that.lang.room_channel}: ${that.roomId}
+
${that.lang.website_language}: ${remote.langMode}
+
${that.lang.network_status}: ${remote.network}
+
${that.lang.join_time}: ${remote.joinTime}
+
${that.lang.public_ip}: ${remote.ip}
+
${that.lang.webrtc_ice_state}: ${remote.iceConnectionState}
+
${that.lang.device_classification}: ${remote.ua}
+
${that.lang.terminal_equipment}: ${remote.userAgent}
+
+ ${rtcStatDomList}
+
+
+ `
+ })
+ })
+ },
+ iceOk : function(state){
+ return ['completed', 'connected', 'checking', 'new'].includes(state);
+ },
consoleLogo : function(){
- window.console.log(`%c____ TL-RTC-FILE-V10.1.5 ____ \n____ FORK ME IN GITHUB ____ \n____ https://github.com/tl-open-source/tl-rtc-file ____`, this.logo)
+ window.console.log(`%c____ TL-RTC-FILE-V${this.version} ____ \n____ FORK ME IN GITHUB ____ \n____ https://github.com/tl-open-source/tl-rtc-file ____`, this.logo)
},
changeLanguage: function () {
let that = this;
@@ -291,9 +385,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
let file = filterFile[0]
if (file.size > this.uploadCodeFileMaxSize) {
- if(window.layer){
- layer.msg(`${this.lang.max_saved} ${this.uploadCodeFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
- }
+ layer.msg(`${this.lang.max_saved} ${this.uploadCodeFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
return
}
@@ -363,7 +455,8 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.initSendFile(recoder);
},
// 私聊弹窗
- startChatRoomSingle: function(remote){
+ startChatRoomSingle: function(event, remote){
+ event.stopPropagation();
this.chatRoomSingleSocketId = remote.id;
let that = this;
let options = {
@@ -433,7 +526,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
`
@@ -626,7 +719,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
let fileRecorde = filterFile[0];
if (fileRecorde.size > this.previewFileMaxSize) {
- layer.msg(`${this.lang.max_previewed} ${this.previewFileMaxSize / 1024 / 1024} ${mb_file}`);
+ layer.msg(`${this.lang.max_previewed} ${this.previewFileMaxSize / 1024 / 1024} ${this.lang.mb_file}`);
return
}
@@ -853,7 +946,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
`
@@ -1007,11 +1100,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
layer.prompt({
formType: 1,
- title: this.lang.please_enter_password
+ title: that.lang.please_enter_password
}, function (value, index, elem) {
that.createPasswordRoom(value);
layer.close(index);
- that.addUserLogs(this.lang.enter_password_room + that.roomId + `,${this.lang.password}:` + value);
+ that.addUserLogs(that.lang.enter_password_room + that.roomId + `,${that.lang.password}:` + value);
});
});
}
@@ -1124,12 +1217,12 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
-
${this.lang.relay_server_current} ${useTurn ? this.lang.on : this.lang.off}
-
${this.lang.relay_server_current_detail}
-
+
${this.lang.relay_server_current} '${useTurn ? this.lang.on : this.lang.off}'
+
${this.lang.relay_server_current_detail}
+
-
-
+
+
@@ -1180,11 +1273,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
});
that.clickMediaVideo();
that.isVideoShare = !that.isVideoShare;
- that.addUserLogs(this.lang.start_video_call);
+ that.addUserLogs(that.lang.start_video_call);
}else{
layer.prompt({
formType: 1,
- title: this.lang.please_enter_video_call_room_num
+ title: that.lang.please_enter_video_call_room_num
}, function (value, index, elem) {
that.roomId = value;
that.createMediaRoom("video");
@@ -1197,7 +1290,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
});
that.clickMediaVideo();
that.isVideoShare = !that.isVideoShare;
- that.addUserLogs(this.lang.start_video_call);
+ that.addUserLogs(that.lang.start_video_call);
});
}
},
@@ -1239,7 +1332,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
});
that.clickMediaScreen();
that.isScreenShare = !that.isScreenShare;
- that.addUserLogs(this.lang.start_screen_sharing);
+ that.addUserLogs(that.lang.start_screen_sharing);
}else{
layer.prompt({
formType: 1,
@@ -1256,7 +1349,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
});
that.clickMediaScreen();
that.isScreenShare = !that.isScreenShare;
- that.addUserLogs(this.lang.this.lang.start_screen_sharing);
+ that.addUserLogs(that.lang.start_screen_sharing);
});
}
},
@@ -1289,9 +1382,25 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
return
}
let that = this;
- if (window.layer) {
- if(that.isShareJoin){ //分享进入
+ if(that.isShareJoin){ //分享进入
+ that.createMediaRoom("live");
+ that.socket.emit('message', {
+ emitType: "startLiveShare",
+ room: that.roomId,
+ to : that.socketId
+ });
+ that.clickMediaLive();
+ that.isLiveShare = !that.isLiveShare;
+ that.addUserLogs(that.lang.start_live);
+ }else{
+ layer.prompt({
+ formType: 1,
+ title: this.lang.please_enter_live_room_num,
+ }, function (value, index, elem) {
+ that.roomId = value;
that.createMediaRoom("live");
+ layer.close(index)
+
that.socket.emit('message', {
emitType: "startLiveShare",
room: that.roomId,
@@ -1299,30 +1408,13 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
});
that.clickMediaLive();
that.isLiveShare = !that.isLiveShare;
- that.addUserLogs(this.lang.start_live);
- }else{
- layer.prompt({
- formType: 1,
- title: this.lang.please_enter_live_room_num,
- }, function (value, index, elem) {
- that.roomId = value;
- that.createMediaRoom("live");
- layer.close(index)
-
- that.socket.emit('message', {
- emitType: "startLiveShare",
- room: that.roomId,
- to : that.socketId
- });
- that.clickMediaLive();
- that.isLiveShare = !that.isLiveShare;
- that.addUserLogs(this.lang.start_live);
- });
- }
+ that.addUserLogs(that.lang.start_live);
+ });
}
},
// 打开画笔
openRemoteDraw : function(){
+ let that = this;
if (!this.switchData.openRemoteDraw) {
layer.msg(this.lang.feature_close)
this.addUserLogs(this.lang.feature_close)
@@ -1338,26 +1430,26 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
// 触发draw.js中的方法
window.Bus.$emit("openDraw", {
openCallback: () => {
- this.socket.emit('message', {
+ that.socket.emit('message', {
emitType: "startRemoteDraw",
- room: this.roomId,
- to: this.socketId
+ room: that.roomId,
+ to: that.socketId
});
},
closeCallback: (drawCount) => {
- this.socket.emit('message', {
+ that.socket.emit('message', {
emitType: "stopRemoteDraw",
- room: this.roomId,
- to: this.socketId,
+ room: that.roomId,
+ to: that.socketId,
drawCount : drawCount
});
},
localDrawCallback : (data) => {
- Object.entries(this.remoteMap).forEach(([id, remote]) => {
+ Object.entries(that.remoteMap).forEach(([id, remote]) => {
if(remote && remote.sendDataChannel){
const sendDataChannel = remote.sendDataChannel;
if (!sendDataChannel || sendDataChannel.readyState !== 'open') {
- this.addSysLogs("sendDataChannel error in draw")
+ that.addSysLogs("sendDataChannel error in draw")
return;
}
sendDataChannel.send(JSON.stringify(data));
@@ -1387,15 +1479,15 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
openCallback : () => {
that.socket.emit('message', {
emitType: "startScreen",
- room: this.roomId,
- to : this.socketId
+ room: that.roomId,
+ to : that.socketId
});
- that.addUserLogs(this.lang.start_local_screen_recording);
+ that.addUserLogs(that.lang.start_local_screen_recording);
},
closeCallback : (res) => {
- this.receiveFileRecoderList.push({
- id: this.lang.web_screen_recording,
- nickName : this.nickName,
+ that.receiveFileRecoderList.push({
+ id: that.lang.web_screen_recording,
+ nickName : that.nickName,
href: res.src,
style: 'color: #ff5722;text-decoration: underline;',
name: 'screen-recording-' + res.donwId + '.mp4',
@@ -1406,14 +1498,14 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
start: 0,
cost: res.times
})
- this.socket.emit('message', {
+ that.socket.emit('message', {
emitType: "stopScreen",
- to : this.socketId,
- room: this.roomId,
+ to : that.socketId,
+ room: that.roomId,
size: res.size,
cost: res.times
});
- this.addUserLogs(this.lang.end_local_screen_recording);
+ that.addUserLogs(that.lang.end_local_screen_recording);
}
});
},
@@ -1461,7 +1553,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
- shift+enter ${this.lang.enter_send}
+ shift+enter | ${this.lang.enter_send}
`
@@ -1617,7 +1709,7 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
- shift+enter ${this.lang.enter_send}
+ shift+enter | ${this.lang.enter_send}
`
@@ -2118,7 +2210,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
type : 'password',
password : '',
nickName : this.nickName,
- langMode : this.langMode
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network
});
this.isJoined = true;
this.addPopup({
@@ -2147,7 +2241,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
room: this.roomId,
type: type,
nickName : this.nickName,
- langMode : this.langMode
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network
});
this.isJoined = true;
this.roomType = type;
@@ -2183,7 +2279,9 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
type : 'password',
password: password,
nickName : this.nickName,
- langMode : this.langMode
+ langMode : this.langMode,
+ ua: this.isMobile ? 'mobile' : 'pc',
+ network : this.network
});
this.isJoined = true;
this.addPopup({
@@ -2225,12 +2323,19 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
rtcConnect.oniceconnectionstatechange = (e) => {
that.addSysLogs("iceConnectionState: " + rtcConnect.iceConnectionState);
+ that.setRemoteInfo(id, {
+ iceConnectionState : rtcConnect.iceConnectionState
+ })
}
//保存peer连接
this.rtcConns[id] = rtcConnect;
if (!this.remoteMap[id]) {
- Vue.set(this.remoteMap, id, { id: id, receiveChatRoomSingleList : [] })
+ Vue.set(this.remoteMap, id, {
+ id: id,
+ receiveChatRoomSingleList : [],
+ p2pMode : '识别中...'
+ })
}
//数据通道
@@ -2467,11 +2572,20 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
})
}
- // 缓冲区満了
+ //缓冲区暂定 256kb
+ sendFileDataChannel.bufferedAmountLowThreshold = 16 * 1024 * 16;
+ //局域网一般不会走缓冲区,所以bufferedAmount一般为0,公网部分情况受限于带宽,bufferedAmount可能会逐渐堆积,从而进行排队
if (sendFileDataChannel.bufferedAmount > sendFileDataChannel.bufferedAmountLowThreshold) {
- this.addSysLogs(this.lang.file_send_channel_buffer_full)
+ this.addSysLogs(
+ that.lang.file_send_channel_buffer_full + ",bufferedAmount=" +
+ sendFileDataChannel.bufferedAmount + ",bufferedAmountLowThreshold=" +
+ sendFileDataChannel.bufferedAmountLowThreshold
+ )
sendFileDataChannel.onbufferedamountlow = () => {
- this.addSysLogs(this.lang.file_send_channel_buffer_recover)
+ that.addSysLogs(
+ that.lang.file_send_channel_buffer_recover + ",bufferedAmount=" +
+ sendFileDataChannel.bufferedAmount
+ )
sendFileDataChannel.onbufferedamountlow = null;
that.sendFileToRemoteByLoop(event);
}
@@ -2844,15 +2958,17 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
for (let i = 0; i < data.peers.length; i++) {
let otherSocketId = data.peers[i].id;
- let otherSocketIdNickName = data.peers[i].nickName;
- let otherSocketIdLangMode = data.peers[i].langMode;
- let otherSocketIdOwner = data.peers[i].owner;
let rtcConnect = that.getOrCreateRtcConnect(otherSocketId);
// 处理完连接后,更新下昵称
that.setRemoteInfo(otherSocketId, {
- nickName : otherSocketIdNickName,
- langMode : otherSocketIdLangMode,
- owner : otherSocketIdOwner
+ nickName : data.peers[i].nickName,
+ langMode : data.peers[i].langMode,
+ owner : data.peers[i].owner,
+ ua : data.peers[i].ua,
+ joinTime : data.peers[i].joinTime,
+ userAgent : data.peers[i].userAgent,
+ ip : data.peers[i].ip,
+ network : data.peers[i].network,
})
await new Promise(resolve => {
@@ -2895,7 +3011,11 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
nickName : data.nickName,
owner : data.owner,
langMode : data.langMode,
- owner : false
+ ua : data.ua,
+ network : data.network,
+ joinTime : data.joinTime,
+ userAgent : data.userAgent,
+ ip : data.ip,
})
// 处理音视频逻辑
if (data.type === 'screen') {
@@ -3656,10 +3776,14 @@ axios.get("/api/comm/initData?turn="+useTurn, {}).then((initData) => {
this.addSysLogs(this.lang.basic_data_get_done);
this.addSysLogs(this.lang.window_event_init);
- window.onresize = this.touchResize;
+ window.onresize = this.touchResize;
setInterval(() => {
this.touchResize()
}, 1000);
+
+ setInterval(async () => {
+ await this.updateRemoteRtcState()
+ }, 5000);
this.addSysLogs(this.lang.window_event_init_done);
this.addSysLogs(this.lang.message_box_init);
diff --git a/svr/res/js/language.js b/svr/res/js/language.js
index 6e19fbd..9310c6c 100644
--- a/svr/res/js/language.js
+++ b/svr/res/js/language.js
@@ -314,8 +314,28 @@ const local_lang = {
"you_refresh_room": "You refreshed the room number, the current room number is",
"your_browser": "Your browser",
"your_ip_list": "Your IP list is",
+ "nickname" : "Nickname",
+ "userid" : "Userd",
+ "room_channel" : "Room channel",
+ "join_time" : "Join time",
+ "website_language" : "Website language",
+ "terminal_equipment" : "Terminal equipment",
+ "device_classification" : "Device classification",
+ "network_status" : "Network status",
+ "public_ip" : "Public IP",
+ "webrtc_ice_state" : "webrtc state"
},
"zh": {
+ "webrtc_ice_state" : "webrtc状态",
+ "nickname" : "用户昵称",
+ "userid" : "用户ID ",
+ "room_channel" : "房间频道",
+ "join_time" : "加入时间",
+ "website_language" : "网站语言",
+ "terminal_equipment" : "终端设备",
+ "device_classification" : "设备分类",
+ "network_status" : "网络状态",
+ "public_ip" : "传输地址",
"add_ice_candidate_failed": "addIceCandidate失败",
"add_ice_candidate_success": "addIceCandidateSuccess成功",
"ai_answering": "AI正在回答您的问题,请稍后再问",
@@ -445,9 +465,9 @@ const local_lang = {
"not_support": "不支持",
"note_website_for_learing": "注意:示例网站仅用于学习演示,请勿他用",
"notice": "通知",
- "off": "已关闭",
+ "off": "关闭",
"offer_failed": "offer失败",
- "on": "已开启",
+ "on": "开启",
"online": "当前在线人数",
"online_number": "人在线",
"only_show" : "仅展示 ",
@@ -553,7 +573,7 @@ const local_lang = {
"select_wait_send_record": "选择待发送记录中",
"selected_file": "已选择文件",
"selected_file_exist": "选择的文件已经存在相同的文件,不再重复添加",
- "self": "我自己",
+ "self": "自己",
"send": "发送",
"send_all": "一键发送",
"send_alone": "单独发送",
diff --git a/svr/res/pay.html b/svr/res/pay.html
index e338466..e21e8da 100644
--- a/svr/res/pay.html
+++ b/svr/res/pay.html
@@ -63,7 +63,7 @@
收费模式
- - 按小时计费:根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300,企业定制另谈
+ - 按小时计费:根据实际工作时间计算费用,目前个人定制功能2小时起,每小时200~300
- 阶段性付费:确认开发前,预付1/3,开发完成付1/3,交付上线1/3
diff --git a/svr/src/socket/rtcCreateJoin/createJoin.js b/svr/src/socket/rtcCreateJoin/createJoin.js
index 407b0ac..3d70176 100644
--- a/svr/src/socket/rtcCreateJoin/createJoin.js
+++ b/svr/src/socket/rtcCreateJoin/createJoin.js
@@ -19,7 +19,10 @@ const check = require("./../../utils/check/content");
async function userCreateAndJoin(io, socket, tables, dbClient, data){
let {handshake, userAgent, ip} = utils.getSocketClientInfo(socket);
- let {room, type, nickName, password = '', langMode = 'zh'} = data;
+ let {
+ room, type = 'file', nickName = '', password = '',
+ langMode = 'zh', ua = '', network = ''
+ } = data;
if (room && room.length > 15) {
room = room.toString().substr(0, 14);
@@ -28,14 +31,37 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
if(nickName && nickName.length > 20){
nickName = nickName.substr(0, 20);
}
- //设置昵称
- io.sockets.connected[socket.id].nickName = nickName;
- io.sockets.connected[socket.id].langMode = langMode;
+
+ if(['zh', 'en'].indexOf(langMode) === -1){
+ langMode = 'zh'
+ }
+
+ if(['file', 'screen', 'video', 'password', 'live'].indexOf(type) === -1){
+ type = 'file'
+ }
+
+ if(['pc', 'mobile'].indexOf(ua) === -1){
+ ua = 'pc';
+ }
+
+ if(['wifi', '4g', '3g', '2g', '5g'].indexOf(network) === -1){
+ network = '2g';
+ }
if(password && password.length > 6){
password = password.toString().substr(0,6);
}
+ //设置连接信息
+ io.sockets.connected[socket.id].nickName = nickName;
+ io.sockets.connected[socket.id].langMode = langMode;
+ io.sockets.connected[socket.id].ua = ua;
+ io.sockets.connected[socket.id].network = network;
+ io.sockets.connected[socket.id].ip = ip;
+ const joinTime = utils.formateDateTime(new Date(), "yyyy-MM-dd hh:mm:ss")
+ io.sockets.connected[socket.id].joinTime = joinTime;
+ io.sockets.connected[socket.id].userAgent = userAgent;
+
let recoderId = await daoRoom.createJoinRoom({
uid: "1",
uname: nickName,
@@ -105,6 +131,11 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
type: type,
recoderId : recoderId,
langMode : langMode,
+ ua : ua,
+ network : network,
+ joinTime : joinTime,
+ ip : ip,
+ userAgent : userAgent
});
let peers = new Array();
@@ -114,11 +145,22 @@ async function userCreateAndJoin(io, socket, tables, dbClient, data){
let peerNickName = io.sockets.connected[otherSocketId].nickName
let peerOwner = io.sockets.connected[otherSocketId].owner
let peerLangMode = io.sockets.connected[otherSocketId].langMode
+ let peerUa = io.sockets.connected[otherSocketId].ua
+ let peerNetwork = io.sockets.connected[otherSocketId].network
+ let peerJoinTime = io.sockets.connected[otherSocketId].joinTime
+ let peerIp = io.sockets.connected[otherSocketId].ip
+ let peerUserAgent = io.sockets.connected[otherSocketId].userAgent
+
peers.push({
id: otherSocketId,
nickName: peerNickName,
owner : peerOwner,
- langMode : peerLangMode
+ langMode : peerLangMode,
+ ua : peerUa,
+ network : peerNetwork,
+ joinTime : peerJoinTime,
+ ip : peerIp,
+ userAgent : peerUserAgent
});
}
diff --git a/svr/static/layui/font-ext/demo_index.html b/svr/static/layui/font-ext/demo_index.html
index 918da38..3864f52 100644
--- a/svr/static/layui/font-ext/demo_index.html
+++ b/svr/static/layui/font-ext/demo_index.html
@@ -54,6 +54,30 @@
+ -
+
+
数据汇总
+ 
+
+
+ -
+
+
控桩终端
+ 
+
+
+ -
+
+
浏览器
+ 
+
+
+ -
+
+
连接流
+ 
+
+
-
三角形
@@ -534,9 +558,9 @@
@font-face {
font-family: 'iconfont';
- src: url('iconfont.woff2?t=1688291642630') format('woff2'),
- url('iconfont.woff?t=1688291642630') format('woff'),
- url('iconfont.ttf?t=1688291642630') format('truetype');
+ src: url('iconfont.woff2?t=1688799262496') format('woff2'),
+ url('iconfont.woff?t=1688799262496') format('woff'),
+ url('iconfont.ttf?t=1688799262496') format('truetype');
}
第二步:定义使用 iconfont 的样式
@@ -562,6 +586,42 @@
+ -
+
+
+ 数据汇总
+
+ .icon-rtc-file-daohang-shujufenxi
+
+
+
+ -
+
+
+ 控桩终端
+
+ .icon-rtc-file-kongzhuangzhongduan
+
+
+
+ -
+
+
+ 浏览器
+
+ .icon-rtc-file-liulanqi
+
+
+
+ -
+
+
+ 连接流
+
+ .icon-rtc-file-lianjieliu
+
+
+
-
@@ -1282,6 +1342,38 @@
+ -
+
+
数据汇总
+ #icon-rtc-file-daohang-shujufenxi
+
+
+ -
+
+
控桩终端
+ #icon-rtc-file-kongzhuangzhongduan
+
+
+ -
+
+
浏览器
+ #icon-rtc-file-liulanqi
+
+
+ -
+
+
连接流
+ #icon-rtc-file-lianjieliu
+
+
-