From 33ee5bef6ef741d259bf4568a65512d6a468fac7 Mon Sep 17 00:00:00 2001 From: michal Date: Mon, 18 May 2026 17:12:22 +0200 Subject: [PATCH] feat: first impl of MEASN --- .../src/examples/AudioTag/AudioTag.tsx | 148 ++++++++++++++---- apps/fabric-example/ios/Podfile.lock | 2 +- .../audiodocs/docs/core/audio-context.mdx | 10 ++ .../docs/other/web-audio-api-coverage.mdx | 2 +- .../media-element-audio-source-node.mdx | 107 +++++++++++++ .../HostObjects/AudioContextHostObject.cpp | 20 ++- .../HostObjects/AudioContextHostObject.h | 1 + .../BaseAudioContextHostObject.cpp | 3 +- .../sources/AudioFileSourceNodeHostObject.h | 5 + .../AudioScheduledSourceNodeHostObject.cpp | 2 +- .../MediaElementAudioSourceNodeHostObject.cpp | 17 ++ .../MediaElementAudioSourceNodeHostObject.h | 17 ++ .../common/cpp/audioapi/core/AudioNode.cpp | 8 +- .../common/cpp/audioapi/core/AudioNode.h | 6 +- .../cpp/audioapi/core/BaseAudioContext.cpp | 21 +++ .../cpp/audioapi/core/BaseAudioContext.h | 5 +- .../core/sources/AudioFileSourceNode.cpp | 63 ++++++++ .../core/sources/AudioFileSourceNode.h | 30 ++++ .../sources/MediaElementAudioSourceNode.cpp | 49 ++++++ .../sources/MediaElementAudioSourceNode.h | 32 ++++ .../audioapi/core/utils/AudioGraphManager.cpp | 35 ++++- .../audioapi/core/utils/AudioGraphManager.h | 81 +++++----- .../common/cpp/audioapi/types/NodeOptions.h | 8 + .../common/cpp/test/CMakeLists.txt | 1 - packages/react-native-audio-api/src/api.ts | 2 + .../react-native-audio-api/src/api.web.ts | 2 + .../src/core/AudioContext.ts | 8 + .../src/core/MediaElementAudioSourceNode.ts | 31 ++++ .../src/development/react/Audio/Audio.tsx | 15 ++ .../react/Audio/AudioFileSourceNode.ts | 16 +- .../src/development/react/Audio/types.ts | 10 ++ .../react-native-audio-api/src/interfaces.ts | 5 + .../react-native-audio-api/src/mock/index.ts | 22 +++ .../src/web-core/AudioContext.tsx | 11 ++ .../web-core/MediaElementAudioSourceNode.tsx | 19 +++ 35 files changed, 708 insertions(+), 106 deletions(-) create mode 100644 packages/audiodocs/docs/sources/media-element-audio-source-node.mdx create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/MediaElementAudioSourceNodeHostObject.cpp create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/MediaElementAudioSourceNodeHostObject.h create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/core/sources/MediaElementAudioSourceNode.cpp create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/core/sources/MediaElementAudioSourceNode.h create mode 100644 packages/react-native-audio-api/src/core/MediaElementAudioSourceNode.ts create mode 100644 packages/react-native-audio-api/src/web-core/MediaElementAudioSourceNode.tsx diff --git a/apps/common-app/src/examples/AudioTag/AudioTag.tsx b/apps/common-app/src/examples/AudioTag/AudioTag.tsx index 7ff67d93c..ea8645f73 100644 --- a/apps/common-app/src/examples/AudioTag/AudioTag.tsx +++ b/apps/common-app/src/examples/AudioTag/AudioTag.tsx @@ -1,58 +1,140 @@ -import React, { useRef } from 'react'; -import { Button, View } from 'react-native'; +import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react'; +import { Text, useWindowDimensions, View } from 'react-native'; import { Audio, AudioTagHandle, } from 'react-native-audio-api/development/react'; +import { AudioContext, GainNode } from 'react-native-audio-api'; -import { Container } from '../../components'; +import { Button, Container, Slider, Spacer } from '../../components'; // const DEMO_AUDIO_URL = 'https://filesamples.com/samples/audio/m4a/sample4.m4a'; const DEMO_AUDIO_URL = 'https://filesamples.com/samples/audio/mp3/sample4.mp3'; const AudioTag: React.FC = () => { + const { width: screenWidth } = useWindowDimensions(); const audioRef = useRef(null); + const [sliderVolume, setSliderVolume] = useState(1); + const volumeRef = useRef(1); + const audioContextRef = useRef(new AudioContext()); + const gainNodeRef = useRef(null); - // const handlePlay = () => { - // audioRef.current?.play(); - // }; + const ensureMediaElementRoute = useCallback(() => { + if (!audioRef.current) { + throw new Error('Audio tag handle is not ready yet.'); + } - // const handlePause = () => { - // audioRef.current?.pause(); - // }; + const ctx = audioContextRef.current; + const mediaElementSource = ctx.createMediaElementSource(audioRef.current); + gainNodeRef.current = ctx.createGain(); + gainNodeRef.current.gain.value = volumeRef.current; - // const handleSeekToTime = (time: number) => { - // console.log('handleSeekToTime', time); - // audioRef.current?.seekToTime(time); - // }; + const biquad = ctx.createBiquadFilter(); + biquad.type = 'highpass'; + biquad.frequency.value = 5000; + mediaElementSource.connect(biquad); + biquad.connect(gainNodeRef.current); + gainNodeRef.current.connect(ctx.destination); + audioRef.current?.play(); + }, []); - // const handleSetVolume = (volume: number) => { - // audioRef.current?.setVolume(volume); - // }; + const handleVolumeChange = useCallback((nextVolume: number) => { + setSliderVolume(nextVolume); + volumeRef.current = nextVolume; + audioRef.current?.setVolume(nextVolume); + if (gainNodeRef.current) { + gainNodeRef.current.gain.value = nextVolume; + } + }, []); - // const handleSetMuted = (muted: boolean) => { - // audioRef.current?.setMuted(muted); - // }; + const handleLoadStart = useCallback(() => { + // console.log('onLoadStart'); + }, []); + const handleLoad = useCallback(() => { + // console.log('onLoad'); + }, []); + const handleError = useCallback((error: Error) => { + // console.log('onError', error); + }, []); + const handlePositionChange = useCallback( + (seconds: number) => { + // console.log('onPositionChange', seconds); + }, + [] + ); + const handleEnded = useCallback(() => { + // console.log('onEnded'); + }, []); + const handlePlay = useCallback(() => { + // console.log('onPlay'); + }, []); + const handlePause = useCallback(() => { + // console.log('onPause'); + }, []); + const handleVolumeEvent = useCallback( + (volume: number) => { + // console.log('onVolumeChange', volume); + }, + [] + ); + + const audioTagElement = useMemo( + () => ( +