正确处理麦克风音频的 React Hooks

2024-04-30

我正在尝试编写一个 React Hook 来处理流音频到 AudioContext,并使用 Meyda 进行分析。

https://meyda.js.org/ https://meyda.js.org/

我已经设法使流正常工作并能够提取我想要的数据。但是,我在取消初始化音频时遇到问题。

如果有人能为我提供一些有关正确设置此挂钩的指导,我将不胜感激。

当我使用这些钩子离开页面时,当前收到以下错误:

警告:无法对已卸载的组件执行 React 状态更新。这是一个空操作,但它表明应用程序中存在内存泄漏。要修复此问题,请取消 useEffect 清理函数中的所有订阅和异步任务。

我尝试在钩子末尾添加清理功能,但我的尝试经常以音频立即切断或出现任何其他奇怪的错误而结束。

带 Meyda 分析仪的麦克风音频挂钩

export const useMeydaAnalyser = () => {

    const [running, setRunning] = useState(false);
    const [features, setFeatures] = useState(null);
    const featuresRef = useRef(features);
    const audioContext = useRef(new AudioContext());

    const getMedia = async() => {
        try {
            return await navigator
                .mediaDevices
                .getUserMedia({audio: true, video: false});
        } catch(err) {
            console.log('Error:', err);
        }
    };

    useEffect(
        () => {
            const audio = audioContext.current;
            let unmounted = false;
            if(!running) {
                getMedia().then(stream => {
                    if (unmounted) return;
                    setRunning(true);
                    const source = audio.createMediaStreamSource(stream);
                    const analyser = Meyda.createMeydaAnalyzer({
                        audioContext: audio,
                        source: source,
                        bufferSize: 1024,
                        featureExtractors: [
                            'amplitudeSpectrum',
                            'mfcc',
                            'rms',
                        ],
                        callback: nextFeatures => {
                            if(!isEqual(featuresRef.current, nextFeatures)) {
                                setFeatures(nextFeatures);
                            }
                        },
                    });
                    analyser.start();
                });
            }
            return () => {
                unmounted = true;
            }
        },
        [running, audioContext],
    );

    useEffect(
        () => {
            featuresRef.current = features;
        },
        [features],
    );

    return features;
};

音频视图

import React, {useEffect} from 'react';
import { useMeydaAnalyser } from '../hooks/use-meyda-audio';

const AudioViewDemo = () => {
    const audioContext = new AudioContext();
    const features = useMeydaAnalyser(audioContext);

    useEffect(() => {
        // Todo: Handle Audio features
        console.log(features);
        // setAudioData(features);
    }, [features]);

    return (
        <div>
            RMS: {features && features.rms}
        </div>
    );
};

export default AudioViewDemo;


该错误应该是没有关闭导致的AudioContext。你需要关闭AudioContext在清理功能中。

使用前请注意AudioContext,确定状态是否关闭,因为getMedia是异步的,所以如果组件在加载后很快就被卸载,AudioContext使用时关闭。

const getMedia = async () => {
  try {
    return await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: false,
    })
  } catch (err) {
    console.log('Error:', err)
  }
}

