From 4100d8a925fefb74507f24fdf289f72f7783077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C4=99k?= Date: Mon, 9 Feb 2026 15:15:31 +0100 Subject: [PATCH 1/2] feat: use audio context hook --- apps/common-app/src/App.tsx | 3 +- apps/fabric-example/ios/Podfile.lock | 2 +- .../src/core/AudioContext.ts | 2 + .../react-native-audio-api/src/hooks/index.ts | 1 + .../src/hooks/useAudioContext.tsx | 55 +++++++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 packages/react-native-audio-api/src/hooks/useAudioContext.tsx diff --git a/apps/common-app/src/App.tsx b/apps/common-app/src/App.tsx index 9bf407505..c877dc619 100644 --- a/apps/common-app/src/App.tsx +++ b/apps/common-app/src/App.tsx @@ -170,7 +170,8 @@ const App: FC = () => { headerTintColor: colors.white, headerBackTitle: 'Back', headerBackAccessibilityLabel: 'Go back', - }}> + }} + > (null); + +export const AudioContextProvider: React.FC = ({ + context, + options, + children, +}) => { + const rCtx = useMemo(() => { + if (context) { + return context; + } + + if (options) { + return new AudioContext(options); + } + + return getGlobalAudioContextInstance(); + }, [context, options]); + + return ( + + {children} + + ); +}; + +export function useAudioContext(): AudioContext { + const reactContext = useContext(ReactAudioContext); + + if (reactContext) { + return reactContext; + } + + return getGlobalAudioContextInstance(); +} From 7636b6ebc3a492ddf1da14f6059507d81da987ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C4=99k?= Date: Tue, 10 Feb 2026 15:37:55 +0100 Subject: [PATCH 2/2] feat: useAudioContext hook, state change event --- .../src/examples/LFCHooks/LFCHooks.tsx | 172 ++++++++++++++++++ .../src/examples/LFCHooks/index.tsx | 1 + apps/common-app/src/examples/index.ts | 8 + .../swmansion/audioapi/system/AudioEvent.kt | 1 + .../BaseAudioContextHostObject.cpp | 7 + .../HostObjects/BaseAudioContextHostObject.h | 3 + .../HostObjects/utils/JsEnumParser.cpp | 2 + .../common/cpp/audioapi/core/AudioContext.cpp | 2 +- .../cpp/audioapi/core/BaseAudioContext.cpp | 18 ++ .../cpp/audioapi/core/BaseAudioContext.h | 4 + .../common/cpp/audioapi/events/AudioEvent.h | 2 + .../src/core/BaseAudioContext.ts | 34 ++++ .../src/events/types.ts | 1 + .../src/hooks/useAudioContext.tsx | 36 +++- .../react-native-audio-api/src/interfaces.ts | 2 + 15 files changed, 283 insertions(+), 10 deletions(-) create mode 100644 apps/common-app/src/examples/LFCHooks/LFCHooks.tsx create mode 100644 apps/common-app/src/examples/LFCHooks/index.tsx diff --git a/apps/common-app/src/examples/LFCHooks/LFCHooks.tsx b/apps/common-app/src/examples/LFCHooks/LFCHooks.tsx new file mode 100644 index 000000000..67b65ae30 --- /dev/null +++ b/apps/common-app/src/examples/LFCHooks/LFCHooks.tsx @@ -0,0 +1,172 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { StyleSheet, Text, View } from 'react-native'; +import { + AudioBuffer, + AudioBufferSourceNode, + AudioContext, + AudioContextProvider, + useAudioContext, +} from 'react-native-audio-api'; + +import { Button, Container, Spacer } from '../../components'; + +type ComponentType = 'global' | 'provider' | 'customProvider'; + +const filePath = + 'https://software-mansion.github.io/react-native-audio-api/audio/voice/example-voice-01.mp3'; + +const ContextUserComponent: React.FC = () => { + const audioContext = useAudioContext(); + const [sampleBuffer, setSampleBuffer] = useState(null); + const [sourceNode, setSourceNode] = useState( + null + ); + const sourceNodeRef = useRef(null); + + useEffect(() => { + sourceNodeRef.current = sourceNode; + }, [sourceNode]); + + const onToggleState = async () => { + if (audioContext.state === 'suspended') { + await audioContext.resume(); + } else { + await audioContext.suspend(); + } + }; + + useEffect(() => { + async function prepareSample() { + const buffer = await audioContext.decodeAudioData(filePath); + setSampleBuffer(buffer); + } + + prepareSample(); + }, [audioContext]); + + const onPlaySample = () => { + if (!sampleBuffer) { + return; + } + + const node = audioContext.createBufferSource(); + node.buffer = sampleBuffer; + node.connect(audioContext.destination); + node.start(); + + setSourceNode(node); + }; + + const onStopSample = () => { + if (!sourceNode) { + return; + } + + sourceNode.stop(); + setSourceNode(null); + }; + + useEffect(() => { + return () => { + if (sourceNodeRef.current) { + sourceNodeRef.current.stop(); + } + }; + }, []); + + return ( + <> + state: {audioContext.state} + +