【免费下载链接】commet
Your space to connect
📞Commet是一款主打安全与隐私的 Matrix 开源聊天客户端(口号是 "Your space to connect"),它的语音通话与视频通话能力非常值得一提。本文将揭秘 Commet 是如何把WebRTC的点对点直连与LiveKit的 SFU 群组通话两条技术路线,无缝接入 Matrix 协议的。无论你是想了解 Matrix 群组通话原理的新手,还是准备给自己的项目接入 VoIP 的开发者,这篇完整指南都能帮你在 5 分钟内看懂其中的门道。
一图看懂 Commet 的通话架构:两套引擎并存
很多用户在用 Commet 时会发现:1 对 1 聊天里点「通话」,和多人通话房间里的体验并不完全一样。这不是玄学,而是 Commet 故意设计的双引擎架构:
| 场景 | 信令通道 | 媒体传输 | 核心代码 |
|---|---|---|---|
| 1 对 1 语音/视频通话 | Matrixto-device消息(m.call.invite等) | WebRTC P2P 直连 | matrix_voip_component.dart |
| 群组通话(VoIP Room) | Matrix 房间状态事件 + homeserver 签发 JWT | LiveKit SFU 转发 | matrix_livekit_backend.dart |
Commet 用一个抽象层把两条路线统一起来。在 voip_component.dart 中,VoipComponent抽象类只关心四件事:发起通话(startCall)、查询会话(getSessionsInRoom)、监听会话开始/结束事件、判断房间能否通话。UI 层完全不需要知道底层是 WebRTC 还是 LiveKit,这种"策略可替换"的设计是整个 VoIP 模块的精髓。
引擎一:WebRTC 如何让两个人"直接连上"
1 对 1 通话走的是 Matrix 官方 VoIP 规范:双方通过m.call.invite、m.call.answer、m.call.hangup等to-device事件交换 SDP 与 ICE 候选,最终在两台设备之间建立WebRTC PeerConnection直连。
在 matrix_voip_component.dart 中,Commet 实现了WebRTCDelegate接口来接管这条链路,其中有两个很务实的细节:
- ICE 服务器拆分:homeserver 下发的 STUN/TURN 配置会被拆成单个 URL 的独立条目,避免
flutter_webrtc只检查第一个地址的问题; - TURN 回退兜底:如果 homeserver 没有配置任何 ICE 服务器,Commet 会弹出确认框,询问是否使用预设的回退 TURN 服务器(
VoipTurnFallbackDialog),否则直接抛错提示"无法连接"。
底层真正干活的是flutter_webrtc库(在 pubspec.yaml 中锁定为 1.4.0,并使用了 commet 社区的 fork 以保证兼容性),它负责麦克风采集、摄像头采集、媒体流发布等 WebRTC 标准能力。
引擎二:LiveKit SFU 如何撑起群组通话 🎥
两个人直连没问题,但 10 个人互连就要维护 45 条媒体流,根本不可行。因此 Commet 的群组语音通话采用了 MSC3417 提案 中的"VoIP Room"方案:房间创建时type为org.matrix.msc3417.call,所有参与者的音视频都上传到一台LiveKit SFU(选择性转发单元)服务器,由 SFU 负责分发,任何客户端只需下载自己需要的流,带宽与延迟都大大优化。
加入一次群组通话,matrix_livekit_backend.dart 的join()方法会按下面 5 步走:
- 发现 LiveKit 服务地址(Focus URL):优先读取房间状态事件
org.matrix.msc3401.call.member中其他成员留下的foci_preferred;找不到就查询 homeserver 的 well-known 文件里的org.matrix.msc4143.rtc_foci字段; - 向 homeserver 换 JWT:调用
requestOpenIdToken拿到临时访问令牌,这是"用 Matrix 身份进入 LiveKit 房间"的门票; - 请求 SFU 接入点:POST 到
{livekit_service_url}/sfu/get,携带设备 ID、房间 ID 和 OpenID 令牌,换回 LiveKit 连接地址与 JWT; - 宣告自己在场:把自己的
foci_preferred和focus_active写回房间状态事件,方便后加入的人发现同一台 SFU; - 连接 LiveKit 房间并开麦:以自适应码率(
adaptiveStream)与dynacast模式连接,随后自动启用默认麦克风。
加密通话里的密钥是如何悄悄交换的 🔒
在加密房间中,SFU 转发的是"密文",所以 Commet 还需要一套媒体层端到端加密。核心实现在 matrix_livekit_encryption_key_provider.dart:
- 基于 LiveKit 的 E2EE 框架,为每个参与者维护一个 256 位的密钥环,采用 HKDF 派生与 Ratchet 滚动机制(依赖
vodozemac/flutter_vodozemac加密库,见 pubspec.yaml); - 每当有人加入或离开通话(监听房间
call.member状态变化),就会立即轮换密钥,并通过 Matrixto-device加密事件io.element.call.encryption_keys把新密钥分发给每个在席设备; - 旧参与者离开后,其密钥自然失效——这正是"前向保密"思想在音视频场景中的落地。
你看到的通话界面背后发生了什么
通话 UI 位于 call_view.dart,它根据VoipState(incoming / outgoing / connecting / connected / ended)切换五种界面:响铃页、拨出页、通话中网格页、结束页等。配套的 voip_stream_view.dart 负责渲染每一路视频流。
而全局的"通话大脑"是 call_manager.dart:
- 🔔 来电时触发系统通知(Android 上直接交给推送通知响铃),其他平台播放 ringtone_in.ogg;
- 🎵 有人加入/离开时播放
joined_call.ogg、left_call.ogg提示音; - 🎙️ 即使不在通话中按下静音快捷键,也会播放反馈音,方便用户确认快捷键生效。
想动手看看?核心文件路径清单
| 模块 | 路径 |
|---|---|
| VoIP 抽象接口(组件/会话/流) | commet/lib/client/components/voip/ |
| WebRTC 1v1 通话 | commet/lib/client/matrix/components/voip/ |
| LiveKit 群组通话后端 | commet/lib/client/matrix/components/voip_room/ |
| 通话管理(铃声/通知/快捷键) | call_manager.dart |
| 通话 UI(来电/通话中视图) | commet/lib/ui/organisms/call_view/ |
| 依赖声明(livekit_client、flutter_webrtc) | pubspec.yaml |
写在最后:Commet 这套方案能教会我们什么?
Commet 的 VoIP 实现给了开源项目一个很好的参考范式:信令交给 Matrix 房间与 to-device 事件,媒体交给 WebRTC/LiveKit,加密交给密钥环 + 前向保密,三者各司其职。
- 🤝 小型通话:P2P 直连,链路最短、隐私最佳;
- 🏢 群组通话:LiveKit SFU 承担扇出,客户端只拉自己需要的流;
- 🧩 抽象层
VoipComponent/VoipSession让 UI 与底层引擎彻底解耦,未来替换或新增后端(比如换一家 SFU 厂商)几乎不用动界面代码。
如果你想给 Matrix 客户端加上自己的语音视频通话能力,或者想深入 Matrix 通话协议,从上面这张路径清单出发,按"抽象接口 → 后端实现 → UI 层"的顺序阅读源码,就是最高效的路线。
【免费下载链接】commet
Your space to connect
相关推荐
海尔智能家居设备如何无缝集成到HomeAssistant生态系统
海尔智能家居设备如何无缝集成到HomeAssistant生态系统 在智能家居生态系统中,设备兼容性一直是困扰技术爱好者的核心难题。不同品牌设备之间的协议差异、A
智能家居物联网零基础入门:用Electron-React-Boilerplate构建高效WebRTC音视频通话应用全指南
零基础入门:用Electron React Boilerplate构建高效WebRTC音视频通话应用全指南 Electron React Boilerplate
示例工程前端PhoneRTC终极指南:如何在Cordova应用中实现WebRTC音视频通话
PhoneRTC终极指南:如何在Cordova应用中实现WebRTC音视频通话 PhoneRTC是一个专为Cordova移动应用设计的WebRTC插件,让开发者
即时通讯移动开发音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考