录制控制实战:开始、暂停、恢复、停止与时长限制
各位同学,今天我们来聊聊录制控制的核心操作。说实话,这部分内容在 WebRTC 开发中特别实用。我刚开始做录制功能时,以为就是点一下开始、再点一下停止那么简单。结果呢?用户反馈说「录到一半想暂停怎么办?」、「录了俩小时才发现没设时长限制,文件大得打不开」……嗯,这些坑我都踩过。
今天这一章,我们就来系统地把这些控制逻辑捋清楚。你想想看,一个完整的录制器,至少需要这几个按钮:开始、暂停、恢复、停止。再加上一个时长限制,基本就齐活了。
1. 开始录制:从 MediaRecorder 说起
开始录制,说白了就是创建一个 MediaRecorder 实例,然后把媒体流喂给它。我个人习惯先检查一下浏览器是否支持:
if (!window.MediaRecorder) {
alert('您的浏览器不支持录制功能,请使用 Chrome 或 Firefox');
return;
}
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const recorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9,opus'
});
recorder.start();
这里有个小细节——mimeType 最好做个兼容判断。我在项目中遇到过,某些安卓浏览器不支持 vp9,会直接抛异常。所以稳妥的做法是先检测:
const mimeType = MediaRecorder.isTypeSupported('video/webm;codecs=vp9,opus')
? 'video/webm;codecs=vp9,opus'
: 'video/webm';
2. 暂停录制:不是你想的那样
暂停录制,很多人以为就是 recorder.pause() 就完了。没错,API 确实是这样。但有个坑——暂停后,浏览器会继续接收媒体流,只是不写入文件。这意味着摄像头灯可能还亮着,麦克风还在收音。
我曾经遇到一个用户投诉,说「我明明点了暂停,为什么同事还能听到我说话?」嗯,这就是因为暂停只暂停了录制,没有暂停媒体流。如果你需要同时关闭摄像头/麦克风,得手动 stop 轨道:
recorder.pause();
// 可选:暂停媒体流
stream.getTracks().forEach(track => track.enabled = false);
恢复录制时再重新启用:
recorder.resume();
stream.getTracks().forEach(track => track.enabled = true);
recorder.state 会变成 'paused'。你可以利用这个状态来判断当前是否可恢复。
3. 恢复录制:简单但容易忘
恢复录制就是 recorder.resume()。没什么复杂的。但有个细节——恢复后,录制的文件是连续的,不会产生新的文件片段。这一点和「停止后再开始」完全不同。
我个人建议在 UI 上做清晰的状态切换:
- 录制中 → 显示「暂停」按钮
- 暂停中 → 显示「恢复」按钮
- 停止后 → 显示「开始」按钮
这样用户一看就明白当前是什么状态,不会误操作。
4. 停止录制:别忘了释放资源
停止录制调用 recorder.stop() 即可。但这里有个关键点——停止后,一定要释放媒体流。否则摄像头灯会一直亮着,用户会以为程序出 bug 了。
recorder.stop();
stream.getTracks().forEach(track => track.stop());
另外,停止后 MediaRecorder 会触发 onstop 事件,你可以在里面做最后的文件处理:
recorder.ondataavailable = (event) => {
if (event.data.size > 0) {
chunks.push(event.data);
}
};
recorder.onstop = () => {
const blob = new Blob(chunks, { type: 'video/webm' });
// 保存或上传 blob
};
5. 处理录制错误:别让用户一脸懵
录制过程中可能出现的错误,我总结了几种常见情况:
| 错误类型 | 原因 | 处理方式 |
|---|---|---|
NotAllowedError |
用户拒绝了摄像头/麦克风权限 | 提示用户开启权限 |
NotFoundError |
没有找到摄像头/麦克风设备 | 提示检查设备连接 |
SecurityError |
非安全上下文(非 HTTPS 或 localhost) | 提示使用 HTTPS |
AbortError |
录制被意外中止 | 尝试重新开始录制 |
我建议统一用一个错误处理函数:
function handleRecordingError(error) {
console.error('录制出错:', error.name, error.message);
// 根据 error.name 给出不同提示
if (error.name === 'NotAllowedError') {
alert('请允许使用摄像头和麦克风权限');
} else if (error.name === 'NotFoundError') {
alert('未检测到摄像头或麦克风设备');
} else {
alert('录制出现异常,请重试');
}
// 重置 UI 状态
resetUI();
}
6. 录制时长限制:防止用户录到天荒地老
时长限制这个功能,说白了就是定时器。我一般用 setTimeout 来实现:
const MAX_DURATION = 60 * 1000; // 60 秒
let timer = null;
function startRecordingWithLimit() {
recorder.start();
timer = setTimeout(() => {
recorder.stop();
alert('录制已超时,自动停止');
}, MAX_DURATION);
}
但这里有个坑——如果用户手动暂停了,计时器还在跑。所以暂停时要清除计时器,恢复时重新设置:
recorder.onpause = () => {
clearTimeout(timer);
};
recorder.onresume = () => {
timer = setTimeout(() => {
recorder.stop();
alert('录制已超时,自动停止');
}, MAX_DURATION - elapsedTime);
};
嗯,这里需要记录一下已经录制的时间 elapsedTime,否则恢复后计时就不准了。
知识体系总览
下面这张图,我把整个录制控制的核心逻辑画出来了。你看一眼就能明白各个状态之间的转换关系:
从这张图可以清楚看到,整个录制控制就是一个有限状态机。每个状态都有明确的进入条件和退出条件。我个人觉得,把状态机画出来,代码写起来就清晰多了。
总结一下
录制控制这块,说白了就是几个 API 的调用组合。但真正做好,需要考虑用户体验、错误处理、资源释放这些细节。我建议你在写代码之前,先把状态图画好,把每个边界情况想清楚。
嗯,这一章的内容就到这里。代码示例我都放在项目仓库里了,你可以直接跑起来试试。有什么问题,欢迎在评论区交流。