Skip to content

feat(stats): report audio echo-cancellation metrics in publisher stats - #3732

Open
raviteja83 wants to merge 3 commits into
mainfrom
publisher-stats-audio-aec-metrics
Open

feat(stats): report audio echo-cancellation metrics in publisher stats#3732
raviteja83 wants to merge 3 commits into
mainfrom
publisher-stats-audio-aec-metrics

Conversation

@raviteja83

@raviteja83 raviteja83 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Adds audio capture metrics to publisher stats from the audio media-source stat, which was previously resolved for video tracks only: echoReturnLoss and echoReturnLossEnhancement (the only signals indicating whether a canceller is applied to the capture path and how much echo it removes), total audio energy and samples duration, and capture level — each reported as a range with an observation count.

ERL/ERLE are reported as min/max per sample window rather than an average, since ERLE legitimately drops to 0 during double-talk and silence and a window mean makes an idle canceller indistinguishable from a working one. erle_distinct_count is 1 when the canceller reported a pinned value, read alongside erle_observed_count because a single observation also scores 1. Energy is reported independently of ERL/ERLE so that tracks published with echoCancellation disabled still carry capture evidence, and every counter delta is omitted rather than emitted as 0 or as a negative when the browser stops reporting it or the media-source is replaced. No level average is reported, since RMS is recoverable from the energy counters.

Also fixes the publisher and subscriber sample windows, which compared against the module constant and so ignored maxSampleWindowSize from init config.

The audio media-source stat carries echoReturnLoss and echoReturnLossEnhancement,
the only signals that say whether the browser's echo canceller is running and how
much echo it removes. media-source was previously resolved for video tracks only,
so neither field reached publisher stats.

Reports min/max per sample window rather than an average: ERLE legitimately drops
to 0 during double-talk and silence, so a window mean makes an idle canceller and
a working one look alike. erle_distinct_count is 1 when the value never moves
across the window, which separates "no software AEC running" from "AEC running".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard-app Ready Ready Preview Aug 12, 2026 8:34am

Request Review

…ure level

Audio tracks resolve a media-source for ERL/ERLE, which set sourceStatsAvailable
and let the video-only frame-counter branch run on audio samples. Those counters
coerce a missing value to 0, so every audio sample shipped source_total_frames: 0.
Gate that branch on track kind instead.

Capture energy was gated behind ERL/ERLE being present. ERL/ERLE only exist while
a software canceller runs, so a track published with echoCancellation disabled lost
its energy figures too — the cohort where "was the mic live at all" is the question.
Report energy independently, and omit it when the browser never reported the counter
so an absent metric is not indistinguishable from measured silence.

sourceAudioLevel was collected but never aggregated into a sample. Report it as a
range; no average, since RMS is already recoverable from the energy counters and
integrated rather than sampled at poll time.
…tric docs

differenceIfReported guarded the whole window while the subtraction reads only two
values: this window's last stat and the previous window's last stat. A counter that
stopped being reported mid-window emitted a fabricated 0, and a media-source replaced
by a device switch or plugin toggle emitted a large negative — which divides against a
negative duration to a plausible-looking RMS, reporting a loud mic during silence. It
now guards the two values it actually reads and treats a backwards counter as unknown.

The publisher and subscriber sample windows ignored the value plumbed in from init
config and compared against the module constant instead, so maxSampleWindowSize could
not take effect. Both now use the configured size, and the payload reports it rather
than the default.

buildAudioSourceStats no longer sets sourceStatsAvailable — that flag gates the video
frame counters, and setting it for audio required a compensating gate that also
narrowed video stats arriving without a kind. Audio media-source matching now accepts
mediaType alongside kind, matching the video helper, so an engine reporting only
mediaType does not silently lose every audio metric.

Adds erle_observed_count and audio_level_observed_count: a single observation scores
erle_distinct_count 1, previously indistinguishable from a canceller pinned across the
whole window. Drops the toFixed(3) rounding, a 0.001 dB tolerance defending against a
hazard three orders of magnitude below the smallest meaningful ERLE change.

Corrects PublishAnalyticPayload.video, which pointed at LocalAudioTrackAnalytics and so
asserted video tracks carry ERLE; the erle_distinct_count doc, which read 1 as "no
canceller" when that case has no ERLE fields at all; and the ERL/ERLE doc, which
inferred where cancellation happened from an absence the spec does not license.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant