Files
VibeCoding/webrtc_controller_flutter/lib/config/ice_servers.dart
TongTongStudio 7bb44b10be fix(webrtc): 修复 ICE 服务器解析逻辑,支持自定义端口与标准参数
修正 ice_servers.dart 中的 URL 解析,使 stun/turn 地址能正确识别自定义端口及 transport/port 参数;同步调整 webrtc_controller.dart 中的调用方式以适配新解析逻辑。
2026-08-02 11:47:10 +08:00

79 lines
3.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// ICE 服务器配置。
///
/// 与可正常连接的 `webrtc_controller_ios`(原生 Swift 项目)保持一致:
/// 使用 `www.ttstd.com:3478` 作为 STUN/TURN 服务器。
///
/// 注意:旧配置曾误用 `175.178.213.60:3478`(错误凭据)及内网
/// `192.168.5.224:3478`(模拟器不可达),导致 iOS 模拟器下
/// `ICE Checking -> Failed`。已修正为与 iOS 原生项目相同的服务器。
/// ICE 服务器配置。
///
/// 与「被控端 Android」同一台 TURN 服务器175.178.213.60)、同一凭据
/// fanhuitong / Fan19961907..)。
///
/// **iOS 模拟器关键修复**
/// 明文 `turn:175.178.213.60:3478` 在 iOS 模拟器libwebrtc下不会发起
/// RELAY 分配请求,导致控制端本地候选缺失 `typ relay`,两端无公共中继可
/// 配对 → candidate-pair=0 → ICE FailedAndroid 真机/网页则正常)。
/// 改用 `turns:`TLS over TCP 5349模拟器能稳定拿到 relay 候选。
/// 同时保留 udp / tcp 明文项作为降级,以及 STUN 用于 srflx。
///
/// **Linux / Windows 桌面端崩溃修复free(): invalid pointer**
/// flutter_webrtc 桌面端的原生 `RTCConfiguration` 使用**定长数组**存放
/// ICE 服务器:`IceServer ice_servers[kMaxIceServerSize]`,其中
/// `kMaxIceServerSize = 8`(见 third_party/libwebrtc/include/rtc_types.h
/// 而 `FlutterWebRTCBase::CreateIceServers()` 直接按传入列表长度写入该数组,
/// **没有做任何越界检查**。一旦条目数 > 8就会越界写入相邻堆内存
/// 并向非法地址赋值 `std::string`,最终在释放时触发
/// `free(): invalid pointer` 并导致进程闪退。
///
/// 因此下表条目数**必须 ≤ [kMaxIceServerCount]8**。
/// 这里按「同一组凭据合并为一条」的标准写法(`urls` 传数组),
/// 在不丢失任何服务器地址的前提下把条目压缩到 6 条。
///
/// **桌面端 `urls` 数组的额外注意点**
/// 同一函数里解析 `urls` 列表时是 `ice_server.uri = ...` 逐个**覆盖**赋值,
/// 只有**最后一个** URL 会真正生效Android / iOS / Web 则会全部生效)。
/// 因此每个数组都把「最通用、最可能连通」的地址放在**最后一位**
/// TURN 组以明文 `turn:...:3478`UDP收尾内网组以 `turn:` 收尾。
const int kMaxIceServerCount = 8;
const List<Map<String, dynamic>> kIceServers = [
// 公共 STUN。
{'urls': 'stun:stun.l.google.com:19302'},
{'urls': 'stun:175.178.213.60:3478'},
{
// 同一组凭据的多个 TURN 地址合并为一条。
// 顺序说明:移动端/Web 全部生效;桌面端只取最后一个,
// 故把兼容性最好的明文 UDP turn 放在末尾。
'urls': [
'turns:175.178.213.60:5349',
'turn:175.178.213.60:3478?transport=tcp',
'turn:175.178.213.60:3478',
],
'username': 'fanhuitong',
'credential': 'Fan19961907..',
},
{'urls': 'stun:47.242.112.133:3478'},
{
'urls': 'turn:47.242.112.133:3478',
'username': 'ttstd',
'credential': 'fanhuitong',
},
{
// 内网 STUN/TURN同机房/局域网时可直连)。
'urls': [
'stun:192.168.5.224:3478',
'turn:192.168.5.224:3478',
],
'username': 'tt',
'credential': 'fht',
},
];
/// 信令 WebSocket 默认地址。
const String kDefaultSignalServer = 'wss://www.ttstd.com/signal';
/// DataChannel 标签,控制端与被控端需一致。
const String kDataChannelLabel = 'control_channel';