Fix live camera pose loading and relay buffer
这个提交包含在:
144
media/main.go
144
media/main.go
@@ -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
|
||||
|
||||
在新工单中引用
屏蔽一个用户