/** * useVideoSoundControl Hook * * Manages video sound state with iOS autoplay compatibility. * Videos start muted to ensure autoplay works on iOS WebKit browsers, * then can be unmuted by user interaction. * * iOS WebKit autoplay policy: * - Videos CAN autoplay if they have `playsinline` AND `muted` attributes * - Unmuted videos require user interaction → native play button appears * - By forcing muted start + custom sound button, we avoid native controls */ import { useState, useCallback, useRef, useEffect } from 'react'; import { logger } from '../lib/logger'; export interface UseVideoSoundControlOptions { /** Whether page settings allow sound (background_video_muted === false) */ pageHasSound: boolean; /** Whether page has a background video */ hasBackgroundVideo: boolean; /** Current video URL - used to detect page changes (optional) */ videoUrl?: string; } export interface UseVideoSoundControlResult { /** Current muted state (always starts true for iOS compatibility) */ isMuted: boolean; /** Whether to show sound toggle button */ showSoundButton: boolean; /** Toggle muted state */ toggleSound: () => void; /** Force muted state (for page changes) */ setMuted: (muted: boolean) => void; } /** * Hook for managing video sound state with iOS autoplay compatibility. * * @example * const { isMuted, showSoundButton, toggleSound } = useVideoSoundControl({ * pageHasSound: selectedPage?.background_video_muted === false, * hasBackgroundVideo: Boolean(backgroundVideoUrl), * }); * * // Pass to RuntimeControls * * * // Pass to CanvasBackground (always muted for autoplay) * */ export function useVideoSoundControl({ pageHasSound, hasBackgroundVideo, videoUrl, }: UseVideoSoundControlOptions): UseVideoSoundControlResult { // Always start muted for iOS autoplay compatibility const [isMuted, setIsMuted] = useState(true); // Track previous video URL to detect page changes const prevVideoUrl = useRef(videoUrl); // Reset to muted when video changes (page navigation) // This ensures iOS autoplay works on every page - new videos always start muted useEffect(() => { // Only reset if there's a new video (URL changed and we have a video) if (prevVideoUrl.current !== videoUrl && videoUrl) { setIsMuted(true); logger.debug('[useVideoSoundControl] Video changed, resetting to muted', { from: prevVideoUrl.current?.slice(-20), to: videoUrl?.slice(-20), }); } prevVideoUrl.current = videoUrl; }, [videoUrl]); const toggleSound = useCallback(() => { setIsMuted((prev) => { logger.debug('[useVideoSoundControl] Toggle sound:', { from: prev, to: !prev, }); return !prev; }); }, []); return { isMuted, // Show button only if page allows sound AND has a background video showSoundButton: pageHasSound && hasBackgroundVideo, toggleSound, setMuted: setIsMuted, }; } export default useVideoSoundControl;