ReactJS录制时切换音视频设备仅新流被录制的解决方法咨询
React视频录制过程中切换音视频设备的实现方案
核心解决思路是不直接把每次获取的设备流绑定到MediaRecorder,而是创建一个固定的合成MediaStream作为录制器的输入源,切换设备时仅替换合成流内对应的音视频轨即可,无需中断录制。
实现步骤
1. 初始化合成流与录制器
首次启动录制时,创建空白合成流,将初始设备的音视频轨加入该流后再绑定到MediaRecorder:
import { useRef } from 'react' // 组件内用ref存储实例,避免state更新导致实例丢失 const mediaRecorderRef = useRef(null) const compositeStreamRef = useRef(null) const recordedChunksRef = useRef([]) const initRecording = async (initialAudioDeviceId, initialVideoDeviceId) => { // 获取初始设备流 const initialStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: initialAudioDeviceId }, video: { deviceId: initialVideoDeviceId } }) // 创建固定的合成流,后续仅修改该流的轨道 const compositeStream = new MediaStream() initialStream.getAudioTracks().forEach(track => compositeStream.addTrack(track)) initialStream.getVideoTracks().forEach(track => compositeStream.addTrack(track)) compositeStreamRef.current = compositeStream // 录制器仅绑定一次合成流 const mediaRecorder = new MediaRecorder(compositeStream, { mimeType: 'video/webm;codecs=vp9,opus' // 可根据兼容需求替换为对应格式 }) mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) recordedChunksRef.current.push(e.data) } mediaRecorderRef.current = mediaRecorder mediaRecorder.start() }
2. 切换设备逻辑
切换音频/视频设备时,仅获取对应设备的单轨道,替换合成流内的旧轨道即可:
// 切换音频设备 const switchAudioDevice = async (newAudioDeviceId) => { // 仅获取新设备的音频流 const newAudioStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: newAudioDeviceId }, video: false }) const newAudioTrack = newAudioStream.getAudioTracks()[0] const compositeStream = compositeStreamRef.current // 移除并停止旧音频轨,释放设备资源 const oldAudioTrack = compositeStream.getAudioTracks()[0] if (oldAudioTrack) { oldAudioTrack.stop() compositeStream.removeTrack(oldAudioTrack) } // 加入新音频轨,录制器会自动读取新轨内容 compositeStream.addTrack(newAudioTrack) } // 切换视频设备逻辑同理,仅需将audio相关替换为video即可 const switchVideoDevice = async (newVideoDeviceId) => { const newVideoStream = await navigator.mediaDevices.getUserMedia({ audio: false, video: { deviceId: newVideoDeviceId } }) const newVideoTrack = newVideoStream.getVideoTracks()[0] const compositeStream = compositeStreamRef.current const oldVideoTrack = compositeStream.getVideoTracks()[0] if (oldVideoTrack) { oldVideoTrack.stop() compositeStream.removeTrack(oldVideoTrack) } compositeStream.addTrack(newVideoTrack) }
注意事项
- 该方案兼容Chrome 80+、Firefox 76+、Safari 14.1+版本,覆盖绝大多数现代浏览器场景
- 如果需要兼容更老旧的浏览器,可使用降级方案:切换设备时停止当前录制,将已生成的视频片段暂存,用新设备流创建新的录制器继续录制,最后合并所有片段即可,缺点是切换时会有百毫秒级的间隙
- 设备切换成功后务必调用旧轨道的
stop()方法释放硬件资源,避免出现设备占用的异常
内容的提问来源于stack exchange,提问作者Amit Gupta
相关产品推荐
相关产品推荐

