Skip to content

fix: prevent double notification sound playback#11283

Open
hannesrudolph wants to merge 1 commit intomainfrom
fix/double-notification-sound
Open

fix: prevent double notification sound playback#11283
hannesrudolph wants to merge 1 commit intomainfrom
fix/double-notification-sound

Conversation

@hannesrudolph
Copy link
Collaborator

@hannesrudolph hannesrudolph commented Feb 7, 2026

Problem

Notification sounds sometimes play twice, with the second starting milliseconds after the first. This is caused by React <StrictMode> in webview-ui/src/index.tsx which intentionally double-fires effects in development builds. The sound-triggering useDeepCompareEffect in ChatView.tsx has no cleanup function, so StrictMode's mount → cleanup → mount cycle plays the sound twice. Since use-sound (Howler.js) defaults to interrupt: false, both audio instances play concurrently.

Root Cause Analysis

  • Systematically investigated and verified against source code across 6 analysis laps
  • Eliminated 5 alternative hypotheses (dual messages, multiple panels, partial transitions, Howler reinit, multiple setState)
  • Confirmed React StrictMode as the sole mechanism

Fix

Two layers of protection:

  1. interrupt: true on all useSound hooks — Tells Howler.js to stop any playing instance before starting a new one, preventing overlapping audio regardless of cause
  2. Ref-based debounce on playSound() — Tracks last-played timestamp per audio type, skips calls within 100ms window. Directly neutralizes StrictMode's double-fire

Testing

  • Added 2 new tests in ChatView.notification-sound.spec.tsx:
    • "should not play the same sound type twice within 100ms"
    • "should allow playing the same sound type again after 100ms"
  • All existing tests pass (30/30)

Files Changed

  • webview-ui/src/components/chat/ChatView.tsx
  • webview-ui/src/components/chat/__tests__/ChatView.notification-sound.spec.tsx

Important

Fix double notification sound playback by setting interrupt: true for useSound hooks and adding a debounce mechanism in ChatView.tsx.

  • Behavior:
    • Set interrupt: true for useSound hooks in ChatView.tsx to prevent overlapping audio.
    • Implement ref-based debounce in playSound() to skip sound playback within 100ms window.
  • Testing:
    • Added tests in ChatView.notification-sound.spec.tsx to verify sound is not played twice within 100ms and is played after 100ms.
    • Tests ensure no sound is played when there are queued messages or when the message is partial.
  • Files Changed:
    • ChatView.tsx
    • ChatView.notification-sound.spec.tsx

This description was created by Ellipsis for 7b2b6ca. You can customize this summary. It will automatically update as commits are pushed.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Feb 7, 2026
@roomote
Copy link
Contributor

roomote bot commented Feb 7, 2026

Oroocle Clock   See task

Review complete -- no issues found. The interrupt: true option is valid per use-sound v5 types, the ref-based debounce is correctly keyed per audio type, and both new tests pass alongside the existing 4.

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant