Skip to content

Measure Jim's audio and keep his volume - #442

Merged
jserv merged 2 commits into
mainfrom
feat/preflight-audio-controls
Oct 23, 2026
Merged

jserv merged 2 commits into
mainfrom
feat/preflight-audio-controls

Conversation

@jserv

@jserv jserv commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Candidates could not turn Jim down or mute him, and the browser smoke could pass while no interviewer audio arrived. This adds two changes, one commit each. Preflight microphone and output selection is left to #411, which this PR no longer duplicates.

Interviewer audio diagnostics in the browser probe: LiveKit receiver counters and decoded RMS for the track attached as Jim are measured separately, so missing observations, transport silence and decoded silence are reported as different outcomes. A generation whose track ends before Speaking or within its first second is superseded rather than judged on a cut-short window, and the last generation must pass.

Jim volume and mute: a positive volume persists across reloads while mute stays session-only, a single step up from the muted slider restores the saved level, and preferences are reapplied whenever Jim's audio attaches, reconnects or recovers through Resume audio. The Meet manual check now resets the volume before recording, since tab audio follows it.

After #411 merges, this branch needs a rebase with one deliberate reconciliation: #411 keeps a fresh Jim element muted until output routing settles, while this PR reapplies the candidate's mute on attach and restores it on unsolicited volume changes. Combined naively, each undoes the other, so the rebase must hold the element muted during routing and then apply the volume preferences. The only textual conflict is the Meet manual-check step list.

Verified with scripts/test.sh: 1540 tests pass, including the Chromium volume, layout and WebRTC loopback probe tests. The only failing gate is skill-refs, caused by an untracked skill directory in the local checkout that is not part of this branch. Each commit passes its own suites. Not covered: audible level and a live Meet capture, which need hardware and an operator run.

cubic-dev-ai[bot]

This comment was marked as resolved.

@jserv
jserv force-pushed the feat/preflight-audio-controls branch from 998a714 to aab6677 Compare October 23, 2026 07:26
@jserv jserv changed the title Add microphone choice, Jim volume and audio probe Measure Jim's audio and keep his volume Oct 23, 2026
jserv added 2 commits October 23, 2026 15:32
Transcript order and a Speaking pill could pass the browser smoke while
the candidate received no audio packets or decoded only silence. Probe
the public LiveKit receiver stats for the native track attached as Jim,
and separately measure its decoded RMS during Speaking. Keep unavailable
observations distinct from observed silence and retain the failed
measurements in the capture before refusing the run.

Bound receiver waits, sampling windows and subscription counts. Keep
counter baselines within one receiver and Speaking interval, discard
late results from replaced tracks, and require healthy evidence after
resubscription. A generation whose track ends within its first second is
superseded rather than judged on a cut-short window, while a longer one
keeps its failure. A slow AudioContext resume does not hold up or end
sampling. Do not infer physical audibility or word delivery from these
counters. Install through CDP so the probe respects the real page CSP
without requiring inline scripts or disabling the policy.

Validate with controlled counter, silence, reset, timeout, cancellation
and subscription tests, plus a Chromium WebRTC tone loopback under the
restrictive CSP using the vendored SDK. Removing the late-track and
Speaking-gap guards makes their regressions fail. The isolated full gate
and final focused checks pass; live LiveKit/Gemini acceptance still
needs an operator-selected isolated configuration and budget.
Candidates could route Jim to a speaker but could not attenuate or mute
him locally. Remember a validated positive volume and keep mute within
the current page, so reload restores the last positive level. Expose a
labelled slider, a fixed-name mute toggle, a reset and a persistent
muted indicator. A single step up from the muted slider unmutes at the
saved level instead of saving 1%. Keep mute available when volume
setters are unsupported, moving focus before hiding the unusable slider.

Apply preferences whenever Jim's audio attaches or returns after a
subscription change. Restore unsolicited SDK volume changes, including
an unmute without a playback-status event. Reapply synchronously during
Resume audio and after its promises settle so a stalled or stale
startAudio cannot leave playback unmuted while the UI claims otherwise.
Remove the element listener when its attachment goes away.

Expanded audio controls and playback warnings could cover report-wait
actions on a short phone screen. Bound and scroll the compact stage, and
reserve its measured height in the wait instead of fixed padding. Keep
recovery reachable by keyboard inside the clipped stage.

Preference, readback, attachment, recovery and DOM checks pass, as do
Chromium keyboard, reload and phone-layout checks. Removing either SDK
unmute restoration or synchronous recovery reapply makes its regression
fail. The full gate covers this and the audio probe together. Physical
audible-level and remote Meet-capture observations remain operator
acceptance work; the interface identifies that possible effect, and the
Meet manual check now resets the volume before recording.
@jserv
jserv force-pushed the feat/preflight-audio-controls branch from aab6677 to 5301df5 Compare October 23, 2026 07:41
@jserv
jserv merged commit 3bb4b11 into main Oct 23, 2026
10 checks passed
@jserv
jserv deleted the feat/preflight-audio-controls branch October 23, 2026 08:14
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