Fix live camera pose loading and relay buffer

这个提交包含在:
cryptocommuniums-afk
2026-03-17 12:31:12 +08:00
父节点 f3f7e1982c
当前提交 597f16d0b9
修改 7 个文件,包含 268 行新增76 行删除

查看文件

@@ -61,8 +61,10 @@ const (
)
const (
relayPreviewWindow = 60 * time.Second
relayCacheTTL = 30 * time.Minute
defaultRelayBufferSeconds = 120
minRelayBufferSeconds = 10
maxRelayBufferSeconds = 300
relayCacheTTL = 30 * time.Minute
)
type PlaybackInfo struct {
@@ -93,36 +95,37 @@ type Marker struct {
}
type Session struct {
ID string `json:"id"`
UserID string `json:"userId"`
Title string `json:"title"`
Purpose SessionPurpose `json:"purpose"`
Status SessionStatus `json:"status"`
ArchiveStatus ArchiveStatus `json:"archiveStatus"`
PreviewStatus PreviewStatus `json:"previewStatus"`
Format string `json:"format"`
MimeType string `json:"mimeType"`
QualityPreset string `json:"qualityPreset"`
FacingMode string `json:"facingMode"`
DeviceKind string `json:"deviceKind"`
ReconnectCount int `json:"reconnectCount"`
UploadedSegments int `json:"uploadedSegments"`
UploadedBytes int64 `json:"uploadedBytes"`
PreviewSegments int `json:"previewSegments"`
DurationMS int64 `json:"durationMs"`
LastError string `json:"lastError,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
FinalizedAt string `json:"finalizedAt,omitempty"`
PreviewUpdatedAt string `json:"previewUpdatedAt,omitempty"`
StreamConnected bool `json:"streamConnected"`
LastStreamAt string `json:"lastStreamAt,omitempty"`
ViewerCount int `json:"viewerCount"`
LiveFrameURL string `json:"liveFrameUrl,omitempty"`
LiveFrameUpdated string `json:"liveFrameUpdatedAt,omitempty"`
Playback PlaybackInfo `json:"playback"`
Segments []SegmentMeta `json:"segments"`
Markers []Marker `json:"markers"`
ID string `json:"id"`
UserID string `json:"userId"`
Title string `json:"title"`
Purpose SessionPurpose `json:"purpose"`
Status SessionStatus `json:"status"`
ArchiveStatus ArchiveStatus `json:"archiveStatus"`
PreviewStatus PreviewStatus `json:"previewStatus"`
Format string `json:"format"`
MimeType string `json:"mimeType"`
QualityPreset string `json:"qualityPreset"`
FacingMode string `json:"facingMode"`
DeviceKind string `json:"deviceKind"`
ReconnectCount int `json:"reconnectCount"`
UploadedSegments int `json:"uploadedSegments"`
UploadedBytes int64 `json:"uploadedBytes"`
PreviewSegments int `json:"previewSegments"`
DurationMS int64 `json:"durationMs"`
RelayBufferSeconds int `json:"relayBufferSeconds"`
LastError string `json:"lastError,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
FinalizedAt string `json:"finalizedAt,omitempty"`
PreviewUpdatedAt string `json:"previewUpdatedAt,omitempty"`
StreamConnected bool `json:"streamConnected"`
LastStreamAt string `json:"lastStreamAt,omitempty"`
ViewerCount int `json:"viewerCount"`
LiveFrameURL string `json:"liveFrameUrl,omitempty"`
LiveFrameUpdated string `json:"liveFrameUpdatedAt,omitempty"`
Playback PlaybackInfo `json:"playback"`
Segments []SegmentMeta `json:"segments"`
Markers []Marker `json:"markers"`
}
func (s *Session) recomputeAggregates() {
@@ -140,14 +143,15 @@ func (s *Session) recomputeAggregates() {
}
type CreateSessionRequest struct {
UserID string `json:"userId"`
Title string `json:"title"`
Format string `json:"format"`
MimeType string `json:"mimeType"`
QualityPreset string `json:"qualityPreset"`
FacingMode string `json:"facingMode"`
DeviceKind string `json:"deviceKind"`
Purpose string `json:"purpose"`
UserID string `json:"userId"`
Title string `json:"title"`
Format string `json:"format"`
MimeType string `json:"mimeType"`
QualityPreset string `json:"qualityPreset"`
FacingMode string `json:"facingMode"`
DeviceKind string `json:"deviceKind"`
Purpose string `json:"purpose"`
RelayBufferSeconds int `json:"relayBufferSeconds"`
}
type SignalRequest struct {
@@ -231,6 +235,9 @@ func (s *sessionStore) refreshFromDisk() error {
if session.Purpose == "" {
session.Purpose = PurposeRecording
}
if session.Purpose == PurposeRelay {
session.RelayBufferSeconds = normalizeRelayBufferSeconds(session.RelayBufferSeconds)
}
session.recomputeAggregates()
}
s.mu.Lock()
@@ -281,23 +288,29 @@ func cloneSession(session *Session) *Session {
func (s *sessionStore) createSession(input CreateSessionRequest) (*Session, error) {
now := time.Now().UTC().Format(time.RFC3339)
purpose := SessionPurpose(defaultString(input.Purpose, string(PurposeRecording)))
relayBufferSeconds := 0
if purpose == PurposeRelay {
relayBufferSeconds = normalizeRelayBufferSeconds(input.RelayBufferSeconds)
}
session := &Session{
ID: randomID(),
UserID: strings.TrimSpace(input.UserID),
Title: strings.TrimSpace(input.Title),
Purpose: SessionPurpose(defaultString(input.Purpose, string(PurposeRecording))),
Status: StatusCreated,
ArchiveStatus: ArchiveIdle,
PreviewStatus: PreviewIdle,
Format: defaultString(input.Format, "webm"),
MimeType: defaultString(input.MimeType, "video/webm"),
QualityPreset: defaultString(input.QualityPreset, "balanced"),
FacingMode: defaultString(input.FacingMode, "environment"),
DeviceKind: defaultString(input.DeviceKind, "desktop"),
CreatedAt: now,
UpdatedAt: now,
Segments: []SegmentMeta{},
Markers: []Marker{},
ID: randomID(),
UserID: strings.TrimSpace(input.UserID),
Title: strings.TrimSpace(input.Title),
Purpose: purpose,
Status: StatusCreated,
ArchiveStatus: ArchiveIdle,
PreviewStatus: PreviewIdle,
Format: defaultString(input.Format, "webm"),
MimeType: defaultString(input.MimeType, "video/webm"),
QualityPreset: defaultString(input.QualityPreset, "balanced"),
FacingMode: defaultString(input.FacingMode, "environment"),
DeviceKind: defaultString(input.DeviceKind, "desktop"),
RelayBufferSeconds: relayBufferSeconds,
CreatedAt: now,
UpdatedAt: now,
Segments: []SegmentMeta{},
Markers: []Marker{},
}
s.mu.Lock()
defer s.mu.Unlock()
@@ -311,6 +324,23 @@ func (s *sessionStore) createSession(input CreateSessionRequest) (*Session, erro
return cloneSession(session), nil
}
func normalizeRelayBufferSeconds(value int) int {
if value <= 0 {
return defaultRelayBufferSeconds
}
if value < minRelayBufferSeconds {
return minRelayBufferSeconds
}
if value > maxRelayBufferSeconds {
return maxRelayBufferSeconds
}
return value
}
func relayPreviewWindowForSession(session *Session) time.Duration {
return time.Duration(normalizeRelayBufferSeconds(session.RelayBufferSeconds)) * time.Second
}
func parseSessionTime(values ...string) time.Time {
for _, value := range values {
if strings.TrimSpace(value) == "" {
@@ -967,7 +997,7 @@ func (m *mediaServer) handleSegmentUpload(sessionID string, w http.ResponseWrite
sortSegmentsBySequence(session.Segments)
if session.Purpose == PurposeRelay {
var kept []SegmentMeta
kept, removedSegments = trimSegmentsToDuration(session.Segments, relayPreviewWindow)
kept, removedSegments = trimSegmentsToDuration(session.Segments, relayPreviewWindowForSession(session))
session.Segments = kept
}
session.Status = StatusRecording