在线会议
  • TypeScript 74.5%
  • Go 25.1%
  • JavaScript 0.2%
  • Shell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-05 16:30:09 +08:00
cmd/e2e Exercise isolated server restart on Windows and Linux 2026-10-03 10:20:40 +08:00
deploy Add codec and UDP call verification and single-interface RTC example 2026-10-04 23:40:58 +08:00
frontend fix: enforce camera codec negotiation and hide waiting tile at two participants 2026-10-05 12:21:21 +08:00
.gitignore Implement Go backend with persistent rooms and media moderation 2026-10-03 09:30:01 +08:00
codec_compatibility.go Add per-camera device matrix and H265 with moderator-controlled codecs 2026-10-04 07:52:40 +08:00
control_flow_test.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
database.go Retain screen publications across subscription changes and preserve pending media sync 2026-10-05 02:16:14 +08:00
device_scans.go Reuse account-scoped device reports from cloud for seven days 2026-10-04 14:46:06 +08:00
device_scans_test.go Refresh restored presets on mount and keep newer scans during recovery 2026-10-04 14:50:56 +08:00
go.mod Implement Go backend with persistent rooms and media moderation 2026-10-03 09:30:01 +08:00
go.sum Implement Go backend with persistent rooms and media moderation 2026-10-03 09:30:01 +08:00
HANDOFF.md docs: record camera codec diagnosis and frontend verification 2026-10-05 12:26:03 +08:00
http.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
ice_diagnostics.go Add correlated media and server diagnostics; preserve resolution during network FPS adaptation 2026-10-04 06:35:51 +08:00
logging.go Report real decode failures and detect paced hardware video sending 2026-10-04 23:36:38 +08:00
main.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
maintenance.go Implement Go backend with persistent rooms and media moderation 2026-10-03 09:30:01 +08:00
media.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
media_actions.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
media_actions_test.go Document the control-first flow and verify durable sync after reload 2026-10-05 02:22:48 +08:00
meeting_policy.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
meeting_policy_test.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
permissions.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00
permissions_test.go Restrict codec reports to moderators and decouple meeting audio from video layout 2026-10-05 01:40:49 +08:00
README.md docs: summarize Hola project progress and remaining validation 2026-10-05 16:30:09 +08:00
reception.go Report real decode failures and detect paced hardware video sending 2026-10-04 23:36:38 +08:00
reception_test.go Report real decode failures and detect paced hardware video sending 2026-10-04 23:36:38 +08:00
rooms.go Retain screen publications across subscription changes and preserve pending media sync 2026-10-05 02:16:14 +08:00
server_diagnostics.go Add correlated media and server diagnostics; preserve resolution during network FPS adaptation 2026-10-04 06:35:51 +08:00
server_diagnostics_test.go Add per-camera device matrix and H265 with moderator-controlled codecs 2026-10-04 07:52:40 +08:00
server_test.go Add independent screen sharing and personal call regression coverage 2026-10-03 17:11:29 +08:00
start.sh Remove Python and P2P paths; add browser recovery and isolated Go test runner 2026-10-03 09:44:08 +08:00
websocket.go Confirm media policies before SFU admission and simplify meeting controls 2026-10-05 02:12:19 +08:00

Hola 私人会议

Hola 是面向个人使用的 Web 视频会议项目,支持多设备入会、会议权限管理、摄像头通话与屏幕共享。当前以 Web 为主,采用 Go、React/TypeScript 和 LiveKit,已在杭州服务器上线。

当前进展

核心 Web 功能和“先确认权限、再连接媒体”的链路已部署,H.264、AV1 的真实 SFU 收发已有回归验证。Windows–Android 的 H.265 摄像头互通仍需真机复测,不能宣布所有设备上的视频功能已完全稳定。

项目 状态
业务后端 Go,运行版本 49c2f95;已替换旧 Python 服务
Web 前端 React/TypeScript,运行版本 00c7b85
媒体服务 LiveKit 1.13.7,SFU 转发,服务器不转码
数据存储 SQLite,持久保存账号、会话、会议、设备报告及待同步媒体操作
部署 Linux 宿主机进程,hola.service 与 start.sh 管理,暂不使用 Docker
最近完成 严格编码协商、黑屏提示、共享统计、两人隐藏加号
APP 暂未开发,当前继续集中处理 Web

项目按个人使用、目标不超过 20 人设计。已有 20 设备信令测试,但不等于完成 20 路高画质视频容量验收。

已完成功能

