React Web App在Safari及iPhone Chrome上无法捕获用户音频的问题
React Web App音频录制异常问题
我的React Web App前端音频录制捕获功能在Windows、Mac及Android的Chrome浏览器中可正常运行,但以下场景存在异常:
- iPhone设备上的Chrome浏览器
- Mac OS及iPhone设备上的Safari浏览器
相关核心代码如下:
const [mediaRecorder, setMediaRecorder] = useState(null); const [hasStarted, setHasStarted] = useState(false); const [chatStatus, setChatStatus] = useState(false); const id = useRef(uuid()); const audioChunksRef = useRef([]); const startRecording = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = (event) => { audioChunksRef.current.push(event.data); }; mediaRecorder.start(); setMediaRecorder(mediaRecorder); setIsRecording(true); } catch (error) { console.error('Error starting recording:', error); } }; const stopRecording = async () => { if (mediaRecorder) { mediaRecorder.onstop = async () => { const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/mp3', }); const formData = new FormData(); formData.append('audio', audioBlob, 'audio_recording.mp3'); formData.append('id', id.current); const response = await fetch(`${URL}/upload-audio`, { method: 'POST', body: formData, credentials: 'include', }).catch((error) => { console.error('Fetch error:', error); throw error; }); const { lastMessage, chatStatus } = await response.json(); console.log(lastMessage); setResponseText(lastMessage); setChatStatus(chatStatus); audioChunksRef.current = []; mediaRecorder.stream.getTracks().forEach((track) => track.stop()); setMediaRecorder(null); }; mediaRecorder.stop(); setIsRecording(false); } };
问题分析与修复方案
1. 格式兼容性问题
Safari(包括iPhone Chrome,其内核基于Safari)对audio/mp3支持有限,MediaRecorder默认生成的是audio/mp4(AAC编码)格式,强行指定mp3会导致录制失败或文件损坏。
修改Blob的MIME类型和文件名:
const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/mp4', }); formData.append('audio', audioBlob, 'audio_recording.mp4');
2. MediaRecorder初始化参数优化
Safari对MediaRecorder的构造参数要求更严格,需显式指定兼容的编码格式:
const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/mp4;codecs=mp4a.40.2' });
3. onstop事件绑定时机调整
Safari要求onstop事件必须在start()之前绑定,否则可能无法触发。重构startRecording函数,提前绑定事件:
const startRecording = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/mp4;codecs=mp4a.40.2' }); // 先绑定onstop事件,再启动录制 mediaRecorder.onstop = async () => { const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/mp4', }); const formData = new FormData(); formData.append('audio', audioBlob, 'audio_recording.mp4'); formData.append('id', id.current); try { const response = await fetch(`${URL}/upload-audio`, { method: 'POST', body: formData, credentials: 'include', }); const { lastMessage, chatStatus } = await response.json(); console.log(lastMessage); setResponseText(lastMessage); setChatStatus(chatStatus); } catch (error) { console.error('Fetch error:', error); } finally { audioChunksRef.current = []; stream.getTracks().forEach(track => track.stop()); setMediaRecorder(null); } }; mediaRecorder.ondataavailable = (event) => { audioChunksRef.current.push(event.data); }; mediaRecorder.start(); setMediaRecorder(mediaRecorder); setIsRecording(true); } catch (error) { console.error('Error starting recording:', error); } };
4. 权限触发要求
Safari和iPhone Chrome要求媒体权限请求必须由用户主动交互(如点击按钮)触发,确保startRecording直接绑定到按钮的onClick事件,避免异步延迟或间接调用。
5. 测试验证
修改后在目标浏览器测试:
- 确认录制能正常启动
- 停止后生成有效的音频文件
- 服务器能正确接收并解析音频
内容的提问来源于stack exchange,提问作者RXM23
相关产品推荐
相关产品推荐