const useMeydaAnalyser = () => {
  const [analyser, setAnalyser] = useState(null)
  const [running, setRunning] = useState(false)
  const [features, setFeatures] = useState(null)

  useEffect(() => {
    const audioContext = new AudioContext()

    let newAnalyser
    getMedia().then(stream => {
      if (audioContext.state === 'closed') {
        return
      }
      const source = audioContext.createMediaStreamSource(stream)
      newAnalyser = Meyda.createMeydaAnalyzer({
        audioContext: audioContext,
        source: source,
        bufferSize: 1024,
        featureExtractors: ['amplitudeSpectrum', 'mfcc', 'rms'],
        callback: features => {
          console.log(features)
          setFeatures(features)
        },
      })
      setAnalyser(newAnalyser)
    })
    return () => {
      if (newAnalyser) {
        newAnalyser.stop()
      }
      if (audioContext) {
        audioContext.close()
      }
    }
  }, [])

  useEffect(() => {
    if (analyser) {
      if (running) {
        analyser.start()
      } else {
        analyser.stop()
      }
    }
  }, [running, analyser])

  return [running, setRunning, features]
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

正确处理麦克风音频的 React Hooks 的相关文章

  • 如何使用函数组件和 React Router v5 拦截 React SPA 中的后退按钮

    我正在 React 中的 SPA 中工作 不使用 React Router 来创建任何路由 我不需要允许用户导航到特定页面 想想多页调查问卷 按顺序填写 但是 当用户按下后退按钮时在浏览器上 我不希望他们退出整个应用程序 我希望能够在用户按
  • 有没有办法告诉你的反应应用程序页面何时完成加载页面/资产?

    我的反应应用程序中有一个脚本 我想在页面完全加载完成后运行该脚本 我尝试在 componentDidMount componentDidUpdate 中监听窗口加载 document onreadystatechange function
  • 鼠标输入时反应显示按钮

    我有一个反应组件 它包含如下方法 mouseEnter console log this is mouse enter render var album list const albums this props if albums user
  • 如何在React中处理多个路由器

    假设我们有一个网络应用程序 它通常有很多视图 例如索引页面 管理面板 帮助页面 联系人等 我在主index js 中使用react router dom 来处理它们 它工作得很好 但是现在我在开发管理面板时遇到了问题 它是 index js
  • 调用axios成功后如何更新页面?反应

    所以我正在做一个使用的项目Axios with Json server 但我有一个问题 每次我做Patch 我必须在主页上按 F5 才能更新 我想知道如何才能做到这一点 这样它就不会自动发生 My Patch onSubmitDate ev
  • 组件样式...是动态创建的。您可能会看到此警告,因为您在另一个组件内调用了 styled

    在 ReactJS 中使用 styled component 时 我在尝试动态生成样式时遇到以下问题 下面是错误信息 id 为 sc fzqyvX 的组件 styled div 已动态创建 您可能会看到此警告 因为您在另一个组件内调用了 s
  • 发布到 npm 时出现问题

    所以我尝试使用 React 构建一个开源项目并将其推送到 npm 问题是 我的组件虽然在测试环境中运行良好 安装到其他组件 但当我将其发布到 npm 并下载包并尝试访问它时 它给了我一个错误 这是代码的一个小示例 import React
  • 如何解构 React props 并仍然访问其他 props?

    我很好奇如果我想要所有的 props 但也想要解构单个属性 那么组件的参数 props 是否可以像导入一样解构 我想这更像是一个 JavaScript 问题 而不是一个 React 问题 但是举个例子 import React useEff
  • Next.js:如何将 source-map-explorer 与 Next.js 一起使用

    我想分析我的 Next js 构建源地图浏览器 https www npmjs com package source map explorer 有人可以帮我编写脚本吗 对于 React CRA 我使用以下脚本 build analyze n
  • 如何使用 jest 通过 Promise.all 设置多次提取测试

    我在测试中使用 jest 我正在使用 React 和 Redux 并且执行以下操作 function getData id notify return dispatch gt dispatch anotherFunction Promise
  • 移动浏览器中的 React 性能

    我有一个组件 表 其中包含许多行 其中包含数据编辑 其掩码形式为contenteditable 可以选择所有字段并同时更改所有行 在桌面上它运行得相当快 但在 iPhone 6 上我有不真实的滞后 Safari 每次操作都会挂起 20 秒
  • 网络音频 API:查找、播放/缓冲进度

    当您使用 Chrome 中的音频元素播放音频时 您会听到烦人的咔嗒声和破裂声 至少在我的 64 位 Linux 安装下 即使在我格式化并安装了新的 Fedora 版本之后也是如此 Firefox 和 Opera 都可以 甚至 Virtual
  • 错误:超出最大更新深度。反应状态

    我收到此错误 我猜是由于反应状态爆发 但我不知道这里出了什么问题 所以我有父子关系组件 如下所示 父组件 class App extends Component constructor props super props this stat
  • useEffect 中的 setTimeout 函数输出缓存的状态值

    这很简单 我正在使用 Redux 来管理我的状态 我有一个setTimeout函数在一个useEffect功能 The setTimeout超时值为50000ms 我想要 SetTimeout 处理程序做什么 After 50000ms t
  • React this.state 未定义?

    我正在遵循 Pluralsight 的初学者教程 在表单提交时将值传递给addUser组件方法 我需要将 userName 推送到this state users但我收到错误 App jsx 14 Uncaught TypeError Ca
  • React 组件等待所需的 props 渲染

    我正在父组件内部声明一个组件 我想在一个文件中建立特定的道具 然后在父组件中 我希望能够同时为子组件建立其他道具 因为它们是共享属性 在大多数情况下 我的问题是 子组件尝试渲染并失败 因为首先没有建立所需的道具类型 有没有办法告诉子组件等待
  • 如何将 hls.js 与 React 结合使用

    我需要一些帮助来尝试弄清楚如何在 React 中使用 hls js 让我解释一下我必须从 api 获取 m3u8 的情况我能够使用基本的 html 使其工作
  • 有没有办法在 Next.js 的 getStaticProps 中使用 redux 工具包?

    我使用时获取数据useEffect代替getStaticProps 但在getStaticProps它表明钩子只能在功能组件中使用 import Head from next head import Image from next imag
  • 在使用第三方东西时如何保持 Browserify 包大小合理(如果重要的话通过 grunt )

    我正在尝试捆绑我自己的代码 A 该代码又使用 2 个第三方组件 B 和 C 其中 C 也需要 B 据我所知 所有内容都是使用 CommonJS 节点样式模块编写的 捆绑后单独使用的价格为 60K B 是单独包含的 并假定是全局的 我通过在构
  • 你如何在react-native中实现捏合缩放?

    我一直在研究 PanResponder 我当前的工作假设是 我将检测是否有两个触摸正在向外移动 如果是 则增加元素大小onPanResponderMove功能 这似乎是一种混乱的方法 有没有更顺畅的方法呢 如果您只需要简单的捏缩放功能 只需

随机推荐