视频会议保存
This commit is contained in:
@@ -67,6 +67,10 @@ type CreateProducerReq struct {
|
||||
TransportID string `json:"transportId"`
|
||||
Kind string `json:"kind"` // "audio" | "video"
|
||||
RtpParameters json.RawMessage `json:"rtpParameters"` // 直接转发给 Node,由其做结构校验
|
||||
// AppData 客户端自定义元信息,例如 {"screen": true} 表示该 Producer 是屏幕共享流
|
||||
// Phase 3 屏幕共享引入:与摄像头/麦克风 video Producer 同走 sendTransport,
|
||||
// 通过 appData.screen 区分,便于服务端识别并触发 meeting.screen.* 广播
|
||||
AppData json.RawMessage `json:"appData,omitempty"`
|
||||
}
|
||||
|
||||
// CreateConsumerReq 创建 Consumer 请求
|
||||
@@ -78,6 +82,38 @@ type CreateConsumerReq struct {
|
||||
RtpCapabilities json.RawMessage `json:"rtpCapabilities"`
|
||||
}
|
||||
|
||||
// ====== 会议录制 RPC(Phase B 引入)======
|
||||
|
||||
// StartRecordingReq 启动录制请求
|
||||
//
|
||||
// ProducerIDs 指定要录的若干 Producer,由业务层决定(Phase B1 通常是 host 的
|
||||
// audio + video 两个;Phase B3 扩展为屏幕共享 + 多人音频后会更多)
|
||||
type StartRecordingReq struct {
|
||||
RouterID string `json:"routerId"`
|
||||
RoomCode string `json:"roomCode"`
|
||||
ProducerIDs []string `json:"producerIds"`
|
||||
}
|
||||
|
||||
// StartRecordingResp media-server 启动成功后的响应
|
||||
type StartRecordingResp struct {
|
||||
RecordingID string `json:"recordingId"`
|
||||
OutputPath string `json:"outputPath"` // media-server 本地 mp4 路径,用于停止后回拉上传
|
||||
Tracks []struct {
|
||||
ProducerID string `json:"producerId"`
|
||||
Kind string `json:"kind"`
|
||||
} `json:"tracks"`
|
||||
}
|
||||
|
||||
// StopRecordingResp media-server 停止录制后返回的元数据
|
||||
type StopRecordingResp struct {
|
||||
RecordingID string `json:"recordingId"`
|
||||
OutputPath string `json:"outputPath"`
|
||||
SizeBytes int64 `json:"sizeBytes"`
|
||||
DurationMS int64 `json:"durationMs"`
|
||||
ExitCode *int `json:"exitCode,omitempty"` // ffmpeg 退出码;nil = 进程未启动到退出阶段
|
||||
FailureReason string `json:"failureReason,omitempty"` // 非空表示录制最终标记为 failed
|
||||
}
|
||||
|
||||
// MediaOrchestrator 媒体服务器编排接口(设计 §6.6 NodeClient)
|
||||
// Task 7 (2026-04-21) 起默认实现为 HTTPMediaOrchestrator(通过 X-Internal-Token
|
||||
// 调用 Node media-server 的 /internal/v1/* REST API)。
|
||||
@@ -122,6 +158,16 @@ type MediaOrchestrator interface {
|
||||
ResumeConsumer(ctx context.Context, consumerID string) error
|
||||
// CloseConsumer 关闭指定 Consumer(幂等)
|
||||
CloseConsumer(ctx context.Context, consumerID string) error
|
||||
|
||||
// ====== 录制(Phase B 引入)======
|
||||
|
||||
// StartRecording 在 media-server 上启动一份会议录制
|
||||
// 失败语义:404 RouterNotFound / 409 producerId 不可消费等返回 ErrMediaServerError
|
||||
// 成功返回 recordingId(hex32)+ media-server 本地 mp4 输出路径
|
||||
StartRecording(ctx context.Context, req *StartRecordingReq) (*StartRecordingResp, error)
|
||||
// StopRecording 停止录制
|
||||
// 幂等:媒体侧已结束(404)返回 ErrMediaResourceNotFound,调用方一般视为"已停止"
|
||||
StopRecording(ctx context.Context, recordingID string) (*StopRecordingResp, error)
|
||||
}
|
||||
|
||||
// NoopMediaOrchestrator 本地调试占位实现(Task 7 后默认不再使用)
|
||||
@@ -205,3 +251,18 @@ func (n *NoopMediaOrchestrator) ResumeConsumer(_ context.Context, _ string) erro
|
||||
func (n *NoopMediaOrchestrator) CloseConsumer(_ context.Context, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartRecording 占位:返回伪造 recordingId 与空 outputPath
|
||||
func (n *NoopMediaOrchestrator) StartRecording(_ context.Context, req *StartRecordingReq) (*StartRecordingResp, error) {
|
||||
return &StartRecordingResp{
|
||||
RecordingID: "noop-recording-" + req.RoomCode,
|
||||
OutputPath: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StopRecording 占位:返回零大小元数据
|
||||
func (n *NoopMediaOrchestrator) StopRecording(_ context.Context, recordingID string) (*StopRecordingResp, error) {
|
||||
return &StopRecordingResp{
|
||||
RecordingID: recordingID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user