mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 00:51:53 +08:00
feat(rustdesk): 优化视频编码协商和添加公共服务器支持
- 调整视频编码优先级为 H264 > H265 > VP8 > VP9,优先使用硬件编码 - 对接 RustDesk 客户端质量预设 (Low/Balanced/Best) 到 BitratePreset - 添加 secrets.toml 编译时读取机制,支持配置公共服务器 - 默认公共服务器: rustdesk.mofeng.run:21116 - 前端 ID 服务器输入框添加问号提示,显示公共服务器信息 - 用户留空时自动使用公共服务器
This commit is contained in:
@@ -109,11 +109,11 @@ pub async fn apply_stream_config(
|
||||
}
|
||||
|
||||
// 更新码率
|
||||
if old_config.bitrate_kbps != new_config.bitrate_kbps {
|
||||
if old_config.bitrate_preset != new_config.bitrate_preset {
|
||||
state
|
||||
.stream_manager
|
||||
.webrtc_streamer()
|
||||
.set_bitrate(new_config.bitrate_kbps)
|
||||
.set_bitrate_preset(new_config.bitrate_preset)
|
||||
.await
|
||||
.ok(); // Ignore error if no active stream
|
||||
}
|
||||
@@ -143,9 +143,9 @@ pub async fn apply_stream_config(
|
||||
}
|
||||
|
||||
tracing::info!(
|
||||
"Stream config applied: encoder={:?}, bitrate={} kbps",
|
||||
"Stream config applied: encoder={:?}, bitrate={}",
|
||||
new_config.encoder,
|
||||
new_config.bitrate_kbps
|
||||
new_config.bitrate_preset
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use axum::{extract::State, Json};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::rustdesk::config::RustDeskConfig;
|
||||
use crate::rustdesk::config::{PublicServerInfo, RustDeskConfig};
|
||||
use crate::state::AppState;
|
||||
|
||||
use super::apply::apply_rustdesk_config;
|
||||
@@ -21,6 +21,8 @@ pub struct RustDeskConfigResponse {
|
||||
pub has_password: bool,
|
||||
/// 是否已设置密钥对
|
||||
pub has_keypair: bool,
|
||||
/// 是否使用公共服务器(用户留空时)
|
||||
pub using_public_server: bool,
|
||||
}
|
||||
|
||||
impl From<&RustDeskConfig> for RustDeskConfigResponse {
|
||||
@@ -32,6 +34,7 @@ impl From<&RustDeskConfig> for RustDeskConfigResponse {
|
||||
device_id: config.device_id.clone(),
|
||||
has_password: !config.device_password.is_empty(),
|
||||
has_keypair: config.public_key.is_some() && config.private_key.is_some(),
|
||||
using_public_server: config.is_using_public_server(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +45,8 @@ pub struct RustDeskStatusResponse {
|
||||
pub config: RustDeskConfigResponse,
|
||||
pub service_status: String,
|
||||
pub rendezvous_status: Option<String>,
|
||||
/// 公共服务器信息(仅当有公共服务器配置时返回)
|
||||
pub public_server: Option<PublicServerInfo>,
|
||||
}
|
||||
|
||||
/// 获取 RustDesk 配置
|
||||
@@ -65,10 +70,14 @@ pub async fn get_rustdesk_status(State(state): State<Arc<AppState>>) -> Json<Rus
|
||||
}
|
||||
};
|
||||
|
||||
// 获取公共服务器信息
|
||||
let public_server = RustDeskConfig::public_server_info();
|
||||
|
||||
Json(RustDeskStatusResponse {
|
||||
config: RustDeskConfigResponse::from(&config),
|
||||
service_status,
|
||||
rendezvous_status,
|
||||
public_server,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ use typeshare::typeshare;
|
||||
use crate::config::*;
|
||||
use crate::error::AppError;
|
||||
use crate::rustdesk::config::RustDeskConfig;
|
||||
use crate::video::encoder::BitratePreset;
|
||||
|
||||
// ===== Video Config =====
|
||||
#[typeshare]
|
||||
@@ -71,8 +72,7 @@ impl VideoConfigUpdate {
|
||||
pub struct StreamConfigResponse {
|
||||
pub mode: StreamMode,
|
||||
pub encoder: EncoderType,
|
||||
pub bitrate_kbps: u32,
|
||||
pub gop_size: u32,
|
||||
pub bitrate_preset: BitratePreset,
|
||||
pub stun_server: Option<String>,
|
||||
pub turn_server: Option<String>,
|
||||
pub turn_username: Option<String>,
|
||||
@@ -85,8 +85,7 @@ impl From<&StreamConfig> for StreamConfigResponse {
|
||||
Self {
|
||||
mode: config.mode.clone(),
|
||||
encoder: config.encoder.clone(),
|
||||
bitrate_kbps: config.bitrate_kbps,
|
||||
gop_size: config.gop_size,
|
||||
bitrate_preset: config.bitrate_preset,
|
||||
stun_server: config.stun_server.clone(),
|
||||
turn_server: config.turn_server.clone(),
|
||||
turn_username: config.turn_username.clone(),
|
||||
@@ -100,8 +99,7 @@ impl From<&StreamConfig> for StreamConfigResponse {
|
||||
pub struct StreamConfigUpdate {
|
||||
pub mode: Option<StreamMode>,
|
||||
pub encoder: Option<EncoderType>,
|
||||
pub bitrate_kbps: Option<u32>,
|
||||
pub gop_size: Option<u32>,
|
||||
pub bitrate_preset: Option<BitratePreset>,
|
||||
/// STUN server URL (e.g., "stun:stun.l.google.com:19302")
|
||||
pub stun_server: Option<String>,
|
||||
/// TURN server URL (e.g., "turn:turn.example.com:3478")
|
||||
@@ -114,16 +112,7 @@ pub struct StreamConfigUpdate {
|
||||
|
||||
impl StreamConfigUpdate {
|
||||
pub fn validate(&self) -> crate::error::Result<()> {
|
||||
if let Some(bitrate) = self.bitrate_kbps {
|
||||
if !(1000..=15000).contains(&bitrate) {
|
||||
return Err(AppError::BadRequest("Bitrate must be 1000-15000 kbps".into()));
|
||||
}
|
||||
}
|
||||
if let Some(gop) = self.gop_size {
|
||||
if !(10..=300).contains(&gop) {
|
||||
return Err(AppError::BadRequest("GOP size must be 10-300".into()));
|
||||
}
|
||||
}
|
||||
// BitratePreset is always valid (enum)
|
||||
// Validate STUN server format
|
||||
if let Some(ref stun) = self.stun_server {
|
||||
if !stun.is_empty() && !stun.starts_with("stun:") {
|
||||
@@ -150,11 +139,8 @@ impl StreamConfigUpdate {
|
||||
if let Some(encoder) = self.encoder.clone() {
|
||||
config.encoder = encoder;
|
||||
}
|
||||
if let Some(bitrate) = self.bitrate_kbps {
|
||||
config.bitrate_kbps = bitrate;
|
||||
}
|
||||
if let Some(gop) = self.gop_size {
|
||||
config.gop_size = gop;
|
||||
if let Some(preset) = self.bitrate_preset {
|
||||
config.bitrate_preset = preset;
|
||||
}
|
||||
// STUN/TURN settings - empty string means clear, Some("value") means set
|
||||
if let Some(ref stun) = self.stun_server {
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::auth::{Session, SESSION_COOKIE};
|
||||
use crate::config::{AppConfig, StreamMode};
|
||||
use crate::error::{AppError, Result};
|
||||
use crate::state::AppState;
|
||||
use crate::video::encoder::BitratePreset;
|
||||
|
||||
// ============================================================================
|
||||
// Health & Info
|
||||
@@ -742,12 +743,12 @@ pub async fn update_config(
|
||||
state
|
||||
.stream_manager
|
||||
.webrtc_streamer()
|
||||
.set_bitrate(new_config.stream.bitrate_kbps)
|
||||
.set_bitrate_preset(new_config.stream.bitrate_preset)
|
||||
.await
|
||||
.ok(); // Ignore error if no active stream
|
||||
|
||||
tracing::info!("Stream config applied: encoder={:?}, bitrate={} kbps",
|
||||
new_config.stream.encoder, new_config.stream.bitrate_kbps);
|
||||
tracing::info!("Stream config applied: encoder={:?}, bitrate={}",
|
||||
new_config.stream.encoder, new_config.stream.bitrate_preset);
|
||||
}
|
||||
|
||||
// HID config processing - always reload if section was sent
|
||||
@@ -1191,7 +1192,7 @@ pub struct AvailableCodecsResponse {
|
||||
/// Set bitrate request
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetBitrateRequest {
|
||||
pub bitrate_kbps: u32,
|
||||
pub bitrate_preset: BitratePreset,
|
||||
}
|
||||
|
||||
/// Set stream bitrate (real-time adjustment)
|
||||
@@ -1199,19 +1200,11 @@ pub async fn stream_set_bitrate(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(req): Json<SetBitrateRequest>,
|
||||
) -> Result<Json<LoginResponse>> {
|
||||
// Validate bitrate range (1000-15000 kbps)
|
||||
if req.bitrate_kbps < 1000 || req.bitrate_kbps > 15000 {
|
||||
return Err(AppError::BadRequest(format!(
|
||||
"Bitrate must be between 1000 and 15000 kbps, got {}",
|
||||
req.bitrate_kbps
|
||||
)));
|
||||
}
|
||||
|
||||
// Update config
|
||||
state
|
||||
.config
|
||||
.update(|config| {
|
||||
config.stream.bitrate_kbps = req.bitrate_kbps;
|
||||
config.stream.bitrate_preset = req.bitrate_preset;
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1219,18 +1212,18 @@ pub async fn stream_set_bitrate(
|
||||
if let Err(e) = state
|
||||
.stream_manager
|
||||
.webrtc_streamer()
|
||||
.set_bitrate(req.bitrate_kbps)
|
||||
.set_bitrate_preset(req.bitrate_preset)
|
||||
.await
|
||||
{
|
||||
warn!("Failed to set bitrate dynamically: {}", e);
|
||||
// Don't fail the request - config is saved, will apply on next connection
|
||||
} else {
|
||||
info!("Bitrate updated to {} kbps", req.bitrate_kbps);
|
||||
info!("Bitrate updated to {}", req.bitrate_preset);
|
||||
}
|
||||
|
||||
Ok(Json(LoginResponse {
|
||||
success: true,
|
||||
message: Some(format!("Bitrate set to {} kbps", req.bitrate_kbps)),
|
||||
message: Some(format!("Bitrate set to {}", req.bitrate_preset)),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user