账号、会议与历史

  • 登录与管理员账号管理,公开注册关闭。
  • 随机 6 位房间码,支持公开会议与带密码的私密会议。
  • 每个账号可设置唯一的 8 位个人码,作为固定私密入口;点击数字即可复制。
  • 主持人可将公开会议转为私密会议、设置或重设密码;在线成员保持连接,新成员按新规则验证。
  • 主持人离开后会议继续;最后一个设备离开 30 分钟后自动结束。
  • 历史记录展示时间、时长及累计参会人数,支持分页;切换页面时会议可保持连接并缩为悬浮窗。

大厅与观看界面

  • 大厅包含快速加入、会议与在线设备统计、正在进行的会议、设备预设和最近会议。
  • 创建、加入前显示确认弹窗,可主动预览本机摄像头;取消或入会前释放预览采集。
  • 正在进行的会议每 5 秒静默刷新,手动刷新才显示按钮忙碌状态;历史页每次加载 30 条。
  • PC 支持网格与主视角;手机采用主画面和可横向滚动的预览列表,当前选择高亮。
  • 竖屏视频完整显示在横向预览框内,全屏时适配屏幕。
  • 网格仅在 1 台参会设备时显示灰色加号,主持人也计入人数,达到 2 台即隐藏;共享画面不增加人数。
  • 主持人、联席可向当前成员发出一次主画面切换,成员随后仍可自行切走。
  • 全屏支持旋转、视频信息、切换摄像头及自己的音视频、分辨率和目标帧率控制。

多设备与权限

同一账号可从多台设备加入,每场会议可选择自己的主设备。普通成员选择主设备不会增加权限;主持人、联席的管理与高画质资格随主设备转移。

能力 主持人主设备 联席主设备 普通成员
选择自己的主设备 支持 支持 支持
修改会议编码 支持 支持 不支持
查看完整设备能力、兼容汇总及执行反馈 支持 支持 不支持
禁用、恢复普通成员的视频 支持 支持 不支持
向全员切换一次主画面 支持 支持 不支持
选择 2K、4K 摄像头档位 按设备能力 按设备能力 不支持
踢人、管理联席、移交主持、管理会议隐私及结束会议 支持 不支持 不支持

平台管理员负责账号管理、运行状态查看与强制结束会议。管理员身份不会自动获得会议内的完整设备汇总或主持权限。后端规则集中于 permissions.go,前端依服务端授权展示操作;角色、主设备迁移或撤销后,详情权限同步变化。

设备检测与云端复用

  • 先获取摄像头、麦克风信息,再对每个摄像头检查 24 个组合:3 种编解码 × 4 档分辨率 × 2 个目标帧率。
  • 结合实际采集约束、浏览器能力和本机 WebRTC 编解码短测。格式预测失败继续实际测试;短测低帧率记录性能提示,不直接等同于不支持。
  • 默认优先选择实测可用的 1080p60 H.265,缺少该组合时按可用组合选择,兼容格式优先 H.264。
  • 首次检测前预设禁用,有有效报告后只提供实际通过的组合。
  • 格式预测最多 8 路并发;实际采集、编解码逐路运行,避免检测任务相互争抢。同分辨率 60/30 帧复用回环连接。
  • 报告按账号与浏览器标识在本机、云端隔离保存,有效 7 天,读取不延期。登录后优先复用本机报告,否则尝试云端恢复。
  • 设备标识为本站保存的随机 UUID,表示浏览器实例,并非硬件序列号。换浏览器、无痕访问或清除完整站点数据可能需要重新检测。
  • 复用前核对检测版本、时间、浏览器及设备信息;支持手动重新扫描。自动恢复不请求采集权限,不改变正在发送的视频方案。
  • 完整扫描不是入会门槛,零可用组合也不直接禁止摄像头。 开启时仍按会议选择的编码实际尝试发布。

控制与媒体链路

权限和规则通过 Go 业务接口与 WebSocket 确认,视频由浏览器编码后经 LiveKit 转发。

flowchart LR
    W[Web 客户端] <-->|登录、入会、能力、规则与反馈| G[Go 业务服务]
    G <-->|持久化| D[(SQLite)]
    G -->|发布源权限、踢出、结束会议| L[LiveKit SFU]
    W <-->|规则确认后连接 WebRTC 音视频| L
  1. 浏览器登录并加入会议,建立业务 WebSocket,报告设备编解码能力。
  2. Go 根据角色、主设备、禁视频状态与参会设备数,下发带版本的媒体规则。
  3. 前端确认规则后申请 SFU 凭证,服务端在发放时再次核验权限。
  4. 浏览器连接媒体服务,按需开启采集;每台设备反馈规则应用中、成功或失败。
  5. 权限变化重新下发规则,忽略过期反馈;完整设备详情只发送给有权限的管理设备。

会议规则与待执行的 SFU 操作在同一 SQLite 事务中保存。媒体调用不持有会议状态锁,失败时明确显示待同步并每 5 秒重试,重启后继续处理。

