feat(webrtc): 添加公共ICE服务器支持和优化HID延迟

- 重构ICE配置:将TURN配置改为统一的ICE配置,支持STUN和多TURN URL
- 添加公共ICE服务器:类似RustDesk,用户留空时使用编译时配置的公共服务器
- 优化DataChannel HID消息:使用tokio::spawn立即处理,避免依赖webrtc-rs轮询
- 添加WebRTCReady事件:客户端等待此事件后再建立连接
- 初始化时启动音频流,确保WebRTC可订阅
- 移除多余的trace/debug日志减少开销
- 更新前端配置界面支持公共ICE服务器显示
This commit is contained in:
mofeng-git
2026-01-04 15:06:08 +08:00
parent 0c82d1a840
commit 9ab3d052f9
24 changed files with 766 additions and 258 deletions

View File

@@ -73,6 +73,10 @@ pub struct StreamConfigResponse {
pub mode: StreamMode,
pub encoder: EncoderType,
pub bitrate_preset: BitratePreset,
/// 是否有公共 ICE 服务器可用(编译时确定)
pub has_public_ice_servers: bool,
/// 当前是否正在使用公共 ICE 服务器STUN/TURN 都为空时)
pub using_public_ice_servers: bool,
pub stun_server: Option<String>,
pub turn_server: Option<String>,
pub turn_username: Option<String>,
@@ -82,10 +86,13 @@ pub struct StreamConfigResponse {
impl From<&StreamConfig> for StreamConfigResponse {
fn from(config: &StreamConfig) -> Self {
use crate::webrtc::config::public_ice;
Self {
mode: config.mode.clone(),
encoder: config.encoder.clone(),
bitrate_preset: config.bitrate_preset,
has_public_ice_servers: public_ice::is_configured(),
using_public_ice_servers: config.is_using_public_ice_servers(),
stun_server: config.stun_server.clone(),
turn_server: config.turn_server.clone(),
turn_username: config.turn_username.clone(),
@@ -101,8 +108,10 @@ pub struct StreamConfigUpdate {
pub encoder: Option<EncoderType>,
pub bitrate_preset: Option<BitratePreset>,
/// STUN server URL (e.g., "stun:stun.l.google.com:19302")
/// Leave empty to use public ICE servers
pub stun_server: Option<String>,
/// TURN server URL (e.g., "turn:turn.example.com:3478")
/// Leave empty to use public ICE servers
pub turn_server: Option<String>,
/// TURN username
pub turn_username: Option<String>,
@@ -142,7 +151,7 @@ impl StreamConfigUpdate {
if let Some(preset) = self.bitrate_preset {
config.bitrate_preset = preset;
}
// STUN/TURN settings - empty string means clear, Some("value") means set
// STUN/TURN settings - empty string means clear (use public servers), Some("value") means set custom
if let Some(ref stun) = self.stun_server {
config.stun_server = if stun.is_empty() { None } else { Some(stun.clone()) };
}

View File

@@ -648,6 +648,24 @@ pub async fn setup_init(
}
}
// Start audio streaming if audio device was selected during setup
if new_config.audio.enabled {
let audio_config = crate::audio::AudioControllerConfig {
enabled: true,
device: new_config.audio.device.clone(),
quality: crate::audio::AudioQuality::from_str(&new_config.audio.quality),
};
if let Err(e) = state.audio.update_config(audio_config).await {
tracing::warn!("Failed to start audio during setup: {}", e);
} else {
tracing::info!("Audio started during setup: device={}", new_config.audio.device);
}
// Also enable WebRTC audio
if let Err(e) = state.stream_manager.set_webrtc_audio_enabled(true).await {
tracing::warn!("Failed to enable WebRTC audio during setup: {}", e);
}
}
tracing::info!("System initialized successfully with admin user: {}", req.username);
Ok(Json(LoginResponse {