diff --git a/src/components/app/app.tsx b/src/components/app/app.tsx
index e0eee08..1ef6cd2 100644
--- a/src/components/app/app.tsx
+++ b/src/components/app/app.tsx
@@ -12,6 +12,7 @@ import { Categories } from '@/components/categories';
import { SharedModal } from '@/components/modals/shared';
import { Toolbar } from '@/components/toolbar';
import { SnackbarProvider } from '@/contexts/snackbar';
+import { SoundProvider } from '@/contexts/sound';
import { sounds } from '@/data/sounds';
import { FADE_OUT } from '@/constants/events';
@@ -86,17 +87,19 @@ export function App() {
}, [favoriteSounds, categories]);
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
);
}
diff --git a/src/contexts/sound.tsx b/src/contexts/sound.tsx
new file mode 100644
index 0000000..402e602
--- /dev/null
+++ b/src/contexts/sound.tsx
@@ -0,0 +1,73 @@
+import React, { createContext, useContext, useEffect, useState } from 'react';
+import { Howler } from 'howler';
+
+// Define the context's interface
+interface SoundContextType {
+ connectBufferSource: (bufferSource: AudioBufferSourceNode) => void;
+}
+
+// Create the SoundContext with an empty initial value
+const SoundContext = createContext(undefined);
+
+// Custom hook to use the SoundContext
+export const useSoundContext = (): SoundContextType => {
+ const context = useContext(SoundContext);
+ if (!context) {
+ throw new Error('useSoundContext must be used within a SoundProvider');
+ }
+ return context;
+};
+
+// Props for the SoundProvider component
+interface SoundProviderProps {
+ children: React.ReactNode;
+}
+
+export const SoundProvider: React.FC = ({ children }) => {
+ const [dest, setDest] = useState(
+ null,
+ );
+ const [audioTag, setAudioTag] = useState(null);
+
+ useEffect(() => {
+ if (typeof window !== 'undefined') {
+ // Get the Howler.js AudioContext after the component is mounted
+ const audioCtx = Howler.ctx;
+
+ if (audioCtx) {
+ const mediaDest = audioCtx.createMediaStreamDestination();
+ setDest(mediaDest);
+
+ // Create an audio element to trick iOS
+ const audioElement = document.createElement('audio');
+ audioElement.srcObject = mediaDest.stream;
+ audioElement.style.display = 'none'; // Hide the audio element
+ document.body.appendChild(audioElement);
+ setAudioTag(audioElement);
+
+ return () => {
+ // Clean up the audio element on unmount
+ document.body.removeChild(audioElement);
+ };
+ }
+ }
+ }, []);
+
+ // Function to connect a buffer source to the MediaStreamDestination
+ const connectBufferSource = (bufferSource: AudioBufferSourceNode) => {
+ if (dest) {
+ bufferSource.connect(dest);
+
+ // Start playing the audio once the first buffer connects
+ if (audioTag && audioTag.paused) {
+ audioTag.play().catch(() => console.error('Failed to play audio'));
+ }
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/hooks/use-sound.ts b/src/hooks/use-sound.ts
index 934092d..8baab42 100644
--- a/src/hooks/use-sound.ts
+++ b/src/hooks/use-sound.ts
@@ -5,6 +5,7 @@ import { useLoadingStore } from '@/stores/loading';
import { subscribe } from '@/lib/event';
import { useSSR } from './use-ssr';
import { FADE_OUT } from '@/constants/events';
+import { useSoundContext } from '@/contexts/sound';
/**
* A custom React hook to manage sound playback using Howler.js with additional features.
@@ -34,6 +35,8 @@ export function useSound(
const setIsLoading = useLoadingStore(state => state.set);
const { isBrowser } = useSSR();
+ const { connectBufferSource } = useSoundContext(); // Access SoundContext
+
const sound = useMemo(() => {
let sound: Howl | null = null;
@@ -43,6 +46,14 @@ export function useSound(
onload: () => {
setIsLoading(src, false);
setHasLoaded(true);
+
+ // Connect the buffer source to the MediaStreamDestination
+ // @ts-ignore
+ const source = sound!._sounds[0]._node.bufferSource;
+ if (source) {
+ console.log('DOOOOPE');
+ connectBufferSource(source);
+ }
},
preload: options.preload ?? false,
src: src,
@@ -50,7 +61,14 @@ export function useSound(
}
return sound;
- }, [src, isBrowser, setIsLoading, html5, options.preload]);
+ }, [
+ src,
+ isBrowser,
+ setIsLoading,
+ html5,
+ options.preload,
+ connectBufferSource,
+ ]);
useEffect(() => {
if (sound) {