Introduce streamHealth instrumentation for Golibrtsp to track per-stream metrics (write durations, gaps, lost packets, decode errors) and emit immediate warnings and periodic summaries to distinguish downstream back-pressure from upstream camera/network stalls. Wire gortsplib Client hooks (OnPacketsLost, OnDecodeError) to the health logger, label streams, and measure WritePacket blocking time around packet writes. Add packetAgeString helper and augment Kerberos ControlAgent logs with stalled counters and last-packet age to provide more context when triggering restarts.
Compute and propagate per-sample composition time offsets (PTS - DTS) so fragmented MP4s remain decode-timestamp-monotonic while preserving presentation order for B-frame streams. Changes include:
- Add a dtsExtractor interface and compositionOffsetMs helper to extract DTS from H264/H265 access units using mediacommon extractors (safe no-op if extraction fails).
- Compute composition offsets for H264 and H265 packet handlers and store them in Packet.CompositionTime. Preserve decoded AU for H265 before Annex-B rewriting for correct DTS extraction.
- Introduce writeSampleToMP4 helper to centralize writing logic; derive DTS = PTS - compositionOffset when present and call MP4.AddSampleToTrack accordingly.
- Change MP4.AddSampleToTrack signature to accept compositionOffset and write it into sample.CompositionTimeOffset so players (MSE) can present samples in PTS order while fragments use DTS.
- Update tests to pass the new compositionOffset argument.
This ensures proper playback of streams with frame reordering (B-frames) in browsers and other fragmented-MP4 consumers.
When the agent configuration is provided via environment variables (e.g. Kubernetes ConfigMap in factory standalone/configmap mode) there is no separate custom config from MongoDB. Add logic in OverrideWithEnvironmentVariables to copy configuration.Config into configuration.CustomConfig when DEPLOYMENT is unset or set to "agent", so UI/consumers that read the per-agent custom configuration (such as the factory agent edit page) see the env-injected values instead of an empty config.
UploadKerberosHub used a bare http.Client with no CheckRedirect policy, so
it followed redirects automatically. net/http strips the standard sensitive
headers on a cross-host redirect but not custom-named headers, so the Hub
credentials carried in X-Kerberos-Hub-PrivateKey / X-Kerberos-Hub-PublicKey
were forwarded verbatim to any host the configured HubURI redirected to,
disclosing the private key.
Add a CheckRedirect policy that deletes the Hub credential headers when the
redirect target host differs from the original request host.
Signed-off-by: tonghuaroot <tonghuaroot@gmail.com>
Add LastKeyframeGapMs to MP4 state and update fragment-flush logic to consider the previous keyframe gap before forcing a fragment boundary. Previously any unexpectedly short keyframe gap (< MinNormalGOPMs) would force a flush, which could cascade on streams that legitimately emit short GOPs. Now we only force a flush when the current gap is short and the prior gap was healthy (or unset), and we record the current gap for future checks. Also refactor the check to use a local gap variable and preserve the existing log message.
Add a MinNormalGOPMs constant (950 ms) and use it to detect unusually close consecutive IDRs; when a keyframe arrives sooner than this threshold and the current fragment is still short, force a fragment flush to isolate the seam and avoid mid-fragment sync samples. Replace the previous hardcoded 500 ms check in mp4.go and add TestMP4LoopSeamIsolation to reproduce the loop-seam pattern and assert that seam IDRs are isolated into their own fragments.
Track LastKeyframeRawPTS and force a fragment flush when two consecutive keyframes on the video track arrive unexpectedly close (<500ms). This detects upstream loop/restart discontinuities (e.g. ffmpeg stream_loop seams) where a fresh IDR would otherwise become a mid-fragment sync sample and cause MSE players to reject the fragment. Emits a warning when triggered and updates LastKeyframeRawPTS for video samples. Also add a sample MP4 file to machinery/data.
Guard against large forward PTS/DTS jumps that can occur when looping source MP4s or when upstream RTSP/ffmpeg inserts offsets/stalls. In flushPendingVideoSample() clamp an excessively large video sample duration to a plausible ceiling (1s hard cap, or LastVideoSampleDTS*10 if smaller), falling back to LastVideoSampleDTS or 33ms, and log a warning. In AddSampleToTrack() clamp audio sample durations if the new dts is >10x the previous audio DTS and log a warning. These changes prevent huge sample durations that cause trun/sidx/mvhd discontinuities and browser playback errors.
Add trailing commas to the arguments passed to fallbackToSDLiveview in ui/src/pages/Dashboard/Dashboard.jsx. This is a non-functional formatting change applied to the WebRTC initialization, ICE candidate handling, and connection-state fallback calls to align with the project's code style/formatter.
Clean up trailing commas and minor formatting in ui/src/pages/Dashboard/Dashboard.jsx. Adjusts object/argument commas and formatting around WebRTC message handling, peer connection setup, error handling, and SD liveview fallback callbacks to avoid potential syntax/lint issues.
Apply consistent formatting to ui/src/pages/Dashboard/Dashboard.jsx by adding trailing commas in object literals, function call argument lists, and callbacks (primarily around WebRTC handling and error messages). This is a non-functional style change to match the project's code style (e.g., Prettier/ESLint) and should not affect runtime behavior.
Remove the uuidv4 import and introduce a local createUUID helper that uses window.crypto.randomUUID when available and falls back to a v4-style generator. Update webrtcClientId and webrtcSessionId to use createUUID(), removing the external dependency while preserving UUID generation for WebRTC session/client IDs.
Add trailing commas to multi-line function calls and RTCPeerConnection instantiation in Dashboard.jsx for consistent formatting. In Media.scss remove an extra blank line and relocate the .media-filters__field:first-child rule to consolidate related styles. Purely stylistic/organizational changes with no intended behavior change.
Reformat code in ui/src/pages/Media/Media.jsx for readability: wrap long argument lists (getTimestampFromInput, buildEventFilter) and reflow the appliedFilter ternary onto multiple lines. Also add the missing trailing newline to ui/public/locales/en/translation.json. No functional changes.
Switch MQTT client to persistent sessions by setting CleanSession to false, enabling ResumeSubs and using an in-memory store. Previously CleanSession was true and resume/store were commented out, which could drop subscriptions on reconnect; these changes ensure subscriptions are preserved across reconnects and re-subscribed from memory.