perf(meeting-detector): gate the depth-25 AX walk on recent audio#3957
Merged
Conversation
The meeting detector ran scan_process (a depth-25 accessibility-tree walk, every node a synchronous cross-process AX IPC) on each running meeting-capable app every 5-10s, gated only by screen-lock and app-presence, never by audio. The worst case is the common case: with no meeting there is no signal to early-break on, so it walks every window to full depth, forever, finding nothing. For an always-open browser with a huge web AX tree that is the dominant steady-state non-model CPU cost. screenpipe already computes per-chunk audio activity (RMS-thresholded) and called MeetingDetector::on_audio_activity, but that hook was a no-op and is_in_audio_session() was a circular wrapper around the v2 flag the detector itself sets. This wires the existing signal into a real recency stamp and gates the idle scan cadence on it: - Idle + meeting apps open + recent audio -> fast idle rate (10s, unchanged) - Idle + meeting apps open + silent -> quiet rate (30s), ~3x fewer walks - audio onset (quiet->active) wakes the loop immediately, so a call that just started is scanned at once and detection latency does NOT regress - Confirming/Active/Ending: unchanged; a tracked meeting is never slowed The state machine (advance_state) is untouched, so all existing detector tests pass unchanged. With no detector (tests / detector disabled) the cadence is byte-identical to the prior behaviour. Inspired by fastrepl/anarlog (hyprnote), which keys meeting detection off audio-device activity rather than UI walking. Tests: +4 engine gate tests, +4 audio recency tests (incl. one pinning that the signal is independent of the v2 flag). audio 6/6 pass; engine 102 pass / 0 fail / 2 pre-existing ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collaborator
Author
|
Pushed a format-only follow-up (9fa6176) for the Code Quality failure. Local validation: \cargo fmt --all -- --check, \cargo test -p screenpipe-audio meeting_detector --lib, and \cargo test -p screenpipe-engine meeting_detector --lib\ all pass. Fresh CI is running. |
Contributor
Meeting-detection evalSource:
flap = Ending → Active oscillations inside one meeting. controls-flap = controls reappeared; audio-flap = output audio kept it alive. High controls-flap = brittle scan; high audio-flap = legitimate but watch for drift. See Assertion details |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The meeting detector runs
scan_process— a depth-25 accessibility-tree walk (every node a synchronous cross-process AX IPC) — on each running meeting-capable app every 5–10s, gated only by screen-lock and app-presence, never by audio.The worst case is the common case: with no meeting there's no signal to early-break on, so it walks every window to full depth, forever, finding nothing. For an always-open browser with a huge web AX tree that's the dominant steady-state non-model CPU cost (it showed up as a top continuous non-model consumer in live sampling).
screenpipe already computes per-chunk audio activity (RMS-thresholded) and calls
MeetingDetector::on_audio_activity— but that hook was a no-op, andis_in_audio_session()was a circular wrapper around the v2 flag the detector itself sets. This wires the existing-but-discarded signal into a real recency stamp and gates the idle scan cadence on it.Inspired by fastrepl/anarlog (hyprnote), which keys meeting detection off audio-device activity rather than UI walking.
The change (idle scan cadence)
Why detection accuracy cannot regress
advance_state) is untouched → all existing detector tests pass unchanged.Tests
screenpipe-audio: 6/6 (4 new recency tests, incl. one pinning the signal is independent of the v2 flag — no circular dep).screenpipe-engine: 102 passed / 0 failed / 2 pre-existing ignored (4 new gate tests + the existingadvance_statesuite, all green).Validation status
Files
crates/screenpipe-audio/src/meeting_detector.rs— realon_audio_activityrecency stamp +audio_onsetNotify+audio_active_within()/wait_for_audio_onset().crates/screenpipe-engine/src/meeting_detector.rs—IDLE_QUIET_SCAN_INTERVAL+ pureapps_present_scan_interval()+ audio-onsetselect!arm.🤖 Generated with Claude Code
A rendered before/after diagram is available (HTML→PNG) — gist hosting rejected the binary, so the ASCII timeline above stands in. Happy to attach the image inline if you'd prefer it.