OBSERVERTC / Client Monitor
Collection & sampling
Follow the update lifecycle and understand the sample boundary.
Collection and sampling do different jobs
Collection reads browser statistics and updates live metrics and detectors. Sampling packages the current state and buffered records for your backend. You can collect more frequently than you send samples.
For example, collecting every second and sampling every five seconds lets a local diagnostics view update quickly while reducing network traffic. Each sample contains the current snapshot, not an average of all five updates.
const monitor = new ClientMonitor({
collectingPeriodInMs: 1000,
samplingPeriodInMs: 5000,
});Choose a sampling interval that is a multiple of the collection interval. A value of zero disables the corresponding automatic operation. For manual sampling, enable bufferingEventsForSamples if events, issues, and metadata should be included.
What happens during collection
The browser supplies statistics, adapters normalize browser differences, the monitor updates connections and tracks, and detectors evaluate their evidence. Scores are then updated and stats-collected is emitted. A scheduled sample follows when it is due.
Detailed lifecycle
RtcPeerConnectionStatsCollector.getStats()calls the real browser API;convertRTCStatsReport()keeps reports with id, timestamp and type. Mediasoup has its own collector and bindings. Bind a device before transports are created, or attach existing transports explicitly.- PC adapters run before dispatch. Chromium folds legacy fields and infers missing references. Safari additionally normalizes old data-channel IDs and pair-state spellings. Firefox can reconstruct a missing transport from its selected candidate pair, maintaining totals across pair changes. Inferred/reconstructed values must be labeled separately from browser-native measurements.
- PC accept calculates
deltaTimefrom successive maximum stats timestamps, resets PC aggregates, dispatches reports with a retry pass for unresolved ordering, updates references/path state, then runs PC and ICE-transport detectors. - Root collection aggregates PCs, feeds its window, updates tracks and their detectors, runs root detectors, updates scores, expires extension monitors, emits
stats-collected, and possibly emits a sample. - Collection defaults to 5000 ms. Sampling defaults to 5000 ms and is collection-count-driven:
max(1, floor(samplingPeriod/collectingPeriod)). A non-integral ratio warns and floors. Zero disables the relevant automatic mechanism.createSample()remains callable manually. A sample contains current stat snapshots and buffered discrete records; it is not a time average of all intervening monitor values. close()tears down sources/timers, resolves lifecycle state, optionally records departure and emits a final sample before closing. Opt-in pre-subscriber buffering preserves samples until the first subscriber; it is off by default.- Live track-associated RTP/source monitors are retained when a report is omitted. Ended and pending tracks are cleaned up.
Source references
- client-monitor-js/src/collectors/RtcPeerConnectionStatsCollector.ts
- client-monitor-js/src/collectors/MediasoupTransportStatsCollector.ts
- client-monitor-js/src/adapters/ChromeStatsAdapter.ts
- client-monitor-js/src/adapters/FirefoxStatsAdapter.ts
- client-monitor-js/src/adapters/SafariStatsAdapter.ts
- client-monitor-js/src/monitors/PeerConnectionMonitor.ts · _acceptAdaptedStats
- client-monitor-js/src/ClientMonitor.ts · _setSamplingTick
- client-monitor-js/CHANGELOG.md
Wire projection
A createSample() call drains buffered events, issues, metadata and extension entries. It does not serialize every live property, nor average all collection intervals. See the schema mapping.
When automatic sampling is disabled, set bufferingEventsForSamples: true if manual samples must include discrete records. Otherwise events and metadata return before buffering; local issue emission is independent.