[*] JS
This commit is contained in:
@@ -1,78 +0,0 @@
|
|||||||
# 部署
|
|
||||||
|
|
||||||
## 源
|
|
||||||
|
|
||||||
```
|
|
||||||
cd /etc/yum.repos.d
|
|
||||||
rm -rf *
|
|
||||||
wget /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
|
|
||||||
yum makecache
|
|
||||||
```
|
|
||||||
|
|
||||||
## 证书
|
|
||||||
|
|
||||||
```
|
|
||||||
keytool -genkeypair -keyalg RSA -dname "CN=localhost, OU=acgist, O=taoyao, L=GZ, ST=GD, C=CN" -alias taoyao -validity 3650 -ext ku:c=dig,keyE -ext eku=serverAuth -ext SAN=dns:localhost,ip:127.0.0.1 -keystore taoyao.jks -keypass 123456 -storepass 123456
|
|
||||||
```
|
|
||||||
|
|
||||||
## Linux句柄数量
|
|
||||||
|
|
||||||
```
|
|
||||||
vim /etc/security/limits.conf
|
|
||||||
|
|
||||||
root soft nofile 655350
|
|
||||||
root hard nofile 655350
|
|
||||||
* soft nofile 655350
|
|
||||||
* hard nofile 655350
|
|
||||||
* soft nproc 655350
|
|
||||||
* hard nproc 655350
|
|
||||||
* soft core unlimited
|
|
||||||
* hard core unlimited
|
|
||||||
```
|
|
||||||
|
|
||||||
## Linux内核优化
|
|
||||||
|
|
||||||
```
|
|
||||||
vim /etc/sysctl.conf
|
|
||||||
|
|
||||||
net.ipv4.tcp_tw_reuse = 1
|
|
||||||
net.ipv4.tcp_tw_recycle = 1
|
|
||||||
net.ipv4.tcp_syncookies = 1
|
|
||||||
net.ipv4.tcp_fin_timeout = 30
|
|
||||||
net.ipv4.tcp_max_tw_buckets = 8192
|
|
||||||
net.ipv4.tcp_max_syn_backlog = 8192
|
|
||||||
|
|
||||||
# 其他
|
|
||||||
net.core.rmem_max
|
|
||||||
net.core.rmem_default
|
|
||||||
net.core.wmem_max
|
|
||||||
net.core.wmem_default
|
|
||||||
net.core.somaxconn = 1024
|
|
||||||
net.core.netdev_max_backlog = 8092
|
|
||||||
net.ipv4.udp_mem
|
|
||||||
net.ipv4.udp_rmem
|
|
||||||
net.ipv4.udp_wmem
|
|
||||||
net.ipv4.tcp_mem = 78643200 104857600 157286400
|
|
||||||
net.ipv4.tcp_rmem = 873200 1746400 3492800
|
|
||||||
net.ipv4.tcp_wmem = 873200 1746400 3492800
|
|
||||||
|
|
||||||
sysctl -p
|
|
||||||
```
|
|
||||||
|
|
||||||
## 应用
|
|
||||||
|
|
||||||
```
|
|
||||||
```
|
|
||||||
|
|
||||||
## 防火墙
|
|
||||||
|
|
||||||
```
|
|
||||||
firewall-cmd --zone=public --add-port=8888/tcp --permanent
|
|
||||||
firewall-cmd --zone=public --add-port=45535-65535/tcp --permanent
|
|
||||||
firewall-cmd --zone=public --add-port=45535-65535/udp --permanent
|
|
||||||
|
|
||||||
firewall-cmd --reload
|
|
||||||
firewall-cmd --list-ports
|
|
||||||
firewall-cmd --zone=public --remove-port=45535-65535/tcp --permanent
|
|
||||||
firewall-cmd --zone=public --remove-port=45535-65535/udp --permanent
|
|
||||||
```
|
|
||||||
174
docs/Deploy.md
Normal file
174
docs/Deploy.md
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# 部署
|
||||||
|
|
||||||
|
## Yum源
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /etc/yum.repos.d
|
||||||
|
rm -rf *
|
||||||
|
wget /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
|
||||||
|
yum makecache
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linux句柄数量
|
||||||
|
|
||||||
|
```
|
||||||
|
vim /etc/security/limits.conf
|
||||||
|
|
||||||
|
root soft nofile 655350
|
||||||
|
root hard nofile 655350
|
||||||
|
* soft nofile 655350
|
||||||
|
* hard nofile 655350
|
||||||
|
* soft nproc 655350
|
||||||
|
* hard nproc 655350
|
||||||
|
* soft core unlimited
|
||||||
|
* hard core unlimited
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linux内核优化
|
||||||
|
|
||||||
|
```
|
||||||
|
vim /etc/sysctl.conf
|
||||||
|
|
||||||
|
net.ipv4.tcp_tw_reuse = 1
|
||||||
|
net.ipv4.tcp_tw_recycle = 1
|
||||||
|
net.ipv4.tcp_syncookies = 1
|
||||||
|
net.ipv4.tcp_fin_timeout = 30
|
||||||
|
net.ipv4.tcp_max_tw_buckets = 8192
|
||||||
|
net.ipv4.tcp_max_syn_backlog = 8192
|
||||||
|
|
||||||
|
# 其他
|
||||||
|
net.core.rmem_max
|
||||||
|
net.core.rmem_default
|
||||||
|
net.core.wmem_max
|
||||||
|
net.core.wmem_default
|
||||||
|
net.core.somaxconn = 1024
|
||||||
|
net.core.netdev_max_backlog = 8092
|
||||||
|
net.ipv4.udp_mem
|
||||||
|
net.ipv4.udp_rmem
|
||||||
|
net.ipv4.udp_wmem
|
||||||
|
net.ipv4.tcp_mem = 78643200 104857600 157286400
|
||||||
|
net.ipv4.tcp_rmem = 873200 1746400 3492800
|
||||||
|
net.ipv4.tcp_wmem = 873200 1746400 3492800
|
||||||
|
|
||||||
|
sysctl -p
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
```
|
||||||
|
yum install git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Java
|
||||||
|
|
||||||
|
安装之前需要卸载旧版,如果旧版已经是`17+`可以忽略安装。
|
||||||
|
|
||||||
|
```
|
||||||
|
# 下载
|
||||||
|
mkdir -p /data/java
|
||||||
|
cd /data/java
|
||||||
|
wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz
|
||||||
|
tar -zxvf openjdk-17.0.2_linux-x64_bin.tar.gz
|
||||||
|
# 环境变量
|
||||||
|
vim ~/.bash_profile
|
||||||
|
PATH=$PATH:/data/java/jdk-17.0.2/bin
|
||||||
|
. ~/.bash_profile
|
||||||
|
ln -sf /data/java/jdk-17.0.2/bin/java /usr/local/bin/java
|
||||||
|
# 验证
|
||||||
|
java -version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Maven
|
||||||
|
|
||||||
|
```
|
||||||
|
# 下载
|
||||||
|
mkdir -p /data/maven
|
||||||
|
cd /data/maven
|
||||||
|
wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
|
||||||
|
tar -zxvf apache-maven-3.8.6-bin.tar.gz
|
||||||
|
# 环境变量
|
||||||
|
vim ~/.bash_profile
|
||||||
|
PATH=$PATH:/data/maven/apache-maven-3.8.6/bin
|
||||||
|
. ~/.bash_profile
|
||||||
|
# 验证
|
||||||
|
mvn -version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Taoyao
|
||||||
|
|
||||||
|
```
|
||||||
|
# 下载源码
|
||||||
|
mkdir -p /data/taoyao
|
||||||
|
cd /data
|
||||||
|
git clone https://gitee.com/acgist/taoyao.git
|
||||||
|
cd /data/taoyao/taoyao
|
||||||
|
|
||||||
|
# 编译代码
|
||||||
|
mvn clean package -D skipTests
|
||||||
|
#mvn clean package -D skipTests -P release
|
||||||
|
|
||||||
|
# 拷贝脚本
|
||||||
|
cp taoyao-server/target/taoyao-server-1.0.0/bin/deploy.sh ../
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
vim /usr/lib/systemd/system/taoyao.service
|
||||||
|
----
|
||||||
|
[Unit]
|
||||||
|
Description=桃夭
|
||||||
|
After=network.target
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=root
|
||||||
|
Type=forking
|
||||||
|
KillMode=process
|
||||||
|
ExecStart=/data/taoyao/taoyao-server/bin/startup.sh
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
ExecStop=/bin/kill -QUIT $MAINPID
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
----
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl start taoyao
|
||||||
|
systemctl enable taoyao
|
||||||
|
```
|
||||||
|
|
||||||
|
## 防火墙
|
||||||
|
|
||||||
|
```
|
||||||
|
firewall-cmd --zone=public --add-port=8888/tcp --permanent
|
||||||
|
firewall-cmd --zone=public --add-port=45535-65535/udp --permanent
|
||||||
|
|
||||||
|
firewall-cmd --reload
|
||||||
|
firewall-cmd --list-ports
|
||||||
|
|
||||||
|
# 删除端口
|
||||||
|
firewall-cmd --zone=public --remove-port=8888/udp --permanent
|
||||||
|
firewall-cmd --zone=public --remove-port=45535-65535/udp --permanent
|
||||||
|
```
|
||||||
|
|
||||||
|
## 证书
|
||||||
|
|
||||||
|
正式环境建议关闭项目`SSL`配置,可以使用`Nginx`配置证书。
|
||||||
|
|
||||||
|
```
|
||||||
|
keytool -genkeypair -keyalg RSA -dname "CN=localhost, OU=acgist, O=taoyao, L=GZ, ST=GD, C=CN" -alias taoyao -validity 3650 -ext ku:c=dig,keyE -ext eku=serverAuth -ext SAN=dns:localhost,ip:127.0.0.1 -keystore taoyao.jks -keypass 123456 -storepass 123456
|
||||||
|
```
|
||||||
|
|
||||||
|
https://www.jianshu.com/p/fa047d7054eb
|
||||||
|
https://www.jianshu.com/p/59da3d350488
|
||||||
|
https://www.jianshu.com/p/fa047d7054eb
|
||||||
|
https://segmentfault.com/a/1190000039782685
|
||||||
|
https://www.cnblogs.com/bolingcavalry/p/15473808.html
|
||||||
|
http://www.manoner.com/post/音视频基础/WebRTC核心组件和协议栈/
|
||||||
|
https://blog.csdn.net/eguid_1/article/details/117277841
|
||||||
|
https://blog.csdn.net/xiang_6119/article/details/108779678
|
||||||
|
https://blog.csdn.net/qq_40321119/article/details/108336324
|
||||||
|
https://blog.csdn.net/ababab12345/article/details/115585378
|
||||||
|
https://blog.csdn.net/jisuanji111111/article/details/121634199
|
||||||
|
https://blog.csdn.net/weixin_48638578/article/details/120191152
|
||||||
|
https://blog.csdn.net/weixin_45565568/article/details/108929438
|
||||||
12
docs/LINK.md
12
docs/LINK.md
@@ -1,12 +0,0 @@
|
|||||||
https://www.jianshu.com/p/fa047d7054eb
|
|
||||||
https://www.jianshu.com/p/59da3d350488
|
|
||||||
https://segmentfault.com/a/1190000039782685
|
|
||||||
https://www.cnblogs.com/bolingcavalry/p/15473808.html
|
|
||||||
http://www.manoner.com/post/音视频基础/WebRTC核心组件和协议栈/
|
|
||||||
https://blog.csdn.net/eguid_1/article/details/117277841
|
|
||||||
https://blog.csdn.net/xiang_6119/article/details/108779678
|
|
||||||
https://blog.csdn.net/qq_40321119/article/details/108336324
|
|
||||||
https://blog.csdn.net/ababab12345/article/details/115585378
|
|
||||||
https://blog.csdn.net/jisuanji111111/article/details/121634199
|
|
||||||
https://blog.csdn.net/weixin_48638578/article/details/120191152
|
|
||||||
https://blog.csdn.net/weixin_45565568/article/details/108929438
|
|
||||||
@@ -15,22 +15,23 @@ fi
|
|||||||
# 编译代码
|
# 编译代码
|
||||||
if [ -z $mvned ]; then
|
if [ -z $mvned ]; then
|
||||||
echo "编译代码:${project.artifactId}-${project.version}"
|
echo "编译代码:${project.artifactId}-${project.version}"
|
||||||
mvn clean package install -pl "${project.groupId}:${project.artifactId}" -am -D skipTests -P ${env}
|
cd $base/taoyao
|
||||||
|
mvn clean package -D skipTests -P ${profile}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 删除文件:注意不要删除日志
|
# 删除文件:注意不要删除日志
|
||||||
rm -rf $base/../deploy/${project.artifactId}/bin
|
rm -rf $base/${project.artifactId}/bin
|
||||||
rm -rf $base/../deploy/${project.artifactId}/lib
|
rm -rf $base/${project.artifactId}/lib
|
||||||
rm -rf $base/../deploy/${project.artifactId}/config
|
rm -rf $base/${project.artifactId}/config
|
||||||
# 运行目录
|
# 运行目录
|
||||||
echo "拷贝文件:${project.artifactId}-${project.version}"
|
echo "拷贝文件:${project.artifactId}-${project.version}"
|
||||||
if [ ! -d "$base/../deploy/${project.artifactId}" ]; then
|
if [ ! -d "$base/${project.artifactId}" ]; then
|
||||||
mkdir -p $base/../deploy/${project.artifactId}
|
mkdir -p $base/${project.artifactId}
|
||||||
fi
|
fi
|
||||||
# 拷贝文件
|
# 拷贝文件
|
||||||
cp -rf ${project.basedir}/target/${project.artifactId}-${project.version}/* $base/../deploy/${project.artifactId}
|
cp -rf ${project.basedir}/target/${project.artifactId}-${project.version}/* $base/${project.artifactId}
|
||||||
|
|
||||||
# 启动服务
|
# 启动服务
|
||||||
#cd $base/../deploy/${project.artifactId}
|
#cd $base/${project.artifactId}
|
||||||
#sh bin/startup.sh
|
#sh bin/startup.sh
|
||||||
systemctl restart taoyao
|
systemctl restart taoyao
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=桃夭
|
|
||||||
After=network.target
|
|
||||||
Wants=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=root
|
|
||||||
Type=forking
|
|
||||||
KillMode=process
|
|
||||||
ExecStart=/data/taoyao/bin/startup.sh
|
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
|
||||||
ExecStop=/bin/kill -QUIT $MAINPID
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5s
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
2
pom.xml
2
pom.xml
@@ -23,9 +23,9 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<!-- 版本 -->
|
<!-- 版本 -->
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<lombok.version>1.18.24</lombok.version>
|
|
||||||
<javacv.version>1.5.8</javacv.version>
|
<javacv.version>1.5.8</javacv.version>
|
||||||
<ffmpeg.version>5.1.2</ffmpeg.version>
|
<ffmpeg.version>5.1.2</ffmpeg.version>
|
||||||
|
<lombok.version>1.18.24</lombok.version>
|
||||||
<kurento.version>6.18.0</kurento.version>
|
<kurento.version>6.18.0</kurento.version>
|
||||||
<springdoc.version>1.6.12</springdoc.version>
|
<springdoc.version>1.6.12</springdoc.version>
|
||||||
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ server:
|
|||||||
port: 8888
|
port: 8888
|
||||||
http2:
|
http2:
|
||||||
enabled: true
|
enabled: true
|
||||||
# 如果Nginx代理可以不用配置SSL提升性能
|
|
||||||
ssl:
|
ssl:
|
||||||
key-alias: taoyao
|
key-alias: taoyao
|
||||||
key-store: classpath:taoyao.jks
|
key-store: classpath:taoyao.jks
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
/** 桃夭WebRTC终端核心功能 */
|
/** 桃夭WebRTC终端核心功能 */
|
||||||
/** 配置 */
|
/** 兼容 */
|
||||||
const taoyaoConfig = {
|
const PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
|
||||||
// 当前终端SN
|
/** 默认音频配置 */
|
||||||
sn: 'taoyao',
|
|
||||||
// 信令授权
|
|
||||||
username: 'taoyao',
|
|
||||||
password: 'taoyao'
|
|
||||||
};
|
|
||||||
/** 音频配置 */
|
|
||||||
const defaultAudioConfig = {
|
const defaultAudioConfig = {
|
||||||
// 音量:0~1
|
// 音量:0~1
|
||||||
volume: 0.5,
|
volume: 0.5,
|
||||||
// 设备
|
// 设备
|
||||||
// deviceId : '',
|
// deviceId : '',
|
||||||
// 采样率:8000|16000|32000|48000
|
// 采样率:8000|16000|32000|48000
|
||||||
sampleRate: 32000,
|
sampleRate: 48000,
|
||||||
// 采样数:16
|
// 采样数:16
|
||||||
sampleSize: 16,
|
sampleSize: 16,
|
||||||
// 延迟大小(单位毫秒):500毫秒以内较好
|
// 延迟大小(单位毫秒):500毫秒以内较好
|
||||||
latency: 0.3,
|
latency: 0.4,
|
||||||
// 声道数量:1|2
|
// 声道数量:1|2
|
||||||
channelCount : 1,
|
channelCount : 1,
|
||||||
// 是否开启自动增益:true|false
|
// 是否开启自动增益:true|false
|
||||||
@@ -30,7 +24,7 @@ const defaultAudioConfig = {
|
|||||||
// 消除回音方式:system|browser
|
// 消除回音方式:system|browser
|
||||||
echoCancellationType: 'system'
|
echoCancellationType: 'system'
|
||||||
};
|
};
|
||||||
/** 视频配置 */
|
/** 默认视频配置 */
|
||||||
const defaultVideoConfig = {
|
const defaultVideoConfig = {
|
||||||
// 宽度
|
// 宽度
|
||||||
width: 1280,
|
width: 1280,
|
||||||
@@ -45,9 +39,244 @@ const defaultVideoConfig = {
|
|||||||
// 选摄像头:user|left|right|environment
|
// 选摄像头:user|left|right|environment
|
||||||
facingMode: 'environment'
|
facingMode: 'environment'
|
||||||
}
|
}
|
||||||
/** 兼容 */
|
/** 信令配置 */
|
||||||
const XMLHttpRequest = window.XMLHttpRequest;
|
const signalConfig = {
|
||||||
const PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
|
/** 当前终端SN */
|
||||||
|
sn: 'taoyao',
|
||||||
|
/** 当前版本 */
|
||||||
|
version: '1.0.0',
|
||||||
|
// 信令授权
|
||||||
|
username: 'taoyao',
|
||||||
|
password: 'taoyao'
|
||||||
|
};
|
||||||
|
/** 信令协议 */
|
||||||
|
const signalProtocol = {
|
||||||
|
/** 直播信令 */
|
||||||
|
live: {
|
||||||
|
},
|
||||||
|
/** 媒体信令 */
|
||||||
|
media: {
|
||||||
|
},
|
||||||
|
/** 终端信令 */
|
||||||
|
client: {
|
||||||
|
/** 注册 */
|
||||||
|
register: 2000,
|
||||||
|
/** 下发配置 */
|
||||||
|
config: 2004,
|
||||||
|
/** 心跳 */
|
||||||
|
heartbeat: 2005,
|
||||||
|
},
|
||||||
|
/** 会议信令 */
|
||||||
|
meeting: {
|
||||||
|
},
|
||||||
|
/** 平台信令 */
|
||||||
|
platform: {
|
||||||
|
},
|
||||||
|
/** 当前索引 */
|
||||||
|
index: 100000,
|
||||||
|
/** 最小索引 */
|
||||||
|
minIndex: 100000,
|
||||||
|
/** 最大索引 */
|
||||||
|
maxIndex: 999999,
|
||||||
|
/** 生成索引 */
|
||||||
|
buildId: function() {
|
||||||
|
if(this.index++ >= this.maxIndex) {
|
||||||
|
this.index = this.minIndex;
|
||||||
|
}
|
||||||
|
return Date.now() + '' + this.index;
|
||||||
|
},
|
||||||
|
/** 生成信令消息 */
|
||||||
|
buildProtocol: function(sn, pid, body, id) {
|
||||||
|
let message = {
|
||||||
|
header: {
|
||||||
|
v: signalConfig.version,
|
||||||
|
id: id || this.buildId(),
|
||||||
|
sn: sn,
|
||||||
|
pid: pid,
|
||||||
|
},
|
||||||
|
'body': body
|
||||||
|
};
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 信令通道 */
|
||||||
|
const signalChannel = {
|
||||||
|
/** 桃夭 */
|
||||||
|
taoyao: null,
|
||||||
|
/** 通道 */
|
||||||
|
channel: null,
|
||||||
|
/** 地址 */
|
||||||
|
address: null,
|
||||||
|
/** 回调 */
|
||||||
|
callback: null,
|
||||||
|
/** 回调事件 */
|
||||||
|
callbackMapping: new Map(),
|
||||||
|
/** 心跳时间 */
|
||||||
|
heartbeatTime: 30 * 1000,
|
||||||
|
/** 心跳定时器 */
|
||||||
|
heartbeatTimer: null,
|
||||||
|
/** 重连定时器 */
|
||||||
|
reconnectTimer: null,
|
||||||
|
/** 防止重复重连 */
|
||||||
|
lockReconnect: false,
|
||||||
|
/** 当前重连时间 */
|
||||||
|
connectionTimeout: 5 * 1000,
|
||||||
|
/** 最小重连时间 */
|
||||||
|
minReconnectionDelay: 5 * 1000,
|
||||||
|
/** 最大重连时间 */
|
||||||
|
maxReconnectionDelay: 60 * 1000,
|
||||||
|
/** 重连失败时间增长倍数 */
|
||||||
|
reconnectionDelayGrowFactor: 2,
|
||||||
|
/** 心跳 */
|
||||||
|
heartbeat: function() {
|
||||||
|
let self = this;
|
||||||
|
if(self.heartbeatTimer) {
|
||||||
|
clearTimeout(self.heartbeatTimer);
|
||||||
|
}
|
||||||
|
self.heartbeatTimer = setTimeout(function() {
|
||||||
|
if (self.channel && self.channel.readyState == WebSocket.OPEN) {
|
||||||
|
self.push(signalProtocol.buildProtocol(
|
||||||
|
signalConfig.sn,
|
||||||
|
signalProtocol.client.heartbeat,
|
||||||
|
{
|
||||||
|
signal: 100,
|
||||||
|
battery: 100
|
||||||
|
}
|
||||||
|
));
|
||||||
|
self.heartbeat();
|
||||||
|
} else {
|
||||||
|
console.warn('发送心跳失败', self.channel);
|
||||||
|
}
|
||||||
|
}, self.heartbeatTime);
|
||||||
|
},
|
||||||
|
/** 连接 */
|
||||||
|
connect: function(address, callback, reconnection = true) {
|
||||||
|
let self = this;
|
||||||
|
self.address = address;
|
||||||
|
self.callback = callback;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.debug('连接信令通道', address);
|
||||||
|
self.channel = new WebSocket(address);
|
||||||
|
self.channel.onopen = function(e) {
|
||||||
|
console.debug('打开信令通道', e);
|
||||||
|
// 注册终端
|
||||||
|
self.push(signalProtocol.buildProtocol(
|
||||||
|
signalConfig.sn,
|
||||||
|
signalProtocol.client.register,
|
||||||
|
{
|
||||||
|
ip: null,
|
||||||
|
mac: null,
|
||||||
|
signal: 100,
|
||||||
|
battery: 100,
|
||||||
|
username: signalConfig.username,
|
||||||
|
password: signalConfig.password
|
||||||
|
}
|
||||||
|
));
|
||||||
|
// 重置时间
|
||||||
|
self.connectionTimeout = self.minReconnectionDelay
|
||||||
|
// 开始心跳
|
||||||
|
self.heartbeat();
|
||||||
|
// 成功回调
|
||||||
|
resolve(e);
|
||||||
|
};
|
||||||
|
self.channel.onclose = function(e) {
|
||||||
|
console.error('信令通道关闭', self.channel, e);
|
||||||
|
if(reconnection) {
|
||||||
|
self.reconnect();
|
||||||
|
}
|
||||||
|
reject(e);
|
||||||
|
};
|
||||||
|
self.channel.onerror = function(e) {
|
||||||
|
console.error('信令通道异常', self.channel, e);
|
||||||
|
if(reconnection) {
|
||||||
|
self.reconnect();
|
||||||
|
}
|
||||||
|
reject(e);
|
||||||
|
};
|
||||||
|
self.channel.onmessage = function(e) {
|
||||||
|
console.debug('信令通道消息', e.data);
|
||||||
|
let done = false;
|
||||||
|
let data = JSON.parse(e.data);
|
||||||
|
// 注册回调
|
||||||
|
if(self.callback) {
|
||||||
|
done = self.callback(data);
|
||||||
|
}
|
||||||
|
// 默认回调
|
||||||
|
if(!done) {
|
||||||
|
self.defaultCallback(data);
|
||||||
|
}
|
||||||
|
// 请求回调
|
||||||
|
if(self.callbackMapping.has(data.header.id)) {
|
||||||
|
self.callbackMapping.get(data.header.id)();
|
||||||
|
self.callbackMapping.delete(data.header.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 重连 */
|
||||||
|
reconnect: function() {
|
||||||
|
let self = this;
|
||||||
|
if (self.lockReconnect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.lockReconnect = true;
|
||||||
|
// 关闭旧的通道
|
||||||
|
if(self.channel && self.channel.readyState == WebSocket.OPEN) {
|
||||||
|
self.channel.close();
|
||||||
|
self.channel = null;
|
||||||
|
}
|
||||||
|
if(self.reconnectTimer) {
|
||||||
|
clearTimeout(self.reconnectTimer);
|
||||||
|
}
|
||||||
|
// 打开定时重连
|
||||||
|
self.reconnectTimer = setTimeout(function() {
|
||||||
|
console.info('信令通道重连', self.address, new Date());
|
||||||
|
self.connect(self.address, self.callback, true);
|
||||||
|
self.lockReconnect = false;
|
||||||
|
}, self.connectionTimeout);
|
||||||
|
if (self.connectionTimeout >= self.maxReconnectionDelay) {
|
||||||
|
self.connectionTimeout = self.maxReconnectionDelay;
|
||||||
|
} else {
|
||||||
|
self.connectionTimeout = self.connectionTimeout * self.reconnectionDelayGrowFactor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 发送消息 */
|
||||||
|
push: function(data, callback) {
|
||||||
|
// 注册回调
|
||||||
|
if(data && callback) {
|
||||||
|
this.callbackMapping.set(data.header.id, callback);
|
||||||
|
}
|
||||||
|
// 发送消息
|
||||||
|
if(data && data.header) {
|
||||||
|
this.channel.send(JSON.stringify(data));
|
||||||
|
} else {
|
||||||
|
this.channel.send(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 关闭通道 */
|
||||||
|
close: function() {
|
||||||
|
clearTimeout(this.heartbeatTimer);
|
||||||
|
},
|
||||||
|
/** 默认回调 */
|
||||||
|
defaultCallback: function(data) {
|
||||||
|
console.debug('没有适配信令消息默认处理', data);
|
||||||
|
switch(data.header.pid) {
|
||||||
|
case signalProtocol.client.register:
|
||||||
|
console.debug('终端注册成功');
|
||||||
|
break;
|
||||||
|
case signalProtocol.client.config:
|
||||||
|
if(this.taoyao) {
|
||||||
|
this.taoyao
|
||||||
|
.configMedia(data.body.media)
|
||||||
|
.configWebrtc(data.body.webrtc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case signalProtocol.client.heartbeat:
|
||||||
|
console.debug('心跳');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
/** 桃夭 */
|
/** 桃夭 */
|
||||||
function Taoyao(
|
function Taoyao(
|
||||||
webSocket,
|
webSocket,
|
||||||
@@ -55,7 +284,9 @@ function Taoyao(
|
|||||||
audioConfig,
|
audioConfig,
|
||||||
videoConfig
|
videoConfig
|
||||||
) {
|
) {
|
||||||
|
/** WebSocket地址 */
|
||||||
this.webSocket = webSocket;
|
this.webSocket = webSocket;
|
||||||
|
/** IceServer地址 */
|
||||||
this.iceServer = iceServer;
|
this.iceServer = iceServer;
|
||||||
/** 媒体状态 */
|
/** 媒体状态 */
|
||||||
this.audioStatus = true;
|
this.audioStatus = true;
|
||||||
@@ -87,12 +318,16 @@ function Taoyao(
|
|||||||
let videoDevice = false;
|
let videoDevice = false;
|
||||||
list.forEach(v => {
|
list.forEach(v => {
|
||||||
console.debug('终端媒体设备', v.kind, v.label);
|
console.debug('终端媒体设备', v.kind, v.label);
|
||||||
if(v.kind === 'audioinput') {
|
switch(v.kind) {
|
||||||
|
case 'audioinput':
|
||||||
audioDevice = true;
|
audioDevice = true;
|
||||||
} else if(v.kind === 'videoinput') {
|
break;
|
||||||
|
case 'videoinput':
|
||||||
videoDevice = true;
|
videoDevice = true;
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
console.debug('没有适配设备', v.kind, v.label);
|
console.debug('没有适配设备', v.kind, v.label);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(!audioDevice) {
|
if(!audioDevice) {
|
||||||
@@ -105,76 +340,41 @@ function Taoyao(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error('获取终端设备失败', e);
|
console.error('检查终端设备异常', e);
|
||||||
self.videoEnabled = false;
|
self.videoEnabled = false;
|
||||||
self.videoEnabled = false;
|
self.videoEnabled = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
/** 请求 */
|
|
||||||
this.request = function(url, data = {}, method = 'GET', async = true, timeout = 5000, mime = 'json') {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let xhr = new XMLHttpRequest();
|
|
||||||
xhr.open(method, url, async);
|
|
||||||
if(async) {
|
|
||||||
xhr.timeout = timeout;
|
|
||||||
xhr.responseType = mime;
|
|
||||||
xhr.send(data);
|
|
||||||
xhr.onload = function() {
|
|
||||||
let response = xhr.response;
|
|
||||||
if(xhr.readyState === 4 && xhr.status === 200) {
|
|
||||||
if(response.code === '0000') {
|
|
||||||
resolve(response.body);
|
|
||||||
} else {
|
|
||||||
reject(response.body || response);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject(response.body || response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xhr.onerror = reject;
|
|
||||||
} else {
|
|
||||||
xhr.send(data);
|
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
response = JSON.parse(xhr.response);
|
|
||||||
} catch(e) {
|
|
||||||
console.error('响应解析失败', xhr);
|
|
||||||
response = xhr.response;
|
|
||||||
}
|
|
||||||
if(xhr.readyState === 4 && xhr.status === 200) {
|
|
||||||
resolve(response.body || response);
|
|
||||||
} else {
|
|
||||||
reject(response.body || response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/** 媒体配置 */
|
/** 媒体配置 */
|
||||||
this.configMedia = function(audio = {}, video = {}) {
|
this.configMedia = function(audio = {}, video = {}) {
|
||||||
this.audioConfig = {...this.audioConfig, ...audio};
|
this.audioConfig = {...this.audioConfig, ...audio};
|
||||||
this.videoCofnig = {...this.videoCofnig, ...video};
|
this.videoCofnig = {...this.videoCofnig, ...video};
|
||||||
console.debug('终端媒体配置', this.audioConfig, this.videoConfig);
|
console.debug('终端媒体配置', this.audioConfig, this.videoConfig);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
/** WebRTC配置 */
|
/** WebRTC配置 */
|
||||||
this.configWebrtc = function(config = {}) {
|
this.configWebrtc = function(config = {}) {
|
||||||
this.webSocket = config.signalAddress;
|
this.webSocket = config.signalAddress;
|
||||||
this.iceServer = config.stun;
|
this.iceServer = config.stun;
|
||||||
console.debug('WebRTC配置', this.webSocket, this.iceServer);
|
console.debug('WebRTC配置', this.webSocket, this.iceServer);
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
/** 信令通道 */
|
/** 打开信令通道 */
|
||||||
this.buildChannel = function(callback) {
|
this.buildChannel = function(callback) {
|
||||||
|
signalChannel.taoyao = this;
|
||||||
this.signalChannel = signalChannel;
|
this.signalChannel = signalChannel;
|
||||||
this.signalChannel.connect(this.webSocket, callback);
|
this.signalChannel.connect(this.webSocket, callback);
|
||||||
// 不能直接this.push = this.signalChannel.push这样导致this对象错误
|
// 不能直接this.push = this.signalChannel.push这样导致this对象错误
|
||||||
this.push = function(data, callback) {
|
this.push = function(data, callback) {
|
||||||
this.signalChannel.push(data, callback)
|
this.signalChannel.push(data, callback)
|
||||||
};
|
};
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
/** 本地媒体 */
|
/** 打开本地媒体 */
|
||||||
this.buildLocalMedia = function() {
|
this.buildLocalMedia = function() {
|
||||||
console.debug("获取终端媒体:", this.audioConfig, this.videoConfig);
|
console.debug('打开终端媒体', this.audioConfig, this.videoConfig);
|
||||||
let self = this;
|
let self = this;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||||
@@ -190,11 +390,11 @@ function Taoyao(
|
|||||||
video: self.videoConfig
|
video: self.videoConfig
|
||||||
}, resolve, reject);
|
}, resolve, reject);
|
||||||
} else {
|
} else {
|
||||||
reject("获取终端媒体失败");
|
reject('打开本地媒体失败');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 本地媒体 */
|
/** 设置本地媒体 */
|
||||||
this.localMedia = async function(localVideoId, stream) {
|
this.localMedia = async function(localVideoId, stream) {
|
||||||
this.localVideo = document.getElementById(localVideoId);
|
this.localVideo = document.getElementById(localVideoId);
|
||||||
if ('srcObject' in this.localVideo) {
|
if ('srcObject' in this.localVideo) {
|
||||||
@@ -215,195 +415,6 @@ function Taoyao(
|
|||||||
/** 媒体 */
|
/** 媒体 */
|
||||||
/** 视频 */
|
/** 视频 */
|
||||||
};
|
};
|
||||||
/** 信令协议 */
|
|
||||||
const protocol = {
|
|
||||||
pid: {
|
|
||||||
/** 心跳 */
|
|
||||||
heartbeat: 2005,
|
|
||||||
/** 注册 */
|
|
||||||
register: 2000
|
|
||||||
},
|
|
||||||
/** 当前索引 */
|
|
||||||
index: 100000,
|
|
||||||
/** 最小索引 */
|
|
||||||
minIndex: 100000,
|
|
||||||
/** 最大索引 */
|
|
||||||
maxIndex: 999999,
|
|
||||||
/** 生成ID */
|
|
||||||
buildId: function() {
|
|
||||||
if(this.index++ >= this.maxIndex) {
|
|
||||||
this.index = this.minIndex;
|
|
||||||
}
|
|
||||||
return Date.now() + '' + this.index;
|
|
||||||
},
|
|
||||||
/** 生成协议 */
|
|
||||||
buildProtocol: function(sn, pid, body) {
|
|
||||||
let message = {
|
|
||||||
header: {
|
|
||||||
v: '1.0.0',
|
|
||||||
id: this.buildId(),
|
|
||||||
sn: sn,
|
|
||||||
pid: pid,
|
|
||||||
},
|
|
||||||
"body": body
|
|
||||||
};
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/** 信令消息 */
|
|
||||||
/** 信令通道 */
|
|
||||||
const signalChannel = {
|
|
||||||
/** 通道 */
|
|
||||||
channel: null,
|
|
||||||
/** 地址 */
|
|
||||||
address: null,
|
|
||||||
/** 回调 */
|
|
||||||
callback: null,
|
|
||||||
/** 回调事件 */
|
|
||||||
callbackMapping: new Map(),
|
|
||||||
/** 心跳时间 */
|
|
||||||
heartbeatTime: 30 * 1000,
|
|
||||||
/** 心跳定时器 */
|
|
||||||
heartbeatTimer: null,
|
|
||||||
/** 防止重连 */
|
|
||||||
lockReconnect: false,
|
|
||||||
/** 重连时间 */
|
|
||||||
connectionTimeout: 5 * 1000,
|
|
||||||
/** 最小重连时间 */
|
|
||||||
minReconnectionDelay: 5 * 1000,
|
|
||||||
/** 最大重连时间 */
|
|
||||||
maxReconnectionDelay: 60 * 1000,
|
|
||||||
/** 自动重连失败后重连时间增长倍数 */
|
|
||||||
reconnectionDelayGrowFactor: 2,
|
|
||||||
/** 关闭 */
|
|
||||||
close: function() {
|
|
||||||
clearTimeout(this.heartbeatTimer);
|
|
||||||
},
|
|
||||||
/** 心跳 */
|
|
||||||
heartbeat: function() {
|
|
||||||
let self = this;
|
|
||||||
self.heartbeatTimer = setTimeout(function() {
|
|
||||||
if (self.channel && self.channel.readyState == WebSocket.OPEN) {
|
|
||||||
self.push(protocol.buildProtocol(
|
|
||||||
taoyaoConfig.sn,
|
|
||||||
protocol.pid.heartbeat,
|
|
||||||
{
|
|
||||||
signal: 100,
|
|
||||||
battery: 100
|
|
||||||
}
|
|
||||||
));
|
|
||||||
self.heartbeat();
|
|
||||||
} else {
|
|
||||||
console.warn('发送心跳失败', self.channel);
|
|
||||||
}
|
|
||||||
}, self.heartbeatTime);
|
|
||||||
},
|
|
||||||
/** 重连 */
|
|
||||||
reconnect: function() {
|
|
||||||
let self = this;
|
|
||||||
if (self.lockReconnect) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.lockReconnect = true;
|
|
||||||
// 关闭旧的通道
|
|
||||||
if(self.channel && self.channel.readyState == WebSocket.OPEN) {
|
|
||||||
self.channel.close();
|
|
||||||
self.channel = null;
|
|
||||||
}
|
|
||||||
// 打开定时重连
|
|
||||||
setTimeout(function() {
|
|
||||||
console.info('信令通道重连', self.address);
|
|
||||||
self.connect(self.address, self.callback, true);
|
|
||||||
self.lockReconnect = false;
|
|
||||||
}, self.connectionTimeout);
|
|
||||||
if (self.connectionTimeout >= self.maxReconnectionDelay) {
|
|
||||||
self.connectionTimeout = self.maxReconnectionDelay;
|
|
||||||
} else {
|
|
||||||
self.connectionTimeout = self.connectionTimeout * self.reconnectionDelayGrowFactor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/** 连接 */
|
|
||||||
connect: function(address, callback, reconnection = true) {
|
|
||||||
let self = this;
|
|
||||||
this.address = address;
|
|
||||||
this.callback = callback;
|
|
||||||
console.debug("连接信令通道", address);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
self.channel = new WebSocket(address);
|
|
||||||
self.channel.onopen = function(e) {
|
|
||||||
console.debug('信令通道打开', e);
|
|
||||||
self.push(protocol.buildProtocol(
|
|
||||||
taoyaoConfig.sn,
|
|
||||||
protocol.pid.register,
|
|
||||||
{
|
|
||||||
ip: null,
|
|
||||||
mac: null,
|
|
||||||
signal: 100,
|
|
||||||
battery: 100,
|
|
||||||
username: taoyaoConfig.username,
|
|
||||||
password: taoyaoConfig.password
|
|
||||||
}
|
|
||||||
));
|
|
||||||
self.connectionTimeout = self.minReconnectionDelay
|
|
||||||
self.heartbeat();
|
|
||||||
resolve(e);
|
|
||||||
};
|
|
||||||
self.channel.onclose = function(e) {
|
|
||||||
console.error('信令通道关闭', self.channel, e);
|
|
||||||
if(reconnection) {
|
|
||||||
self.reconnect();
|
|
||||||
}
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
self.channel.onerror = function(e) {
|
|
||||||
console.error('信令通道异常', self.channel, e);
|
|
||||||
if(reconnection) {
|
|
||||||
self.reconnect();
|
|
||||||
}
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
self.channel.onmessage = function(e) {
|
|
||||||
console.debug('信令消息', e.data);
|
|
||||||
let data = JSON.parse(e.data);
|
|
||||||
// 注册回调
|
|
||||||
let done = false;
|
|
||||||
if(callback) {
|
|
||||||
done = callback(data);
|
|
||||||
}
|
|
||||||
// 请求回调
|
|
||||||
if(self.callbackMapping.has(data.header.id)) {
|
|
||||||
self.callbackMapping.get(data.header.id)();
|
|
||||||
self.callbackMapping.delete(data.header.id);
|
|
||||||
}
|
|
||||||
// 默认回调
|
|
||||||
done || this.defaultCallback(data);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/** 信令消息 */
|
|
||||||
push: function(data, callback) {
|
|
||||||
// 注册回调
|
|
||||||
if(data && callback) {
|
|
||||||
this.callbackMapping.set(data.header.id, callback);
|
|
||||||
}
|
|
||||||
// 发送请求
|
|
||||||
if(data && data.header) {
|
|
||||||
this.channel.send(JSON.stringify(data));
|
|
||||||
} else {
|
|
||||||
this.channel.send(data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/** 默认回调 */
|
|
||||||
defaultCallback: function(data) {
|
|
||||||
console.debug('没有适配信令消息默认处理', data);
|
|
||||||
switch(data.header.pid) {
|
|
||||||
case protocol.pid.heartbeat:
|
|
||||||
break;
|
|
||||||
case protocol.pid.register:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/*
|
/*
|
||||||
var peer;
|
var peer;
|
||||||
var socket; // WebSocket
|
var socket; // WebSocket
|
||||||
|
|||||||
@@ -50,31 +50,20 @@
|
|||||||
child.innerHTML = template;
|
child.innerHTML = template;
|
||||||
list.appendChild(child);
|
list.appendChild(child);
|
||||||
}
|
}
|
||||||
const taoyao = new Taoyao();
|
const taoyao = new Taoyao("wss://localhost:8888/websocket.signal");
|
||||||
// 检查设备
|
// 检查设备
|
||||||
taoyao.checkDevice();
|
taoyao
|
||||||
// 配置媒体
|
.checkDevice()
|
||||||
taoyao.request('/config/media', {}, 'GET', false)
|
.buildChannel(callback)
|
||||||
.then(response => {
|
//.buildLocalMedia()
|
||||||
taoyao.configMedia(response.audio, response.video);
|
//.then(stream => taoyao.localMedia('local', stream))
|
||||||
})
|
//.catch((e) => alert('获取终端媒体失败:' + e));
|
||||||
.catch(e => console.error('获取媒体配置失败', e));
|
|
||||||
// 配置WebRTC
|
|
||||||
taoyao.request('/config/webrtc', {}, 'GET', false)
|
|
||||||
.then(response => {
|
|
||||||
taoyao.configWebrtc(response);
|
|
||||||
taoyao.buildChannel(callback);
|
|
||||||
})
|
|
||||||
.catch(e => console.error('获取WebRTC配置失败', e));
|
|
||||||
// 信令回调
|
// 信令回调
|
||||||
function callback(data) {
|
function callback(data) {
|
||||||
switch(data.header.pid) {
|
switch(data.header.pid) {
|
||||||
case protocol.pid.heartbeat:
|
case signalProtocol.client.heartbeat:
|
||||||
// 心跳
|
// 心跳
|
||||||
return true;
|
return true;
|
||||||
case protocol.pid.register:
|
|
||||||
// 注册
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -92,19 +81,13 @@
|
|||||||
}
|
}
|
||||||
// 录制视频
|
// 录制视频
|
||||||
function record(e) {
|
function record(e) {
|
||||||
taoyao.push(protocol.buildProtocol(taoyaoConfig.sn, protocol.pid.heartbeat), () => {
|
taoyao.push(signalProtocol.buildProtocol(signalConfig.sn, signalProtocol.client.heartbeat), () => {
|
||||||
classSwitch(e, 'active');
|
classSwitch(e, 'active');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 踢出会议
|
// 踢出会议
|
||||||
function kick() {
|
function kick() {
|
||||||
}
|
}
|
||||||
// 信令通道
|
|
||||||
/*
|
|
||||||
taoyao.buildLocalMedia()
|
|
||||||
.then(stream => taoyao.localMedia('local', stream))
|
|
||||||
.catch((e) => alert('获取终端媒体失败:' + e));
|
|
||||||
*/
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -48,6 +48,17 @@
|
|||||||
|
|
||||||
## 终端信令(2000~2999)
|
## 终端信令(2000~2999)
|
||||||
|
|
||||||
|
```
|
||||||
|
# 终端信息
|
||||||
|
{
|
||||||
|
"sn": "终端标识",
|
||||||
|
"ip": "IP地址",
|
||||||
|
"mac": "MAC地址",
|
||||||
|
"signal": "信号强度",
|
||||||
|
"battery": "电池电量"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### 注册信令(2000)
|
### 注册信令(2000)
|
||||||
|
|
||||||
终端->服务端:注册成功后服务端响应,同时下发配置信息,广播终端上线事件。
|
终端->服务端:注册成功后服务端响应,同时下发配置信息,广播终端上线事件。
|
||||||
|
|||||||
Reference in New Issue
Block a user