reactjs - 正确处理麦克风音频的 React Hooks
问题描述
我正在尝试编写一个 React Hook 来将流式音频处理到使用 Meyda 分析的 AudioContext。
我已经设法让流工作并且能够提取我想要的数据。但是,我无法取消初始化音频。
如果有人可以为我提供一些正确设置此钩子的指导,我将不胜感激。
当我使用这些钩子离开页面时,我目前收到以下错误:
警告:无法对未安装的组件执行 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
,先判断状态是否为off,因为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]
}
推荐阅读
- git - 忽略对 git 中添加的文件的更新
- python - 在 Tensorflow 中,我如何 (1) 计算梯度和 (2) 更新 *separate* @tf.function 方法中的变量?
- flutter - 在下一个屏幕的顶部放置一个小部件?
- android - 指定的孩子已经有父母
- java - 将 Java 应用程序移动到 Spring Boot 会在读取资源时产生 java.io.FileNotFoundException
- java - 如何在 Stream API 中将 Enum 转换为 String?
- discord.js - Discord.js 斜线命令说缺少访问权限,即使我有“使用斜线命令”范围
- reactjs - 试图查看用户是否通过 useContext 进行了身份验证
- python - 断断续续的 Linux 网络摄像头视频
- python - 搞砸了 python 2.7.16 的 pip 并将其升级到 pip v 21.1.2