fix: wip for ios

This commit is contained in:
MAZE 2025-02-18 19:42:05 +03:30
parent 699f49bfa3
commit 54b46123b4

View file

@ -20,6 +20,58 @@ import { FADE_OUT } from '@/constants/events';
import type { Sound } from '@/data/types'; import type { Sound } from '@/data/types';
import { subscribe } from '@/lib/event'; import { subscribe } from '@/lib/event';
/**
* =========================================
*/
declare global {
interface Window {
__howlerStreamPatched?: boolean;
}
}
/**
* Patches Howler's master gain node to stream its output into a hidden HTML audio element.
* This helps prevent iOS from suspending audio when the app goes into the background.
*/
export function setupAudioStream(): void {
if (
typeof window !== 'undefined' &&
Howler.ctx &&
!window.__howlerStreamPatched
) {
const audioCtx = Howler.ctx;
const masterGain = Howler.masterGain;
// Create a MediaStream destination node to capture the AudioContext output.
const streamDestination = audioCtx.createMediaStreamDestination();
// Disconnect the master gain from its default destination.
masterGain.disconnect();
// Reconnect the master gain to both the default destination and the stream destination.
masterGain.connect(audioCtx.destination);
masterGain.connect(streamDestination);
// Create a hidden HTML audio element to play the captured stream.
const audioElement = document.createElement('audio');
audioElement.setAttribute('playsinline', 'true'); // essential for iOS
audioElement.srcObject = streamDestination.stream;
audioElement.style.display = 'none';
document.body.appendChild(audioElement);
// Attempt to play the audio element. Note that iOS requires a user gesture.
audioElement.play().catch((err: unknown) => {
console.error('Failed to play background stream:', err);
});
// Mark the stream as patched so we dont run this code again.
window.__howlerStreamPatched = true;
}
}
/**
* =========================================
*/
export function App() { export function App() {
const categories = useMemo(() => sounds.categories, []); const categories = useMemo(() => sounds.categories, []);
@ -86,6 +138,19 @@ export function App() {
return [...favorites, ...categories]; return [...favorites, ...categories];
}, [favoriteSounds, categories]); }, [favoriteSounds, categories]);
useEffect(() => {
const handleUserInteraction = () => {
setupAudioStream();
document.removeEventListener('click', handleUserInteraction);
};
document.addEventListener('click', handleUserInteraction);
return () => {
document.removeEventListener('click', handleUserInteraction);
};
}, []);
return ( return (
<SnackbarProvider> <SnackbarProvider>
<StoreConsumer> <StoreConsumer>