You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-media-recorder在Safari录音后无法播放?求跨浏览器解决方案

React 语音录制兼容 Safari 最简实现方案

Safari 对 MediaRecorder 的编码格式支持与 Chrome 存在差异,默认的 webm 格式在 Safari 中无法正常解码播放,需要指定兼容的 MIME 类型(如 audio/mp4;codecs=mp4a.40.2)。以下是不依赖第三方库、直接基于原生 API 实现的兼容 Chrome 和 Safari 的最简代码:

import { useState, useRef, useEffect } from 'react';

const VoiceRecorder = () => {
  const [isRecording, setIsRecording] = useState(false);
  const [recordedBlob, setRecordedBlob] = useState(null);
  const [audioUrl, setAudioUrl] = useState(null);
  const mediaRecorderRef = useRef(null);
  const audioRef = useRef(null);
  const chunksRef = useRef([]);

  // 请求麦克风权限并初始化录音
  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      // 指定兼容 Safari 的编码格式
      const mimeType = 'audio/mp4;codecs=mp4a.40.2';
      const mediaRecorder = new MediaRecorder(stream, { mimeType });

      mediaRecorderRef.current = mediaRecorder;
      chunksRef.current = [];

      mediaRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) {
          chunksRef.current.push(e.data);
        }
      };

      mediaRecorder.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: mimeType });
        setRecordedBlob(blob);
        // 创建可播放的音频 URL
        const url = URL.createObjectURL(blob);
        setAudioUrl(url);
        // 停止媒体流,释放麦克风资源
        stream.getTracks().forEach(track => track.stop());
      };

      mediaRecorder.start();
      setIsRecording(true);
    } catch (err) {
      console.error('录音初始化失败:', err);
      alert('无法访问麦克风,请检查权限设置');
    }
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current && isRecording) {
      mediaRecorderRef.current.stop();
      setIsRecording(false);
    }
  };

  const playRecording = () => {
    if (audioUrl && audioRef.current) {
      audioRef.current.play().catch(err => {
        console.error('播放失败:', err);
        alert('音频无法播放,请检查浏览器设置');
      });
    }
  };

  // 组件卸载时清理 ObjectURL,避免内存泄漏
  useEffect(() => {
    return () => {
      if (audioUrl) {
        URL.revokeObjectURL(audioUrl);
      }
    };
  }, [audioUrl]);

  return (
    <div>
      <button onClick={isRecording ? stopRecording : startRecording}>
        {isRecording ? '停止录音' : '开始录音'}
      </button>
      {recordedBlob && (
        <button onClick={playRecording} style={{ marginLeft: '10px' }}>
          播放录音
        </button>
      )}
      <audio ref={audioRef} src={audioUrl} controls style={{ display: 'block', marginTop: '10px' }} />
    </div>
  );
};

export default VoiceRecorder;

关键兼容说明:

  • MIME 类型指定:必须明确使用 audio/mp4;codecs=mp4a.40.2,这是 Safari 原生支持的音频编码格式,Chrome 也兼容该格式。
  • 媒体流清理:录音停止后主动停止麦克风流,避免持续占用设备资源。
  • ObjectURL 管理:组件卸载时调用 URL.revokeObjectURL 释放内存,防止内存泄漏。
  • 播放异常处理:调用 play() 时捕获异常,处理 Safari 中严格的自动播放限制(需用户交互触发播放)。

内容的提问来源于stack exchange,提问作者aurelien_morel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:37:26