音频播放独立于视频布局。可见视频和主画面保持订阅,屏幕外视频可暂停订阅并在重新可见时恢复,音频继续播放。摄像头与共享分别发布、展示和统计。

视频规则

项目 当前方案
摄像头格式 AV1、H.265、H.264,已移除 VP9
分辨率 720p、1080p、2K(2560×1440)、4K(3840×2160)
目标帧率 30、60 FPS,实际性能取决于采集、编码与网络
普通成员 5 台及以下最高 1080p60;超过 5 台限制为 720p30,人数回落后恢复原选择
主持人、联席主设备 按设备能力最高 4K60,不随人数改变档位
屏幕共享 独立 H.264,请求 1920×1080、30 FPS,码率上限 5 Mbps
转码与备用流 服务器不转码,摄像头只发布所选编码的单路流,无备用编码流

创建会议采用个人编码预设,加入已有会议服从会议方案。只有主持人、联席的主设备可以手动修改会议编码。设备不兼容、能力未知或档位未通过时提醒管理设备,不自动切编码。

发布前严格限制协商格式,运行中再次核对实际发送编码;与会议方案不一致时停止该路摄像头并报告失败,避免界面显示已开启却发送另一格式。

网络受限时只降低发送帧率上限,按 60→30→15 调整;采集目标、保存的 30/60 帧目标和分辨率保持不变,网络恢复后逐档尝试回到目标。单纯采集或编码低帧率不会直接作为网络拥塞处理。人数导致的普通成员画质限制属于会议规则,与网络调帧分开执行。

浏览器仍可能自行降低实际发送尺寸;应用检测到持续低于所选分辨率时停止视频并提示手动调整。SFU 凭证约束发布源权限,像素和帧率规则由官方网页执行,并非针对自制客户端的服务器像素硬限制。

诊断与待解决问题

现有诊断能力

  • 全屏信息分别显示摄像头发送、共享发送及各路接收的实际编码、分辨率、FPS、间隔码率与延迟。共享每 3 秒采样,码率需要两次样本,换轨后重新测量。
  • 收到数据却未能解码或解码停止时,窗口显示原因;管理设备收到实际接收故障反馈,恢复后清除。
  • 自动采集浏览器、系统、可用设备信息、前后台状态、采集参数、编解码实现、帧计数、耗时、丢包、冻结与 ICE 路径。
  • 服务端采集机器、相关进程负载和 TCP/UDP 诊断;匿名 STUN 包头辅助分析 UDP。
  • 支持本机 Debug 导出与诊断录制;正常自动日志不要求开启录制,录制会额外消耗性能。
日志文件(/opt/Hola/logs/) 内容
meeting-diagnostics.jsonl 入会、摄像头收发、调帧与故障事件
browser-diagnostics.jsonl 客户端采集、连接、协商与规则执行事件
server-diagnostics.jsonl 服务端负载、进程与网络诊断

上述日志为 0600,每类保留当前文件及 3 份轮转文件,每份约 20 MB。应用诊断过滤密码、令牌和原始 SDP;浏览器提供的信息无法直接确定精确 CPU 型号、温度或持续硬件性能。

尚未关闭的问题

  1. 安卓 H.265 摄像头黑屏。 2026-10-05 真机日志出现“请求 H.265、实际发送 VP8”,及“接收 H.265 已有 2835 个包,解码帧数为 0”。严格协商约束、故障提示、帧组装与关键帧日志已上线,最终跨设备互通仍需双方刷新后复测。主持人可手动选择 H.264 对照,系统不自动换码。
  2. 1080p60/30 的持续性能。 当前重点是 H.265/H.264 常用档位。能力声明、短测和芯片型号不能保证长期通话帧率,4K60 AV1 等高档位也需要独立实测。
  3. 安卓 Chrome 网页发起屏幕共享。 项目依赖 getDisplayMedia(),该浏览器没有提供手机屏幕采集能力;观看他人共享可以继续使用,原生安卓采集方案尚未开发。
  4. 移动端后台、锁屏和设备占用。 已加入前台恢复与有限重试,所有浏览器后台持续采集仍无法保证。
  5. 多人媒体容量。 当前杭州 SFU 出口约 200 Mbps,转发流量随观看人数增加。20 路信令测试不代表 20 路高画质视频稳定运行,其他服务器尚未接入媒体链路。

当前服务器的 UDP 网卡映射问题已修复,H.264、AV1 公网 UDP 收发已验证;移动网络仍可能走 TCP 后备。nps 暂未调整,其负载影响未经过干预对照,不能直接认定为低帧率根因。

已完成验证

验证项 已记录结果
最新前端单元测试 68 项通过
TypeScript、UI 漂移、生产构建 通过
最新隔离真实 SFU 回归 4 项通过,约 1.1 分钟
最新正式 HTTPS 回归 4 项通过,约 2.2 分钟
后端检查 当前 Go 代码已通过 test、vet、race;最近前端修复未修改 Go

