Files
EchoChat/docs/plans/2026-05-18-recording-progress.md
2026-05-18 19:42:55 +08:00

108 lines
5.0 KiB
Markdown
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.

# 会议录制实现进度Phase B1→B4
启动日期2026-05-18
负责人Cascade pair-programming session
## 全局架构
```
[host 工具栏] → POST /meeting/rooms/{code}/recording/toggle
[Go MeetingRecordingService]
├─ 校验 host 权限 + 会议状态
├─ 落库 meeting_recordings(status=recording)
└─ 调 HTTPMediaOrchestrator.StartRecording(roomCode, producerIDs)
[media-server /internal/v1/recordings]
├─ 为每个 Producer 建 PlainTransportrtcpMux:false, comedia:false
├─ consume 该 Producer 拿到 negotiated rtpParameters
├─ 选未占用 UDP 端口对rtp+rtcp给 ffmpeg
├─ 写 SDP 文件(含 audio/video pt、codec、rtpmap、fmtp
├─ spawn ffmpeg: -protocol_whitelist file,udp,rtp -i input.sdp -c copy output.mp4
└─ transport.connect({ ip, port: ffmpegPort, rtcpPort: ffmpegRtcpPort })
[ffmpeg 写盘 → /tmp/recordings/{recordingId}.mp4]
[host 再次 toggle → 停止]
├─ media-server SIGINT ffmpeg → wait exit → close transports/consumers
├─ POST /api/v1/meeting/_internal/recordings/{id}/finalizecallback
└─ Go 流式拉取 mp4 → MinIO → 落库 status=ready + file_url + size + duration
[WS 广播 meeting.recording.started/stopped 给所有成员]
```
## 阶段拆分
### Phase B1 — 媒体层录制管线 + Go 控制端 ✏️ 进行中
**media-server**
- [ ] `services/recording.service.ts`起停录制、SDP 生成、ffmpeg 进程管理、端口池
- [ ] `routes/recording.route.ts``POST /internal/v1/recordings``DELETE /internal/v1/recordings/:id``GET /internal/v1/recordings/:id`
- [ ] `schemas/recording.schema.ts`zod 校验
- [ ] `app.ts`:注册路由
- [ ] 端口池实现 `utils/port-pool.ts`
**Go 后端**
- [ ] `app/meeting/model/meeting_recording.go`:表 ORM
- [ ] `app/meeting/dao/meeting_recording_dao.go`
- [ ] `app/meeting/service/interfaces.go` 扩展 MediaOrchestrator: `StartRecording / StopRecording`
- [ ] `app/meeting/service/http_media_orchestrator.go` 实现 RPC
- [ ] `cmd/server/main.go` AutoMigrate 加入 MeetingRecording
### Phase B2 — 业务层 + 持久化
- [ ] `service/meeting_recording_service.go`StartRecording/StopRecording/ListRecordings/GetRecording
- [ ] `controller/meeting_controller.go` 新增 4 个端点
- [ ] `router.go` 挂载路由
- [ ] `provider.go` wire 注册
- [ ] 内部回调端点 `/_internal/recordings/{id}/finalize`media-server 录完后回调Go 拉文件→ MinIO → 更新 DB
- [ ] MinIO 流式上传
### Phase B3 — WS 广播 + 自动停录
- [ ] `constants/meeting.go`MeetingWSEventRecordingStarted/Stopped
- [ ] `meeting_signal_service.go` / `meeting_broadcaster.go` 广播
- [ ] EndRoom / HandleEmptyRoomExpired 自动 StopRecording
- [ ] 前端 `constants/meeting.js` + store 监听
### Phase B4 — 前端 UI
- [ ] `MeetingToolbar.vue`:录制按钮(仅 host 可见)+ 红点动画
- [ ] `room.vue`:顶部"REC"指示条(任意成员都可见)
- [ ] 新页面 `pages/meeting/recordings.vue`:列表 + 下载
## 已知风险与决策
1. **ffmpeg 必须可用**:媒体服务的运行环境(开发:本地 PATH生产Docker 镜像 apt install ffmpeg。Dockerfile 暂不改,由你部署时确认。
2. **PlainTransport 端口分配**:用 dgram 试探可用 UDP 端口;初始范围 50000-59999避开 mediasoup `40000-40199`
3. **ffmpeg 启停时序**:录制启动顺序 = 起 ffmpeg(listen) → 100ms 延迟 → mediasoup transport.connect → consume停止顺序 = SIGINT ffmpeg → wait exit → close transports/consumers。
4. **录制视频编码**:用 `-c:v copy -c:a copy` 直接复制 RTP 载荷为 mp4不重编码节省 CPU。注意浏览器端 VP8/VP9 muxed 进 mp4 可能不被普通播放器识别,必要时改 `-c:v libx264 -preset ultrafast`。本期先用 copy。
5. **DB 表 schema**:参考下方 §SQL。
6. **Phase B 整体不强制阻塞**:每完成一个阶段都可以暂停验证。
## SQL
```sql
CREATE TABLE meeting_recordings (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
room_id BIGINT UNSIGNED NOT NULL,
room_code VARCHAR(32) NOT NULL,
started_by BIGINT UNSIGNED NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'recording', -- recording/uploading/ready/failed
remote_id VARCHAR(64), -- media-server 侧的 recordingId
file_url VARCHAR(512),
file_object VARCHAR(255),
size_bytes BIGINT UNSIGNED DEFAULT 0,
duration_sec INT UNSIGNED DEFAULT 0,
failure_reason VARCHAR(255),
started_at DATETIME NOT NULL,
stopped_at DATETIME,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
KEY idx_room (room_id),
KEY idx_room_code (room_code),
KEY idx_started_by (started_by)
);
```
## 当前会话进度
- ✅ 调研完成MinIO 已就绪、media-server 架构吃透、HTTPMediaOrchestrator 模式吃透
- ⏩ 下一步:写 media-server 端口池 + recording.service.ts