mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-12-18 21:29:09 +08:00
Compare commits
8 Commits
70ae02549f
...
v1.1.13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58c24b798e | ||
|
|
5cc31e5ba3 | ||
|
|
74fe9bebf5 | ||
|
|
1f6a2182be | ||
|
|
1a883f0d6c | ||
|
|
a560b4ca70 | ||
|
|
46f45ed216 | ||
|
|
5c23f1c5e8 |
149
README.md
149
README.md
@@ -179,145 +179,42 @@ sudo docker run -d \
|
|||||||
-e COTURN_PORT=xxxx \
|
-e COTURN_PORT=xxxx \
|
||||||
-e MIN_PORT=xxxxx \
|
-e MIN_PORT=xxxxx \
|
||||||
-e MAX_PORT=xxxxx \
|
-e MAX_PORT=xxxxx \
|
||||||
-v /path/to/your/certs:/crossdesk-server/certs \
|
-v /var/lib/crossdesk:/var/lib/crossdesk \
|
||||||
-v /path/to/your/db:/crossdesk-server/db \
|
-v /var/log/crossdesk:/var/log/crossdesk \
|
||||||
-v /path/to/your/logs:/crossdesk-server/logs \
|
crossdesk/crossdesk-server:v1.1.2
|
||||||
crossdesk/crossdesk-server:v1.1.1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
上述命令中,用户需注意的参数如下:
|
上述命令中,用户需注意的参数如下:
|
||||||
|
|
||||||
|
**参数**
|
||||||
- EXTERNAL_IP:服务器公网 IP , 对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器地址**
|
- EXTERNAL_IP:服务器公网 IP , 对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器地址**
|
||||||
|
|
||||||
- INTERNAL_IP:服务器内网 IP
|
- INTERNAL_IP:服务器内网 IP
|
||||||
|
|
||||||
- CROSSDESK_SERVER_PORT:自托管服务使用的端口,对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口**
|
- CROSSDESK_SERVER_PORT:自托管服务使用的端口,对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口**
|
||||||
|
|
||||||
- COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口**
|
- COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口**
|
||||||
|
|
||||||
- MIN_PORT/MAX_PORT:COTURN 服务使用的端口范围,例如:MIN_PORT=50000, MAX_PORT=60000,范围可根据客户端数量调整。
|
- MIN_PORT/MAX_PORT:COTURN 服务使用的端口范围,例如:MIN_PORT=50000, MAX_PORT=60000,范围可根据客户端数量调整。
|
||||||
|
- `-v /var/lib/crossdesk:/var/lib/crossdesk`:持久化数据库和证书文件到宿主机
|
||||||
- /path/to/your/certs:证书文件目录
|
- `-v /var/log/crossdesk:/var/log/crossdesk`:持久化日志文件到宿主机
|
||||||
|
-
|
||||||
- /path/to/your/db:CrossDesk Server 设备管理数据库
|
|
||||||
|
|
||||||
- /path/to/your/logs:日志目录
|
|
||||||
|
|
||||||
**注意**:
|
**注意**:
|
||||||
- **/path/to/your/ 是示例路径,请替换为你自己的实际路径。挂载的目录必须事先创建好,否则容器会报错。**
|
|
||||||
- **服务器需开放端口:3478/udp,3478/tcp,MIN_PORT-MAX_PORT/udp,CROSSDESK_SERVER_PORT/tcp。**
|
- **服务器需开放端口:3478/udp,3478/tcp,MIN_PORT-MAX_PORT/udp,CROSSDESK_SERVER_PORT/tcp。**
|
||||||
|
- 如果不挂载 volume,容器删除后数据会丢失
|
||||||
|
- 证书文件会在首次启动时自动生成并持久化到宿主机的 `/var/lib/crossdesk/certs` 路径下
|
||||||
|
- 数据库文件会自动创建并持久化到宿主机的 `/var/lib/crossdesk/db/crossdesk-server.db` 路径下
|
||||||
|
- 日志文件会自动创建并持久化到宿主机的 `/var/log/crossdesk/` 路径下
|
||||||
|
|
||||||
|
**权限注意**:如果 Docker 自动创建的目录权限不足(属于 root),容器内用户无法写入,会导致:
|
||||||
|
- 证书生成失败,容器启动脚本会报错退出
|
||||||
|
- 数据库目录创建失败,程序会抛出异常并崩溃
|
||||||
|
- 日志目录创建失败,日志文件无法写入(但程序可能继续运行)
|
||||||
|
|
||||||
|
**解决方案**:在启动容器前手动设置权限:
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
|
||||||
|
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
|
||||||
|
```
|
||||||
|
|
||||||
## 证书文件
|
## 证书文件
|
||||||
客户端需加载根证书文件,服务端需加载服务器私钥和服务器证书文件。
|
在宿主机的 `/var/lib/crossdesk/certs` 路径下可找到证书文件 `crossdesk.cn_root.crt`,下载到你的客户端主机,并在客户端的**自托管服务器设置**中选择相应的**证书文件路径**。
|
||||||
|
|
||||||
如果已有SSL证书的用户,可以忽略下面的证书生成步骤。
|
|
||||||
|
|
||||||
对于无证书的用户,可使用下面的脚本自行生成证书文件:
|
|
||||||
```
|
|
||||||
# 创建证书生成脚本
|
|
||||||
vim generate_certs.sh
|
|
||||||
```
|
|
||||||
拷贝到脚本中
|
|
||||||
```
|
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# 检查参数
|
|
||||||
if [ "$#" -ne 1 ]; then
|
|
||||||
echo "Usage: $0 <SERVER_IP>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SERVER_IP="$1"
|
|
||||||
|
|
||||||
# 文件名
|
|
||||||
ROOT_KEY="crossdesk.cn_root.key"
|
|
||||||
ROOT_CERT="crossdesk.cn_root.crt"
|
|
||||||
SERVER_KEY="crossdesk.cn.key"
|
|
||||||
SERVER_CSR="crossdesk.cn.csr"
|
|
||||||
SERVER_CERT="crossdesk.cn_bundle.crt"
|
|
||||||
FULLCHAIN_CERT="crossdesk.cn_fullchain.crt"
|
|
||||||
|
|
||||||
# 证书主题
|
|
||||||
SUBJ="/C=CN/ST=Zhejiang/L=Hangzhou/O=CrossDesk/OU=CrossDesk/CN=$SERVER_IP"
|
|
||||||
|
|
||||||
# 1. 生成根证书
|
|
||||||
echo "Generating root private key..."
|
|
||||||
openssl genrsa -out "$ROOT_KEY" 4096
|
|
||||||
|
|
||||||
echo "Generating self-signed root certificate..."
|
|
||||||
openssl req -x509 -new -nodes -key "$ROOT_KEY" -sha256 -days 3650 -out "$ROOT_CERT" -subj "$SUBJ"
|
|
||||||
|
|
||||||
# 2. 生成服务器私钥
|
|
||||||
echo "Generating server private key..."
|
|
||||||
openssl genrsa -out "$SERVER_KEY" 2048
|
|
||||||
|
|
||||||
# 3. 生成服务器 CSR
|
|
||||||
echo "Generating server CSR..."
|
|
||||||
openssl req -new -key "$SERVER_KEY" -out "$SERVER_CSR" -subj "$SUBJ"
|
|
||||||
|
|
||||||
# 4. 生成临时 OpenSSL 配置文件,加入 SAN
|
|
||||||
SAN_CONF="san.cnf"
|
|
||||||
cat > $SAN_CONF <<EOL
|
|
||||||
[ req ]
|
|
||||||
default_bits = 2048
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
req_extensions = req_ext
|
|
||||||
prompt = no
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
C = CN
|
|
||||||
ST = Zhejiang
|
|
||||||
L = Hangzhou
|
|
||||||
O = CrossDesk
|
|
||||||
OU = CrossDesk
|
|
||||||
CN = $SERVER_IP
|
|
||||||
|
|
||||||
[ req_ext ]
|
|
||||||
subjectAltName = IP:$SERVER_IP
|
|
||||||
EOL
|
|
||||||
|
|
||||||
# 5. 用根证书签发服务器证书(包含 SAN)
|
|
||||||
echo "Signing server certificate with root certificate..."
|
|
||||||
openssl x509 -req -in "$SERVER_CSR" -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial \
|
|
||||||
-out "$SERVER_CERT" -days 3650 -sha256 -extfile "$SAN_CONF" -extensions req_ext
|
|
||||||
|
|
||||||
# 6. 生成完整链证书
|
|
||||||
cat "$SERVER_CERT" "$ROOT_CERT" > "$FULLCHAIN_CERT"
|
|
||||||
|
|
||||||
# 7. 清理中间文件
|
|
||||||
rm -f "$ROOT_CERT.srl" "$SAN_CONF" "$ROOT_KEY" "$SERVER_CSR" "FULLCHAIN_CERT"
|
|
||||||
|
|
||||||
echo "Generation complete. Deployment files:"
|
|
||||||
echo " Client root certificate: $ROOT_CERT"
|
|
||||||
echo " Server private key: $SERVER_KEY"
|
|
||||||
echo " Server certificate: $SERVER_CERT"
|
|
||||||
```
|
|
||||||
执行
|
|
||||||
```
|
|
||||||
chmod +x generate_certs.sh
|
|
||||||
./generate_certs.sh 服务器公网IP
|
|
||||||
|
|
||||||
# 例如 ./generate_certs.sh 111.111.111.111
|
|
||||||
```
|
|
||||||
输出如下:
|
|
||||||
```
|
|
||||||
Generating root private key...
|
|
||||||
Generating self-signed root certificate...
|
|
||||||
Generating server private key...
|
|
||||||
Generating server CSR...
|
|
||||||
Signing server certificate with root certificate...
|
|
||||||
Certificate request self-signature ok
|
|
||||||
subject=C = CN, ST = Zhejiang, L = Hangzhou, O = CrossDesk, OU = CrossDesk, CN = xxx.xxx.xxx.xxx
|
|
||||||
cleaning up intermediate files...
|
|
||||||
Generation complete. Deployment files::
|
|
||||||
Client root certificate:: crossdesk.cn_root.crt
|
|
||||||
Server private key: crossdesk.cn.key
|
|
||||||
Server certificate: crossdesk.cn_bundle.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
### 服务端
|
|
||||||
将 **crossdesk.cn.key** 和 **crossdesk.cn_bundle.crt** 放置到 **/path/to/your/certs** 目录下。
|
|
||||||
|
|
||||||
### 客户端
|
### 客户端
|
||||||
1. 点击右上角设置进入设置页面。<br>
|
1. 点击右上角设置进入设置页面。<br>
|
||||||
|
|||||||
156
README_EN.md
156
README_EN.md
@@ -187,142 +187,44 @@ sudo docker run -d \
|
|||||||
-e COTURN_PORT=xxxx \
|
-e COTURN_PORT=xxxx \
|
||||||
-e MIN_PORT=xxxxx \
|
-e MIN_PORT=xxxxx \
|
||||||
-e MAX_PORT=xxxxx \
|
-e MAX_PORT=xxxxx \
|
||||||
-v /path/to/your/certs:/crossdesk-server/certs \
|
-v /var/lib/crossdesk:/var/lib/crossdesk \
|
||||||
-v /path/to/your/db:/crossdesk-server/db \
|
-v /var/log/crossdesk:/var/log/crossdesk \
|
||||||
-v /path/to/your/logs:/crossdesk-server/logs \
|
crossdesk/crossdesk-server:v1.1.2
|
||||||
crossdesk/crossdesk-server:v1.1.1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The parameters you need to pay attention to are as follows:
|
The parameters you need to pay attention to are as follows:
|
||||||
|
|
||||||
- **EXTERNAL_IP**: The server's public IP, corresponding to the **Server Address** in the CrossDesk client **Self-Hosted Server Configuration**.
|
**Parameters**
|
||||||
|
- **EXTERNAL_IP**: The server’s public IP. This corresponds to **Server Address** in the CrossDesk client’s **Self-Hosted Server Configuration**.
|
||||||
|
- **INTERNAL_IP**: The server’s internal IP.
|
||||||
|
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted service. This corresponds to **Server Port** in the CrossDesk client’s **Self-Hosted Server Configuration**.
|
||||||
|
- **COTURN_PORT**: The port used by the COTURN service. This corresponds to **Relay Service Port** in the CrossDesk client’s **Self-Hosted Server Configuration**.
|
||||||
|
- **MIN_PORT / MAX_PORT**: The port range used by the COTURN service. Example: `MIN_PORT=50000`, `MAX_PORT=60000`. Adjust the range depending on the number of clients.
|
||||||
|
- `-v /var/lib/crossdesk:/var/lib/crossdesk`: Persists database and certificate files on the host machine.
|
||||||
|
- `-v /var/log/crossdesk:/var/log/crossdesk`: Persists log files on the host machine.
|
||||||
|
|
||||||
- **INTERNAL_IP**: The server's internal IP.
|
**Notes**
|
||||||
|
- **The server must open the following ports: 3478/udp, 3478/tcp, MIN_PORT–MAX_PORT/udp, and CROSSDESK_SERVER_PORT/tcp.**
|
||||||
|
- If you don’t mount volumes, all data will be lost when the container is removed.
|
||||||
|
- Certificate files will be automatically generated on first startup and persisted to the host at `/var/lib/crossdesk/certs`.
|
||||||
|
- The database file will be automatically created and stored at `/var/lib/crossdesk/db/crossdesk-server.db`.
|
||||||
|
- Log files will be created and stored at `/var/log/crossdesk/`.
|
||||||
|
|
||||||
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted server, corresponding to the **Server Port** in the CrossDesk client **Self-Hosted Server Configuration**.
|
**Permission Notice**
|
||||||
|
If the directories automatically created by Docker belong to root and have insufficient write permissions, the container user may not be able to write to them. This can cause:
|
||||||
|
- Certificate generation failure, leading to startup script errors and container exit.
|
||||||
|
- Database directory creation failure, causing the program to throw exceptions and crash.
|
||||||
|
- Log directory creation failure, preventing logs from being written (though the program may continue running).
|
||||||
|
|
||||||
- **COTURN_PORT**: The port used by Coturn, corresponding to the **Relay Server Port** in the CrossDesk client **Self-Hosted Server Configuration**.
|
**Solution:** Manually set permissions before starting the container:
|
||||||
|
```bash
|
||||||
- **MIN_PORT** and **MAX_PORT**: The range of ports used by the self-hosted server, corresponding to the **Minimum Port** and **Maximum Port** in the CrossDesk client **Self-Hosted Server Configuration**. Example: 50000-60000. It depends on the number of devices connected to the server.
|
sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
|
||||||
|
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
|
||||||
- **/path/to/your/certs**: Directory for certificate files.
|
|
||||||
|
|
||||||
- **/path/to/your/db**: CrossDesk Server device management database.
|
|
||||||
|
|
||||||
- **/path/to/your/logs**: Log directory.
|
|
||||||
|
|
||||||
**Note**:
|
|
||||||
- **/path/to/your/ is an example path; please replace it with your actual path. The mounted directories must be created in advance, otherwise the container will fail.**
|
|
||||||
- **The server must open the following ports: 3478/udp, 3478/tcp, 30000-60000/udp, CROSSDESK_SERVER_PORT/tcp.**
|
|
||||||
|
|
||||||
## Certificate Files
|
|
||||||
The client needs to load the root certificate, and the server needs to load the server private key and server certificate.
|
|
||||||
|
|
||||||
If you already have an SSL certificate, you can skip the following certificate generation steps.
|
|
||||||
|
|
||||||
For users without a certificate, you can use the script below to generate the certificate files:
|
|
||||||
```
|
```
|
||||||
# Create certificate generation script
|
|
||||||
vim generate_certs.sh
|
|
||||||
```
|
|
||||||
Copy the following into the script:
|
|
||||||
```
|
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Check arguments
|
### Certificate Files
|
||||||
if [ "$#" -ne 1 ]; then
|
You can find the certificate file `crossdesk.cn_root.crt` at `/var/lib/crossdesk/certs` on the host machine.
|
||||||
echo "Usage: $0 <SERVER_IP>"
|
Download it to your client device and select it in the **Certificate File Path** field under the CrossDesk client’s **Self-Hosted Server Settings**.
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SERVER_IP="$1"
|
|
||||||
|
|
||||||
# Filenames
|
|
||||||
ROOT_KEY="crossdesk.cn_root.key"
|
|
||||||
ROOT_CERT="crossdesk.cn_root.crt"
|
|
||||||
SERVER_KEY="crossdesk.cn.key"
|
|
||||||
SERVER_CSR="crossdesk.cn.csr"
|
|
||||||
SERVER_CERT="crossdesk.cn_bundle.crt"
|
|
||||||
FULLCHAIN_CERT="crossdesk.cn_fullchain.crt"
|
|
||||||
|
|
||||||
# Certificate subject
|
|
||||||
SUBJ="/C=CN/ST=Zhejiang/L=Hangzhou/O=CrossDesk/OU=CrossDesk/CN=$SERVER_IP"
|
|
||||||
|
|
||||||
# 1. Generate root certificate
|
|
||||||
echo "Generating root private key..."
|
|
||||||
openssl genrsa -out "$ROOT_KEY" 4096
|
|
||||||
|
|
||||||
echo "Generating self-signed root certificate..."
|
|
||||||
openssl req -x509 -new -nodes -key "$ROOT_KEY" -sha256 -days 3650 -out "$ROOT_CERT" -subj "$SUBJ"
|
|
||||||
|
|
||||||
# 2. Generate server private key
|
|
||||||
echo "Generating server private key..."
|
|
||||||
openssl genrsa -out "$SERVER_KEY" 2048
|
|
||||||
|
|
||||||
# 3. Generate server CSR
|
|
||||||
echo "Generating server CSR..."
|
|
||||||
openssl req -new -key "$SERVER_KEY" -out "$SERVER_CSR" -subj "$SUBJ"
|
|
||||||
|
|
||||||
# 4. Create temporary OpenSSL config file with SAN
|
|
||||||
SAN_CONF="san.cnf"
|
|
||||||
cat > $SAN_CONF <<EOL
|
|
||||||
[ req ]
|
|
||||||
default_bits = 2048
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
req_extensions = req_ext
|
|
||||||
prompt = no
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
C = CN
|
|
||||||
ST = Zhejiang
|
|
||||||
L = Hangzhou
|
|
||||||
O = CrossDesk
|
|
||||||
OU = CrossDesk
|
|
||||||
CN = $SERVER_IP
|
|
||||||
|
|
||||||
[ req_ext ]
|
|
||||||
subjectAltName = IP:$SERVER_IP
|
|
||||||
EOL
|
|
||||||
|
|
||||||
# 5. Sign server certificate with root certificate (including SAN)
|
|
||||||
echo "Signing server certificate with root certificate..."
|
|
||||||
openssl x509 -req -in "$SERVER_CSR" -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial \
|
|
||||||
-out "$SERVER_CERT" -days 3650 -sha256 -extfile "$SAN_CONF" -extensions req_ext
|
|
||||||
|
|
||||||
# 6. Generate full chain certificate
|
|
||||||
cat "$SERVER_CERT" "$ROOT_CERT" > "$FULLCHAIN_CERT"
|
|
||||||
|
|
||||||
# 7. Clean up intermediate files
|
|
||||||
rm -f "$ROOT_CERT.srl" "$SAN_CONF" "$ROOT_KEY" "$SERVER_CSR" "FULLCHAIN_CERT"
|
|
||||||
|
|
||||||
echo "Generation complete. Deployment files:"
|
|
||||||
echo " Client root certificate: $ROOT_CERT"
|
|
||||||
echo " Server private key: $SERVER_KEY"
|
|
||||||
echo " Server certificate: $SERVER_CERT"
|
|
||||||
```
|
|
||||||
Execute:
|
|
||||||
```
|
|
||||||
chmod +x generate_certs.sh
|
|
||||||
./generate_certs.sh EXTERNAL_IP
|
|
||||||
|
|
||||||
# example ./generate_certs.sh 111.111.111.111
|
|
||||||
```
|
|
||||||
Expected output:
|
|
||||||
```
|
|
||||||
Generating root private key...
|
|
||||||
Generating self-signed root certificate...
|
|
||||||
Generating server private key...
|
|
||||||
Generating server CSR...
|
|
||||||
Signing server certificate with root certificate...
|
|
||||||
Certificate request self-signature ok
|
|
||||||
subject=C = CN, ST = Zhejiang, L = Hangzhou, O = CrossDesk, OU = CrossDesk, CN = xxx.xxx.xxx.xxx
|
|
||||||
cleaning up intermediate files...
|
|
||||||
Generation complete. Deployment files::
|
|
||||||
Client root certificate:: crossdesk.cn_root.crt
|
|
||||||
Server private key: crossdesk.cn.key
|
|
||||||
Server certificate: crossdesk.cn_bundle.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server Side
|
### Server Side
|
||||||
Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/your/certs** directory.
|
Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/your/certs** directory.
|
||||||
|
|||||||
@@ -41,16 +41,43 @@ int ConfigCenter::Load() {
|
|||||||
|
|
||||||
enable_turn_ = ini_.GetBoolValue(section_, "enable_turn", enable_turn_);
|
enable_turn_ = ini_.GetBoolValue(section_, "enable_turn", enable_turn_);
|
||||||
enable_srtp_ = ini_.GetBoolValue(section_, "enable_srtp", enable_srtp_);
|
enable_srtp_ = ini_.GetBoolValue(section_, "enable_srtp", enable_srtp_);
|
||||||
signal_server_host_ = ini_.GetValue(section_, "signal_server_host",
|
|
||||||
signal_server_host_.c_str());
|
|
||||||
signal_server_port_ = static_cast<int>(
|
|
||||||
ini_.GetLongValue(section_, "signal_server_port", signal_server_port_));
|
|
||||||
coturn_server_port_ = static_cast<int>(
|
|
||||||
ini_.GetLongValue(section_, "coturn_server_port", coturn_server_port_));
|
|
||||||
cert_file_path_ =
|
|
||||||
ini_.GetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
|
||||||
enable_self_hosted_ =
|
enable_self_hosted_ =
|
||||||
ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
||||||
|
|
||||||
|
const char* signal_server_host_value =
|
||||||
|
ini_.GetValue(section_, "signal_server_host", nullptr);
|
||||||
|
if (signal_server_host_value != nullptr &&
|
||||||
|
strlen(signal_server_host_value) > 0) {
|
||||||
|
signal_server_host_ = signal_server_host_value;
|
||||||
|
} else {
|
||||||
|
signal_server_host_ = "";
|
||||||
|
}
|
||||||
|
const char* signal_server_port_value =
|
||||||
|
ini_.GetValue(section_, "signal_server_port", nullptr);
|
||||||
|
if (signal_server_port_value != nullptr &&
|
||||||
|
strlen(signal_server_port_value) > 0) {
|
||||||
|
signal_server_port_ =
|
||||||
|
static_cast<int>(ini_.GetLongValue(section_, "signal_server_port", 0));
|
||||||
|
} else {
|
||||||
|
signal_server_port_ = 0;
|
||||||
|
}
|
||||||
|
const char* coturn_server_port_value =
|
||||||
|
ini_.GetValue(section_, "coturn_server_port", nullptr);
|
||||||
|
if (coturn_server_port_value != nullptr &&
|
||||||
|
strlen(coturn_server_port_value) > 0) {
|
||||||
|
coturn_server_port_ =
|
||||||
|
static_cast<int>(ini_.GetLongValue(section_, "coturn_server_port", 0));
|
||||||
|
} else {
|
||||||
|
coturn_server_port_ = 0;
|
||||||
|
}
|
||||||
|
const char* cert_file_path_value =
|
||||||
|
ini_.GetValue(section_, "cert_file_path", nullptr);
|
||||||
|
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
|
||||||
|
cert_file_path_ = cert_file_path_value;
|
||||||
|
} else {
|
||||||
|
cert_file_path_ = "";
|
||||||
|
}
|
||||||
|
|
||||||
enable_autostart_ =
|
enable_autostart_ =
|
||||||
ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_);
|
ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_);
|
||||||
enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_);
|
enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_);
|
||||||
@@ -71,11 +98,18 @@ int ConfigCenter::Save() {
|
|||||||
ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_);
|
ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_);
|
||||||
ini_.SetBoolValue(section_, "enable_turn", enable_turn_);
|
ini_.SetBoolValue(section_, "enable_turn", enable_turn_);
|
||||||
ini_.SetBoolValue(section_, "enable_srtp", enable_srtp_);
|
ini_.SetBoolValue(section_, "enable_srtp", enable_srtp_);
|
||||||
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
|
||||||
ini_.SetLongValue(section_, "signal_server_port",
|
|
||||||
static_cast<long>(signal_server_port_));
|
|
||||||
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
|
||||||
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
||||||
|
|
||||||
|
// only save when self hosted
|
||||||
|
if (enable_self_hosted_) {
|
||||||
|
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
||||||
|
ini_.SetLongValue(section_, "signal_server_port",
|
||||||
|
static_cast<long>(signal_server_port_));
|
||||||
|
ini_.SetLongValue(section_, "coturn_server_port",
|
||||||
|
static_cast<long>(coturn_server_port_));
|
||||||
|
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_);
|
ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_);
|
||||||
ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_);
|
ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_);
|
||||||
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
|
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
|
||||||
@@ -210,6 +244,43 @@ int ConfigCenter::SetCertFilePath(const std::string& cert_file_path) {
|
|||||||
int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
|
int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
|
||||||
enable_self_hosted_ = enable_self_hosted;
|
enable_self_hosted_ = enable_self_hosted;
|
||||||
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
||||||
|
|
||||||
|
// load from config if self hosted is enabled
|
||||||
|
if (enable_self_hosted_) {
|
||||||
|
const char* signal_server_host_value =
|
||||||
|
ini_.GetValue(section_, "signal_server_host", nullptr);
|
||||||
|
if (signal_server_host_value != nullptr &&
|
||||||
|
strlen(signal_server_host_value) > 0) {
|
||||||
|
signal_server_host_ = signal_server_host_value;
|
||||||
|
}
|
||||||
|
const char* signal_server_port_value =
|
||||||
|
ini_.GetValue(section_, "signal_server_port", nullptr);
|
||||||
|
if (signal_server_port_value != nullptr &&
|
||||||
|
strlen(signal_server_port_value) > 0) {
|
||||||
|
signal_server_port_ = static_cast<int>(
|
||||||
|
ini_.GetLongValue(section_, "signal_server_port", 0));
|
||||||
|
}
|
||||||
|
const char* coturn_server_port_value =
|
||||||
|
ini_.GetValue(section_, "coturn_server_port", nullptr);
|
||||||
|
if (coturn_server_port_value != nullptr &&
|
||||||
|
strlen(coturn_server_port_value) > 0) {
|
||||||
|
coturn_server_port_ = static_cast<int>(
|
||||||
|
ini_.GetLongValue(section_, "coturn_server_port", 0));
|
||||||
|
}
|
||||||
|
const char* cert_file_path_value =
|
||||||
|
ini_.GetValue(section_, "cert_file_path", nullptr);
|
||||||
|
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
|
||||||
|
cert_file_path_ = cert_file_path_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
||||||
|
ini_.SetLongValue(section_, "signal_server_port",
|
||||||
|
static_cast<long>(signal_server_port_));
|
||||||
|
ini_.SetLongValue(section_, "coturn_server_port",
|
||||||
|
static_cast<long>(coturn_server_port_));
|
||||||
|
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ class ConfigCenter {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string config_path_;
|
std::string config_path_;
|
||||||
std::string cert_file_path_;
|
|
||||||
CSimpleIniA ini_;
|
CSimpleIniA ini_;
|
||||||
const char* section_ = "Settings";
|
const char* section_ = "Settings";
|
||||||
|
|
||||||
@@ -81,12 +80,13 @@ class ConfigCenter {
|
|||||||
bool hardware_video_codec_ = false;
|
bool hardware_video_codec_ = false;
|
||||||
bool enable_turn_ = true;
|
bool enable_turn_ = true;
|
||||||
bool enable_srtp_ = false;
|
bool enable_srtp_ = false;
|
||||||
std::string signal_server_host_ = "api.crossdesk.cn";
|
std::string signal_server_host_ = "";
|
||||||
std::string signal_server_host_default_ = "api.crossdesk.cn";
|
std::string signal_server_host_default_ = "api.crossdesk.cn";
|
||||||
int signal_server_port_ = 9099;
|
int signal_server_port_ = 0;
|
||||||
int server_port_default_ = 9099;
|
int server_port_default_ = 9099;
|
||||||
int coturn_server_port_ = 3478;
|
int coturn_server_port_ = 0;
|
||||||
int coturn_server_port_default_ = 3478;
|
int coturn_server_port_default_ = 3478;
|
||||||
|
std::string cert_file_path_ = "";
|
||||||
std::string cert_file_path_default_ = "";
|
std::string cert_file_path_default_ = "";
|
||||||
bool enable_self_hosted_ = false;
|
bool enable_self_hosted_ = false;
|
||||||
bool enable_minimize_to_tray_ = false;
|
bool enable_minimize_to_tray_ = false;
|
||||||
|
|||||||
@@ -189,11 +189,11 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
|
|||||||
props->params_.user_id = props->local_id_.c_str();
|
props->params_.user_id = props->local_id_.c_str();
|
||||||
props->peer_ = CreatePeer(&props->params_);
|
props->peer_ = CreatePeer(&props->params_);
|
||||||
|
|
||||||
props->control_window_width_ = title_bar_height_ * 7.5f;
|
props->control_window_width_ = title_bar_height_ * 8.0f;
|
||||||
props->control_window_height_ = title_bar_height_ * 1.16f;
|
props->control_window_height_ = title_bar_height_ * 1.3f;
|
||||||
props->control_window_min_width_ = title_bar_height_ * 0.65f;
|
props->control_window_min_width_ = title_bar_height_ * 0.65f;
|
||||||
props->control_window_min_height_ = title_bar_height_ * 1.16f;
|
props->control_window_min_height_ = title_bar_height_ * 1.3f;
|
||||||
props->control_window_max_width_ = title_bar_height_ * 7.5f;
|
props->control_window_max_width_ = title_bar_height_ * 8.0f;
|
||||||
props->control_window_max_height_ = title_bar_height_ * 6.0f;
|
props->control_window_max_height_ = title_bar_height_ * 6.0f;
|
||||||
|
|
||||||
if (!props->peer_) {
|
if (!props->peer_) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "OPPOSans_Regular.h"
|
#include "OPPOSans_Regular.h"
|
||||||
#include "device_controller_factory.h"
|
#include "device_controller_factory.h"
|
||||||
@@ -20,8 +21,6 @@
|
|||||||
|
|
||||||
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
|
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
|
||||||
|
|
||||||
#define MOUSE_GRAB_PADDING 5
|
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
std::vector<char> Render::SerializeRemoteAction(const RemoteAction& action) {
|
std::vector<char> Render::SerializeRemoteAction(const RemoteAction& action) {
|
||||||
@@ -133,9 +132,39 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
|
|||||||
int window_width, window_height;
|
int window_width, window_height;
|
||||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||||
|
|
||||||
if (area->y < 30 * render->dpi_scale_ && area->y > MOUSE_GRAB_PADDING &&
|
// check if curosor is in tab bar
|
||||||
area->x < window_width - 120 * render->dpi_scale_ &&
|
if (render->stream_window_inited_ && render->stream_window_created_ &&
|
||||||
area->x > MOUSE_GRAB_PADDING && !render->is_tab_bar_hovered_) {
|
!render->fullscreen_button_pressed_ && render->stream_ctx_) {
|
||||||
|
ImGuiContext* prev_ctx = ImGui::GetCurrentContext();
|
||||||
|
ImGui::SetCurrentContext(render->stream_ctx_);
|
||||||
|
|
||||||
|
ImGuiWindow* tab_bar_window = ImGui::FindWindowByName("TabBar");
|
||||||
|
if (tab_bar_window && tab_bar_window->Active) {
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
float scale_x = io.DisplayFramebufferScale.x;
|
||||||
|
float scale_y = io.DisplayFramebufferScale.y;
|
||||||
|
|
||||||
|
float tab_bar_x = tab_bar_window->Pos.x * scale_x;
|
||||||
|
float tab_bar_y = tab_bar_window->Pos.y * scale_y;
|
||||||
|
float tab_bar_width = tab_bar_window->Size.x * scale_x;
|
||||||
|
float tab_bar_height = tab_bar_window->Size.y * scale_y;
|
||||||
|
|
||||||
|
ImGui::SetCurrentContext(prev_ctx);
|
||||||
|
|
||||||
|
if (area->x >= tab_bar_x && area->x <= tab_bar_x + tab_bar_width &&
|
||||||
|
area->y >= tab_bar_y && area->y <= tab_bar_y + tab_bar_height) {
|
||||||
|
return SDL_HITTEST_NORMAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::SetCurrentContext(prev_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float mouse_grab_padding = render->title_bar_button_width_ * 0.16f;
|
||||||
|
if (area->y < render->title_bar_button_width_ &&
|
||||||
|
area->y > mouse_grab_padding &&
|
||||||
|
area->x < window_width - render->title_bar_button_width_ * 4.0f &&
|
||||||
|
area->x > mouse_grab_padding) {
|
||||||
return SDL_HITTEST_DRAGGABLE;
|
return SDL_HITTEST_DRAGGABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,25 +172,25 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
|
|||||||
// return SDL_HITTEST_NORMAL;
|
// return SDL_HITTEST_NORMAL;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (area->y < MOUSE_GRAB_PADDING) {
|
if (area->y < mouse_grab_padding) {
|
||||||
if (area->x < MOUSE_GRAB_PADDING) {
|
if (area->x < mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_TOPLEFT;
|
return SDL_HITTEST_RESIZE_TOPLEFT;
|
||||||
} else if (area->x > window_width - MOUSE_GRAB_PADDING) {
|
} else if (area->x > window_width - mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_TOPRIGHT;
|
return SDL_HITTEST_RESIZE_TOPRIGHT;
|
||||||
} else {
|
} else {
|
||||||
return SDL_HITTEST_RESIZE_TOP;
|
return SDL_HITTEST_RESIZE_TOP;
|
||||||
}
|
}
|
||||||
} else if (area->y > window_height - MOUSE_GRAB_PADDING) {
|
} else if (area->y > window_height - mouse_grab_padding) {
|
||||||
if (area->x < MOUSE_GRAB_PADDING) {
|
if (area->x < mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_BOTTOMLEFT;
|
return SDL_HITTEST_RESIZE_BOTTOMLEFT;
|
||||||
} else if (area->x > window_width - MOUSE_GRAB_PADDING) {
|
} else if (area->x > window_width - mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
|
return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
|
||||||
} else {
|
} else {
|
||||||
return SDL_HITTEST_RESIZE_BOTTOM;
|
return SDL_HITTEST_RESIZE_BOTTOM;
|
||||||
}
|
}
|
||||||
} else if (area->x < MOUSE_GRAB_PADDING) {
|
} else if (area->x < mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_LEFT;
|
return SDL_HITTEST_RESIZE_LEFT;
|
||||||
} else if (area->x > window_width - MOUSE_GRAB_PADDING) {
|
} else if (area->x > window_width - mouse_grab_padding) {
|
||||||
return SDL_HITTEST_RESIZE_RIGHT;
|
return SDL_HITTEST_RESIZE_RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +236,7 @@ int Render::LoadSettingsFromCacheFile() {
|
|||||||
memset(aes128_iv_, 0, sizeof(aes128_iv_));
|
memset(aes128_iv_, 0, sizeof(aes128_iv_));
|
||||||
|
|
||||||
thumbnail_.reset();
|
thumbnail_.reset();
|
||||||
thumbnail_ = std::make_unique<Thumbnail>(cache_path_ + "/thumbnails/");
|
thumbnail_ = std::make_shared<Thumbnail>(cache_path_ + "/thumbnails/");
|
||||||
thumbnail_->GetKeyAndIv(aes128_key_, aes128_iv_);
|
thumbnail_->GetKeyAndIv(aes128_key_, aes128_iv_);
|
||||||
thumbnail_->DeleteAllFilesInDirectory();
|
thumbnail_->DeleteAllFilesInDirectory();
|
||||||
|
|
||||||
@@ -248,7 +277,7 @@ int Render::LoadSettingsFromCacheFile() {
|
|||||||
memcpy(aes128_iv_, cd_cache_.iv, sizeof(cd_cache_.iv));
|
memcpy(aes128_iv_, cd_cache_.iv, sizeof(cd_cache_.iv));
|
||||||
|
|
||||||
thumbnail_.reset();
|
thumbnail_.reset();
|
||||||
thumbnail_ = std::make_unique<Thumbnail>(cache_path_ + "/thumbnails/",
|
thumbnail_ = std::make_shared<Thumbnail>(cache_path_ + "/thumbnails/",
|
||||||
aes128_key_, aes128_iv_);
|
aes128_key_, aes128_iv_);
|
||||||
|
|
||||||
language_button_value_ = (int)config_center_->GetLanguage();
|
language_button_value_ = (int)config_center_->GetLanguage();
|
||||||
@@ -462,14 +491,22 @@ int Render::CreateConnectionPeer() {
|
|||||||
strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(),
|
strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(),
|
||||||
sizeof(signal_server_ip_self_) - 1);
|
sizeof(signal_server_ip_self_) - 1);
|
||||||
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
||||||
strncpy(signal_server_port_self_,
|
int signal_port = config_center_->GetSignalServerPort();
|
||||||
std::to_string(config_center_->GetSignalServerPort()).c_str(),
|
if (signal_port > 0) {
|
||||||
sizeof(signal_server_port_self_) - 1);
|
strncpy(signal_server_port_self_, std::to_string(signal_port).c_str(),
|
||||||
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
sizeof(signal_server_port_self_) - 1);
|
||||||
strncpy(coturn_server_port_self_,
|
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
||||||
std::to_string(config_center_->GetCoturnServerPort()).c_str(),
|
} else {
|
||||||
sizeof(coturn_server_port_self_) - 1);
|
signal_server_port_self_[0] = '\0';
|
||||||
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
|
}
|
||||||
|
int coturn_port = config_center_->GetCoturnServerPort();
|
||||||
|
if (coturn_port > 0) {
|
||||||
|
strncpy(coturn_server_port_self_, std::to_string(coturn_port).c_str(),
|
||||||
|
sizeof(coturn_server_port_self_) - 1);
|
||||||
|
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
coturn_server_port_self_[0] = '\0';
|
||||||
|
}
|
||||||
tls_cert_path_self_ = config_center_->GetCertFilePath();
|
tls_cert_path_self_ = config_center_->GetCertFilePath();
|
||||||
|
|
||||||
// peer config
|
// peer config
|
||||||
@@ -1009,10 +1046,15 @@ int Render::Run() {
|
|||||||
config_center_->GetSignalServerHost().c_str(),
|
config_center_->GetSignalServerHost().c_str(),
|
||||||
sizeof(signal_server_ip_self_) - 1);
|
sizeof(signal_server_ip_self_) - 1);
|
||||||
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
||||||
strncpy(signal_server_port_self_,
|
int signal_port_init = config_center_->GetSignalServerPort();
|
||||||
std::to_string(config_center_->GetSignalServerPort()).c_str(),
|
if (signal_port_init > 0) {
|
||||||
sizeof(signal_server_port_self_) - 1);
|
strncpy(signal_server_port_self_,
|
||||||
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
std::to_string(signal_port_init).c_str(),
|
||||||
|
sizeof(signal_server_port_self_) - 1);
|
||||||
|
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
signal_server_port_self_[0] = '\0';
|
||||||
|
}
|
||||||
strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1);
|
strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1);
|
||||||
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
|
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
|
||||||
} else {
|
} else {
|
||||||
@@ -1237,6 +1279,9 @@ void Render::Cleanup() {
|
|||||||
|
|
||||||
CleanupFactories();
|
CleanupFactories();
|
||||||
CleanupPeers();
|
CleanupPeers();
|
||||||
|
|
||||||
|
WaitForThumbnailSaveTasks();
|
||||||
|
|
||||||
AudioDeviceDestroy();
|
AudioDeviceDestroy();
|
||||||
DestroyMainWindowContext();
|
DestroyMainWindowContext();
|
||||||
DestroyMainWindow();
|
DestroyMainWindow();
|
||||||
@@ -1264,10 +1309,29 @@ void Render::CleanupPeer(std::shared_ptr<SubStreamWindowProperties> props) {
|
|||||||
SDL_FlushEvent(STREAM_REFRESH_EVENT);
|
SDL_FlushEvent(STREAM_REFRESH_EVENT);
|
||||||
|
|
||||||
if (props->dst_buffer_) {
|
if (props->dst_buffer_) {
|
||||||
thumbnail_->SaveToThumbnail(
|
size_t buffer_size = props->dst_buffer_capacity_;
|
||||||
(char*)props->dst_buffer_, props->video_width_, props->video_height_,
|
std::vector<unsigned char> buffer_copy(buffer_size);
|
||||||
props->remote_id_, props->remote_host_name_,
|
memcpy(buffer_copy.data(), props->dst_buffer_, buffer_size);
|
||||||
props->remember_password_ ? props->remote_password_ : "");
|
|
||||||
|
int video_width = props->video_width_;
|
||||||
|
int video_height = props->video_height_;
|
||||||
|
std::string remote_id = props->remote_id_;
|
||||||
|
std::string remote_host_name = props->remote_host_name_;
|
||||||
|
std::string password =
|
||||||
|
props->remember_password_ ? props->remote_password_ : "";
|
||||||
|
|
||||||
|
std::thread save_thread([buffer_copy, video_width, video_height, remote_id,
|
||||||
|
remote_host_name, password,
|
||||||
|
thumbnail = thumbnail_]() {
|
||||||
|
thumbnail->SaveToThumbnail((char*)buffer_copy.data(), video_width,
|
||||||
|
video_height, remote_id, remote_host_name,
|
||||||
|
password);
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(thumbnail_save_threads_mutex_);
|
||||||
|
thumbnail_save_threads_.emplace_back(std::move(save_thread));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props->peer_) {
|
if (props->peer_) {
|
||||||
@@ -1305,6 +1369,25 @@ void Render::CleanupPeers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Render::WaitForThumbnailSaveTasks() {
|
||||||
|
std::vector<std::thread> threads_to_join;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(thumbnail_save_threads_mutex_);
|
||||||
|
threads_to_join.swap(thumbnail_save_threads_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threads_to_join.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& thread : threads_to_join) {
|
||||||
|
if (thread.joinable()) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Render::CleanSubStreamWindowProperties(
|
void Render::CleanSubStreamWindowProperties(
|
||||||
std::shared_ptr<SubStreamWindowProperties> props) {
|
std::shared_ptr<SubStreamWindowProperties> props) {
|
||||||
if (props->stream_texture_) {
|
if (props->stream_texture_) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "IconsFontAwesome6.h"
|
#include "IconsFontAwesome6.h"
|
||||||
#include "config_center.h"
|
#include "config_center.h"
|
||||||
@@ -301,7 +302,7 @@ class Render {
|
|||||||
// thumbnail
|
// thumbnail
|
||||||
unsigned char aes128_key_[16];
|
unsigned char aes128_key_[16];
|
||||||
unsigned char aes128_iv_[16];
|
unsigned char aes128_iv_[16];
|
||||||
std::unique_ptr<Thumbnail> thumbnail_;
|
std::shared_ptr<Thumbnail> thumbnail_;
|
||||||
|
|
||||||
// recent connections
|
// recent connections
|
||||||
std::vector<std::pair<std::string, Thumbnail::RecentConnection>>
|
std::vector<std::pair<std::string, Thumbnail::RecentConnection>>
|
||||||
@@ -512,6 +513,11 @@ class Render {
|
|||||||
void CloseTab(decltype(client_properties_)::iterator& it);
|
void CloseTab(decltype(client_properties_)::iterator& it);
|
||||||
/* ------ stream window property end ------ */
|
/* ------ stream window property end ------ */
|
||||||
|
|
||||||
|
/* ------ async thumbnail save tasks ------ */
|
||||||
|
std::vector<std::thread> thumbnail_save_threads_;
|
||||||
|
std::mutex thumbnail_save_threads_mutex_;
|
||||||
|
void WaitForThumbnailSaveTasks();
|
||||||
|
|
||||||
/* ------ server mode ------ */
|
/* ------ server mode ------ */
|
||||||
std::unordered_map<std::string, ConnectionStatus> connection_status_;
|
std::unordered_map<std::string, ConnectionStatus> connection_status_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,21 +40,21 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
|
||||||
if (props->control_bar_expand_) {
|
if (props->control_bar_expand_) {
|
||||||
ImGui::SetCursorPosX(props->is_control_bar_in_left_
|
ImGui::SetCursorPosX(props->is_control_bar_in_left_
|
||||||
? props->control_window_width_ * 1.02f
|
? props->control_window_width_ * 1.03f
|
||||||
: props->control_window_width_ * 0.23f);
|
: props->control_window_width_ * 0.2f);
|
||||||
|
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
if (!props->is_control_bar_in_left_) {
|
if (!props->is_control_bar_in_left_) {
|
||||||
draw_list->AddLine(
|
draw_list->AddLine(
|
||||||
ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.48f,
|
ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.56f,
|
||||||
ImGui::GetCursorScreenPos().y + button_height * 0.2f),
|
ImGui::GetCursorScreenPos().y + button_height * 0.2f),
|
||||||
ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.48f,
|
ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.56f,
|
||||||
ImGui::GetCursorScreenPos().y + button_height * 0.8f),
|
ImGui::GetCursorScreenPos().y + button_height * 0.8f),
|
||||||
IM_COL32(178, 178, 178, 255), 2.0f);
|
IM_COL32(178, 178, 178, 255), 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string display = ICON_FA_DISPLAY;
|
std::string display = ICON_FA_DISPLAY;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(display.c_str(), ImVec2(button_width, button_height))) {
|
if (ImGui::Button(display.c_str(), ImVec2(button_width, button_height))) {
|
||||||
ImGui::OpenPopup("display");
|
ImGui::OpenPopup("display");
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
ImVec2 btn_size_actual = ImGui::GetItemRectSize();
|
ImVec2 btn_size_actual = ImGui::GetItemRectSize();
|
||||||
|
|
||||||
if (ImGui::BeginPopup("display")) {
|
if (ImGui::BeginPopup("display")) {
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
for (int i = 0; i < props->display_info_list_.size(); i++) {
|
for (int i = 0; i < props->display_info_list_.size(); i++) {
|
||||||
if (ImGui::Selectable(props->display_info_list_[i].name.c_str())) {
|
if (ImGui::Selectable(props->display_info_list_[i].name.c_str())) {
|
||||||
props->selected_display_ = i;
|
props->selected_display_ = i;
|
||||||
@@ -100,7 +100,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
std::string mouse = props->mouse_control_button_pressed_
|
std::string mouse = props->mouse_control_button_pressed_
|
||||||
? ICON_FA_COMPUTER_MOUSE
|
? ICON_FA_COMPUTER_MOUSE
|
||||||
: ICON_FA_COMPUTER_MOUSE;
|
: ICON_FA_COMPUTER_MOUSE;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(mouse.c_str(), ImVec2(button_width, button_height))) {
|
if (ImGui::Button(mouse.c_str(), ImVec2(button_width, button_height))) {
|
||||||
if (props->connection_established_) {
|
if (props->connection_established_) {
|
||||||
start_keyboard_capturer_ = !start_keyboard_capturer_;
|
start_keyboard_capturer_ = !start_keyboard_capturer_;
|
||||||
@@ -140,7 +140,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
std::string audio = props->audio_capture_button_pressed_
|
std::string audio = props->audio_capture_button_pressed_
|
||||||
? ICON_FA_VOLUME_HIGH
|
? ICON_FA_VOLUME_HIGH
|
||||||
: ICON_FA_VOLUME_HIGH;
|
: ICON_FA_VOLUME_HIGH;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(audio.c_str(), ImVec2(button_width, button_height))) {
|
if (ImGui::Button(audio.c_str(), ImVec2(button_width, button_height))) {
|
||||||
if (props->connection_established_) {
|
if (props->connection_established_) {
|
||||||
props->audio_capture_button_pressed_ =
|
props->audio_capture_button_pressed_ =
|
||||||
@@ -184,7 +184,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
button_color_style_pushed = true;
|
button_color_style_pushed = true;
|
||||||
}
|
}
|
||||||
std::string net_traffic_stats = ICON_FA_SIGNAL;
|
std::string net_traffic_stats = ICON_FA_SIGNAL;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(net_traffic_stats.c_str(),
|
if (ImGui::Button(net_traffic_stats.c_str(),
|
||||||
ImVec2(button_width, button_height))) {
|
ImVec2(button_width, button_height))) {
|
||||||
props->net_traffic_stats_button_pressed_ =
|
props->net_traffic_stats_button_pressed_ =
|
||||||
@@ -208,7 +208,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
// fullscreen button
|
// fullscreen button
|
||||||
std::string fullscreen =
|
std::string fullscreen =
|
||||||
fullscreen_button_pressed_ ? ICON_FA_COMPRESS : ICON_FA_EXPAND;
|
fullscreen_button_pressed_ ? ICON_FA_COMPRESS : ICON_FA_EXPAND;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(fullscreen.c_str(),
|
if (ImGui::Button(fullscreen.c_str(),
|
||||||
ImVec2(button_width, button_height))) {
|
ImVec2(button_width, button_height))) {
|
||||||
fullscreen_button_pressed_ = !fullscreen_button_pressed_;
|
fullscreen_button_pressed_ = !fullscreen_button_pressed_;
|
||||||
@@ -228,7 +228,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
// close button
|
// close button
|
||||||
std::string close_button = ICON_FA_XMARK;
|
std::string close_button = ICON_FA_XMARK;
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::Button(close_button.c_str(),
|
if (ImGui::Button(close_button.c_str(),
|
||||||
ImVec2(button_width, button_height))) {
|
ImVec2(button_width, button_height))) {
|
||||||
CleanupPeer(props);
|
CleanupPeer(props);
|
||||||
@@ -250,7 +250,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
|
|
||||||
float expand_button_pos_x =
|
float expand_button_pos_x =
|
||||||
props->control_bar_expand_ ? (props->is_control_bar_in_left_
|
props->control_bar_expand_ ? (props->is_control_bar_in_left_
|
||||||
? props->control_window_width_ * 1.9f
|
? props->control_window_width_ * 1.91f
|
||||||
: props->control_window_width_ * 0.03f)
|
: props->control_window_width_ * 0.03f)
|
||||||
: (props->is_control_bar_in_left_
|
: (props->is_control_bar_in_left_
|
||||||
? props->control_window_width_ * 1.02f
|
? props->control_window_width_ * 1.02f
|
||||||
@@ -290,7 +290,7 @@ int Render::NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props) {
|
|||||||
? props->control_window_width_ * 1.02f
|
? props->control_window_width_ * 1.02f
|
||||||
: props->control_window_width_ * 0.02f,
|
: props->control_window_width_ * 0.02f,
|
||||||
props->control_window_min_height_));
|
props->control_window_min_height_));
|
||||||
ImGui::SetWindowFontScale(0.8f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH,
|
if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH,
|
||||||
ImVec2(props->control_window_max_width_ * 0.9f,
|
ImVec2(props->control_window_max_width_ * 0.9f,
|
||||||
props->control_window_max_height_ - 0.9f))) {
|
props->control_window_max_height_ - 0.9f))) {
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ int Render::TitleBar(bool main_window) {
|
|||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndPopup();
|
||||||
} else {
|
} else {
|
||||||
show_new_version_icon_in_menu_ = true;
|
show_new_version_icon_in_menu_ = true;
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,9 @@ int Render::TitleBar(bool main_window) {
|
|||||||
// render for 1 second
|
// render for 1 second
|
||||||
if (show_new_version_icon_) {
|
if (show_new_version_icon_) {
|
||||||
ImGui::SetWindowFontScale(0.6f);
|
ImGui::SetWindowFontScale(0.6f);
|
||||||
ImGui::SetCursorPos(ImVec2(bar_pos_x + 10, bar_pos_y - 17));
|
ImGui::SetCursorPos(
|
||||||
|
ImVec2(bar_pos_x + title_bar_button_width * 0.15f,
|
||||||
|
bar_pos_y - title_bar_button_width * 0.325f));
|
||||||
ImGui::Text(ICON_FA_TRIANGLE_EXCLAMATION);
|
ImGui::Text(ICON_FA_TRIANGLE_EXCLAMATION);
|
||||||
ImGui::SetWindowFontScale(1.0f);
|
ImGui::SetWindowFontScale(1.0f);
|
||||||
|
|
||||||
|
|||||||
@@ -141,9 +141,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
{
|
{
|
||||||
static int settings_items_padding = title_bar_button_width_;
|
|
||||||
int settings_items_offset = 0;
|
|
||||||
|
|
||||||
ImGui::SetWindowFontScale(0.5f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
|
||||||
@@ -159,8 +156,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::SetWindowFontScale(0.5f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||||
{
|
{
|
||||||
settings_items_offset += settings_items_padding;
|
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text("%s", localization::self_hosted_server_address
|
ImGui::Text("%s", localization::self_hosted_server_address
|
||||||
[localization_language_index_]
|
[localization_language_index_]
|
||||||
@@ -171,7 +166,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
||||||
|
|
||||||
ImGui::InputText("##signal_server_ip_self_", signal_server_ip_self_,
|
ImGui::InputText("##signal_server_ip_self_", signal_server_ip_self_,
|
||||||
@@ -182,8 +176,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
{
|
{
|
||||||
settings_items_offset += settings_items_padding;
|
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text(
|
ImGui::Text(
|
||||||
"%s",
|
"%s",
|
||||||
@@ -195,7 +187,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
||||||
|
|
||||||
ImGui::InputText("##signal_server_port_self_", signal_server_port_self_,
|
ImGui::InputText("##signal_server_port_self_", signal_server_port_self_,
|
||||||
@@ -205,8 +196,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
{
|
{
|
||||||
settings_items_offset += settings_items_padding;
|
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text("%s", localization::self_hosted_server_coturn_server_port
|
ImGui::Text("%s", localization::self_hosted_server_coturn_server_port
|
||||||
[localization_language_index_]
|
[localization_language_index_]
|
||||||
@@ -217,7 +206,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
||||||
|
|
||||||
ImGui::InputText("##coturn_server_port_self_", coturn_server_port_self_,
|
ImGui::InputText("##coturn_server_port_self_", coturn_server_port_self_,
|
||||||
@@ -227,8 +215,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
{
|
{
|
||||||
settings_items_offset += settings_items_padding;
|
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text("%s", localization::self_hosted_server_certificate_path
|
ImGui::Text("%s", localization::self_hosted_server_certificate_path
|
||||||
[localization_language_index_]
|
[localization_language_index_]
|
||||||
@@ -239,7 +225,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
||||||
|
|
||||||
ShowSimpleFileBrowser();
|
ShowSimpleFileBrowser();
|
||||||
@@ -249,15 +234,14 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, title_bar_button_width_ * 0.25f));
|
||||||
|
|
||||||
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
|
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 2.32f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 2.32f);
|
||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosX(title_bar_button_width_ * 2.7f);
|
ImGui::SetCursorPosX(title_bar_button_width_ * 2.7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
settings_items_offset +=
|
|
||||||
settings_items_padding + title_bar_button_width_ * 0.3f;
|
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
@@ -291,16 +275,27 @@ int Render::SelfHostedServerWindow() {
|
|||||||
localization::cancel[localization_language_index_].c_str())) {
|
localization::cancel[localization_language_index_].c_str())) {
|
||||||
show_self_hosted_server_config_window_ = false;
|
show_self_hosted_server_config_window_ = false;
|
||||||
self_hosted_server_config_window_pos_reset_ = true;
|
self_hosted_server_config_window_pos_reset_ = true;
|
||||||
|
strncpy(signal_server_ip_self_,
|
||||||
strncpy(signal_server_ip_self_, signal_server_ip_,
|
config_center_->GetSignalServerHost().c_str(),
|
||||||
sizeof(signal_server_ip_self_) - 1);
|
sizeof(signal_server_ip_self_) - 1);
|
||||||
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
|
||||||
strncpy(signal_server_port_self_, signal_server_port_,
|
int signal_port = config_center_->GetSignalServerPort();
|
||||||
sizeof(signal_server_port_self_) - 1);
|
if (signal_port > 0) {
|
||||||
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
strncpy(signal_server_port_self_, std::to_string(signal_port).c_str(),
|
||||||
config_center_->SetServerHost(signal_server_ip_self_);
|
sizeof(signal_server_port_self_) - 1);
|
||||||
config_center_->SetServerPort(atoi(signal_server_port_self_));
|
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
|
||||||
tls_cert_path_self_.clear();
|
} else {
|
||||||
|
signal_server_port_self_[0] = '\0';
|
||||||
|
}
|
||||||
|
int coturn_port = config_center_->GetCoturnServerPort();
|
||||||
|
if (coturn_port > 0) {
|
||||||
|
strncpy(coturn_server_port_self_, std::to_string(coturn_port).c_str(),
|
||||||
|
sizeof(coturn_server_port_self_) - 1);
|
||||||
|
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
coturn_server_port_self_[0] = '\0';
|
||||||
|
}
|
||||||
|
tls_cert_path_self_ = config_center_->GetCertFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetWindowFontScale(1.0f);
|
ImGui::SetWindowFontScale(1.0f);
|
||||||
|
|||||||
@@ -170,6 +170,20 @@ int Render::StreamWindow() {
|
|||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
} else {
|
} else {
|
||||||
props->tab_selected_ = false;
|
props->tab_selected_ = false;
|
||||||
|
if (!props->tab_opened_) {
|
||||||
|
std::string remote_id_to_close = props->remote_id_;
|
||||||
|
// lock.unlock();
|
||||||
|
{
|
||||||
|
// std::unique_lock unique_lock(client_properties_mutex_);
|
||||||
|
auto close_it = client_properties_.find(remote_id_to_close);
|
||||||
|
if (close_it != client_properties_.end()) {
|
||||||
|
CloseTab(close_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// lock.lock();
|
||||||
|
it = client_properties_.begin();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user