最新回归覆盖两人隐藏加号、H.264 双向解码、手动 AV1 换码与重开摄像头、解码故障提示与恢复、编码不一致时停止、视频退订与恢复、音频持续、摄像头和共享并行及主持禁视频。

正常媒体经过真实浏览器编码、SFU 转发与远端解码;故障场景注入统计,共享选择器使用测试画布和音轨。测试 Chrome 未提供 H.265 编解码,这些结果不能替代安卓 H.265 真机验收,也不能证明物理摄像头持续达到 60 FPS。历次失败、复测及跳过项保留在 HANDOFF.md。

代码结构与开发

Hola/
├── main.go、http.go、websocket.go       # 服务入口、HTTP 与业务信令
├── rooms.go、permissions.go            # 会议状态与集中权限
├── meeting_policy.go、media_actions.go # 版本化规则与持久媒体操作
├── media.go                            # LiveKit 凭证、代理和管理接口
├── database.go、device_scans.go        # SQLite 与设备报告
├── logging.go、*diagnostics.go         # 应用与服务器诊断
├── frontend/src/                      # React 页面及会议功能
├── frontend/src/test/                 # Vitest 单元测试
├── frontend/tests/                    # Playwright 场景
├── cmd/e2e/                           # 独立数据库与进程的测试工具
├── deploy/                            # systemd 与 RTC 示例
└── HANDOFF.md                         # 发布与排障交接

后端使用 Go 1.26(以 go.mod 为准),前端使用 Node.js/npm,已使用 Node.js 24 构建。LiveKit 与浏览器媒体访问环境需另行准备。

在仓库根目录检查、构建后端:

go test ./...
go vet ./...
go build -o bin/hola .

在 frontend/ 安装依赖、检查和构建:

npm ci
npm run check
npm test
npm run build

完成后端、前端构建,并提供可访问的 LiveKit 和测试凭据后,在 frontend/ 执行 npm run test:e2e。该工具创建独立数据库与 Go 进程,不使用生产数据库。

环境变量 用途
HOLA_ROOT 数据与前端目录,默认 /opt/Hola
HOLA_ADDR Go 监听地址,默认 127.0.0.1:9009
HOLA_PUBLIC_URL 对外 HTTPS 地址,用于来源校验
LIVEKIT_URL LiveKit 管理接口,默认 http://127.0.0.1:7880
LIVEKIT_KEY、LIVEKIT_SECRET LiveKit 凭据,与媒体服务配置一致
HOLA_ADMIN_USER、HOLA_ADMIN_PASSWORD 空数据库首次初始化管理员,密码至少 8 位
HOLA_ALLOW_HTTP=1 本机 HTTP 测试模式,正式入口使用 HTTPS

部署与维护

正式目录 /opt/Hola,Go 监听 127.0.0.1:9009,现有 HTTPS 反向代理提供公网入口。LiveKit 信令经 Go 代理,媒体使用 UDP 50000,TCP 50010 为后备。

start.sh 加载私密 .env,启动 Go 与 LiveKit,Go 退出后可单独重启;deploy/hola.service 管理整套进程。RTC 示例 对应当前杭州服务器,迁移时需核对实际公网地址和网卡。

systemctl status hola
curl http://127.0.0.1:9009/health

/health 返回 Go 版本,不表示前端版本;运行清单分别为 runtime/release.json 与 runtime/frontend-release.json。前端采用原子目录交换并保留旧哈希资源,已有页面需刷新。Go 发布保留持久会话和会议状态,但可能短暂中断连接;整套服务重启影响媒体,发布前检查活动会议并备份。

最近前端备份为 /opt/Hola/backups/camera-codec-20261005-122221,发布与公网临时测试清理后原业务记录逐表 SHA256 一致,Go/LiveKit 均未重启。完整备份和回滚说明见 HANDOFF.md。

.env、数据库、私密配置、凭据、日志、运行目录、依赖与构建产物不提交。每次完成代码修改均提交、推送 Forgejo dev。

后续重点

后续开发以用户确认的范围为准,当前优先事项:

  1. 用实际 Windows/安卓设备对照 H.265、H.264 的 1080p60/30,结合编码、帧组装、关键帧和解码日志关闭黑屏问题。
  2. 对采集、硬件编码、网络和服务端负载进行对照,验证降帧及回升效果。
  3. 根据使用反馈继续优化 PC、手机操作,逐步验证高分辨率与多人容量。

安卓 APK、多服务器客户端配置和 APP 专属能力仍在方案阶段。继续坚持 Web 优先,稳定后再经确认进入 APP 开发。