Skip to content

feat(audio): sync background notification volume with video player#1429

Open
theglove44 wants to merge 3 commits into
CaptainFact:stagingfrom
theglove44:fix/sync-notification-volume-with-player
Open

feat(audio): sync background notification volume with video player#1429
theglove44 wants to merge 3 commits into
CaptainFact:stagingfrom
theglove44:fix/sync-notification-volume-with-player

Conversation

@theglove44
Copy link
Copy Markdown

Fixes CaptainFact/captain-fact#93

What changed

Three small, focused changes:

VideoPlaybackContext.jsx — adds volume (default 1) to the playback state, a SET_VOLUME reducer case, and a setVolume action that only dispatches when the value actually changes.

VideoDebatePlayer.jsx — adds syncVolume, which reads the current volume from the internal player on each onProgress event and on onReady. Supports HTML5 <video> (player.volume, 0–1) and YouTube iframe API (player.getVolume(), 0–100). For HTML5 video it also attaches a native volumechange DOM listener so volume changes while paused are captured immediately — no polling needed.

BackgroundNotifier.jsx — reads volume from useVideoPlayback() and applies it (audioFile.volume = volume) to every notification sound before .play().

Why this approach

  • No setInterval polling — volume is sampled on existing player events plus a native DOM listener.
  • No redundant dispatches — setVolume is a no-op when the value has not changed.
  • Cross-provider — handles YouTube and HTML5 video.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="app/components/App/BackgroundNotifier.jsx" line_range="60-66" />
<code_context>

   // Handle sound enable/disable and statement focus changes
   useEffect(() => {
+    const playSound = (audioFile) => {
+      audioFile.volume = volume
+      audioFile.play()
+    }
+
</code_context>
<issue_to_address>
**suggestion:** Guard against play failures and ensure `Audio` state is safe for rapid successive calls.

Shared `Audio` instances can throw or return rejected promises on `play()` (e.g., autoplay policies, rapid preference toggles), and overlapping plays may share state. Consider wrapping `audioFile.play()` in a minimal guard/try-catch (ignoring failures if acceptable) and resetting `audioFile.currentTime = 0` before `play()` so repeated notifications consistently start from the beginning.

```suggestion
  // Handle sound enable/disable and statement focus changes
  useEffect(() => {
+    const playSound = (audioFile) => {
+      if (!audioFile) return
+
+      audioFile.volume = volume
+
+      try {
+        // Ensure rapid successive calls always start from the beginning
+        audioFile.currentTime = 0
+
+        const playPromise = audioFile.play()
+
+        // Guard against browsers returning a rejected play() promise
+        if (playPromise && typeof playPromise.then === 'function') {
+          playPromise.catch(() => {
+            // Intentionally ignore playback failures (e.g., autoplay restrictions)
+          })
+        }
+      } catch {
+        // Intentionally ignore synchronous playback errors
+      }
+    }
+
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread app/components/App/BackgroundNotifier.jsx
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7d58c261a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +59 to +63
useEffect(() => {
return () => {
internalPlayerRef.current?.removeEventListener?.('volumechange', syncVolume)
}
}, [syncVolume])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reattach volumechange listener after first volume update

This cleanup effect depends on syncVolume, so whenever syncVolume gets a new identity (which happens after setVolume updates context state), React runs this cleanup and removes the native volumechange listener—but nothing adds a new listener at that point because listener registration only happens in onReady. In practice, paused-volume tracking works once, then stops after the first volume change, so background notification volume can become stale until playback resumes.

Useful? React with 👍 / 👎.

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.

Adapt background sound volume based on video volume

1 participant