前端音视频:WebRTC 或 MediaRecorder

域名注册
域名注册 正式会员超兽战士 👑年卡会员
发布于 2026-10-07 23:58 ·1 浏览 ·0 回复

前端音视频里 WebRTC 和 MediaRecorder 不是二选一的关系:WebRTC 解决「把音视频实时传到对面」,MediaRecorder 解决「把音视频存成一个文件」。结论:做通话、连麦、远程协助、云游戏这类低延迟互动,用 WebRTC;做录音、录屏、本地保存、上传回放,用 MediaRecorder;要边通话边录制,就是 WebRTC 拿流、MediaRecorder 落盘,两者共用同一个 MediaStream 接口。

WebRTC 和 MediaRecorder 有什么区别?

结论:WebRTC 是实时传输协议栈,MediaRecorder 是编码落盘 API,两者能力不重叠,唯一的交集是都从 navigator.mediaDevices.getUserMedia() 拿到的 MediaStream 开始。

WebRTC 的核心对象是 RTCPeerConnection,通过 SDP 协商(offer/answer)、ICE 收集候选地址、SRTP 加密传输,把音视频包直接推给对端,同城网络下端到端延迟典型值 100–300ms,全链路一般能压在 500ms 以内。它不产文件,只产「另一端的画面」。

MediaRecorder 的核心是 new MediaRecorder(stream, options),把输入的轨道按 MIME 类型编码成 Blob 分片,触发 ondataavailable,产出的是一段可以下载、上传的完整文件。它不管另一端是谁。

一句话记法:WebRTC 管「传」,MediaRecorder 管「存」。

只用 MediaRecorder 怎么录制音视频?

结论:四步就能跑通——拿流、建 Recorder、收分片、拼 Blob,关键是先做 MIME 能力检测,别硬编码格式。

const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const mimeType = ['video/webm;codecs=vp9,opus', 'video/webm;codecs=vp8,opus', 'video/mp4']
  .find(t => MediaRecorder.isTypeSupported(t));
const rec = new MediaRecorder(stream, {
  mimeType,
  videoBitsPerSecond: 2500000,  // 1080p 建议 2.5Mbps 起
  audioBitsPerSecond: 128000
});
const chunks = [];
rec.ondataavailable = e => e.data.size && chunks.push(e.data);
rec.onstop = () => {
  const blob = new Blob(chunks, { type: mimeType });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = 'record.webm';
  a.click();
};
rec.start(1000); // 每秒切一个分片,避免长录制撑爆内存

三个必须注意的点:一是 getUserMedia 只在安全上下文可用,必须是 HTTPS 或 localhost,http 域名下直接报 undefined;二是 start(1000) 的 timeslice 参数很重要,不传的话只有调用 stop() 才吐一次数据,长录制容易出现内存峰值和丢片,传 1000ms 后可以做分片上传;三是 pause()/resume() 在 Chrome 和 Firefox 上都可用,但暂停期间的时间戳仍会保留,剪辑时要自己处理。

为什么录出来的 webm 在 Safari 播不了,或者时长显示 Infinity?

结论:这是浏览器编码器差异,不是代码 bug——Firefox 的 MediaRecorder 只支持 WebM(VP8/VP9/Opus),Safari 从 14.1 起才支持 MediaRecorder 且只输出 MP4(H.264),Chrome 两者都不输出 MP4 录制。跨浏览器想统一格式,只能在服务端转码或前端用 WebCodecs 自己编。

至于 duration 为 Infinity,是 Chrome 录制的 WebM 分片缺少时长元数据导致的,播放器读不到总时长就显示不了进度条。解决方法有两个:用 fix-webm-duration 这类库在保存前重写头部,或者录制时直接用 MP4(在支持的浏览器上)。

WebRTC 最少要写哪几步?

结论:无论多简单的 WebRTC,都绕不开「信令 + SDP 交换 + ICE 交换」这三件事,浏览器 API 只负责后两件的一半。

流程是:A 端 createOffer() → setLocalDescription() → 通过你自己的 WebSocket/HTTP 信令服务器把 offer 发给 B;B 端 setRemoteDescription() → createAnswer() → setLocalDescription() 回传;两端监听 onicecandidate 互相转发候选,onconnectionstatechange 变成 connected 就通了。公网必须配 STUN,stun:stun.l.google.com:19302 可以白嫖;对称 NAT 或企业防火墙下(约占实际用户 10%–20%)必须自建 TURN,比如 coturn,否则连不上。

WebRTC 还有个容易被忽略的坑:addTrack 之后才 setLocalDescription 的话,SDP 里不会带轨道信息,对端只能收到黑屏,正确顺序是先加轨道再协商。

什么时候需要两个一起用?

结论:需要「边实时通话边留证」的场景,就用 WebRTC 传输、MediaRecorder 录制,录的流既可以是本地流也可以是远端流。

典型做法有三种:录本地画面,直接把 getUserMedia 的流喂给 MediaRecorder;录对端画面,把 pc.ontrack 里拿到的 event.streams[0] 交给 MediaRecorder(注意要判断是 event.track.kind === 'video' 还是 audio);双向混流录制,则用 AudioContext 的 createMediaStreamDestination() 把两路音频混成一路再录。

要提醒的是,远端流录制依赖对方的发送码率和你的接收状态,丢包时录下来的画面会花,所以合规存档类场景建议服务端录制(如 SFU 侧的录制能力),前端录制只作为兜底。

总结一下:判断标准就一条——数据要不要实时到对面。要,选 WebRTC,并准备好信令服务器和 TURN;不要,选 MediaRecorder,先检测 MIME 再用 1000ms 分片。两者不是竞品,是流水线的上下游,共用同一个 MediaStream 就是它们能拼在一起的接口。

版权声明:本文来自 GJ站长论坛《前端音视频:WebRTC 或 MediaRecorder》
原文链接:https://www.gj0.com/thread-629.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。

全部回复 0

还没有回复,来抢沙发~