在网络上,我们可以捕捉来自用户的摄像头,麦克风媒体流和甚至桌面。我们可以使用这些媒体流通过 WebRTC进行实时视频聊天,并且通过MediaRecorder API,我们还可以直接在 Web 浏览器中记录和保存用户的音频或视频。
为了探索 MediaRecorder API,让我们使用 HTML、CSS 和 JavaScript 构建一个简单的录音机应用程序。
入门
要构建这个应用程序,我们只需要一个文本编辑器和一个支持 MediaRecorded API的浏览器。在撰写本文时,支持的浏览器包括 Firefox、Chrome 和 Opera。还将此 API 引入 Edge 和 Safari 的工作正在进行中。
首先,创建一个文件夹并保存这个 HTML 文件和这个 CSS 文件,让我们开始工作。确保它们位于同一文件夹中,并且 CSS 文件名为web-recorder-style.css
. 在浏览器中打开 HTML 文件,您应该看到以下内容:
现在让我们来看看 MediaRecorder API。
媒体记录器 API
要开始使用 MediaRecorder API,您需要一个 MediaStream。您可以从 a<video>
或<audio>
element获取一个,也可以通过调用getUserMedia
来捕获用户的相机和麦克风。一旦你有了一个流,你就可以MediaRecorder
用它初始化它,然后你就可以开始录制了。
在记录期间,该MediaRecorder
对象将发出dataavailable
带有记录数据的事件作为事件的一部分。我们将侦听这些事件并整理数组中的数据块。录制完成后,我们会将块数组重新绑定到一个Blob
对象中。我们可以通过在对象上调用start
和来控制录音的开始和结束。stop
MediaRecorder
让我们看看它的实际效果。
获取用户媒体
我们将首先连接一些 UI 并使用第一个按钮访问用户的麦克风流。在<script>
您下载的入门 HTML 底部的标记之间,首先注册一个在页面内容加载后运行的事件,然后收集我们将使用的 UI 部分:
<script>
window.addEventListener('DOMContentLoaded', () => {
const getMic = document.getElementById('mic');
const recordButton = document.getElementById('record');
const list = document.getElementById('recordings');
});
</script>
接下来,我们将检查浏览器是否支持我们正在编写的代码。如果不是,我们将向页面显示错误。
<script>
window.addEventListener('DOMContentLoaded', () => {
const getMic = document.getElementById('mic');
const recordButton = document.getElementById('record');
const list = document.getElementById('recordings');
if ('MediaRecorder' in window) {
// everything is good, let's go ahead
} else {
renderError("Sorry, your browser doesn't support the MediaRecorder API, so this demo will not work.");
}
});
</script>
对于该renderError
方法,我们将用<main>
错误消息替换元素的内容。在事件侦听器之后添加此方法。
function renderError(message) {
const main = document.querySelector('main');
main.innerHTML = `<div class="error"><p>${message}</p></div>`;
}
如果我们可以访问,MediaRecorder
那么我们现在需要访问麦克风进行录音。为此,我们将使用getUserMediaAPI。我们不会立即请求访问麦克风,因为这对任何用户来说都是糟糕的体验。相反,我们将等待用户单击按钮访问麦克风,然后询问。
if ('MediaRecorder' in window) {
getMic.addEventListener('click', async () => {
getMic.setAttribute('hidden', 'hidden');
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
});
console.log(stream);
} catch {
renderError(
'You denied access to the microphone so this demo will not work.'
);
}
});
} else {
navigator.mediaDevices.getUserMedia
如果用户允许访问媒体,则调用返回一个成功解析的承诺。由于我们使用的是现代 JavaScript,因此我们可以使用async/await
. 我们声明点击处理程序是一个async
函数,然后当它调用getUserMedia
我们await
的结果时,然后继续。
用户可能会拒绝访问麦克风,我们将通过将调用包装在try/catch
语句中来处理这种情况。Denial 将导致catch
块执行,我们将renderError
再次使用我们的函数。
保存您的文件并在浏览器中打开它。单击获取麦克风按钮。系统会询问您是否要授予对麦克风的访问权限,当您接受时,您将看到结果MediaStream
记录到控制台。
记录
现在我们可以使用麦克风了,我们可以准备录音机了。我们将存储一些我们也需要的其他变量。首先是我们将使用的 MIME 类型,“audio/webm”。这似乎是浏览器将记录到今天的最广泛支持的格式。我们还将创建一个名为 的数组chunks
,我们将使用该数组在创建录音时存储部分录音。
使用我们从用户麦克风捕获的媒体流和选项对象进行MediaRecorder初始化,我们将传递我们之前定义的 MIME 类型。将console.log
之前的替换为:
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
});
const mimeType = 'audio/webm';
let chunks = [];
const recorder = new MediaRecorder(stream, { type: mimeType });
现在我们已经创建了MediaRecorder
我们需要为它设置一些事件监听器。记录器出于多种不同的原因发出事件。许多与记录器本身的交互有关,因此您可以在开始记录、暂停、恢复和停止时监听事件。最重要的事件是dataavailable
记录器正在主动记录时定期发出的事件。这些事件包含一段录音,我们将把它推送到chunks
我们刚刚创建的数组上。
对于我们的应用程序,我们将侦听dataavailable
收集块的事件,然后当stop
事件触发时,我们会将所有块收集到 a 中Blob,然后我们可以使用一个<audio>
元素并重置chunks
.
const recorder = new MediaRecorder(stream, { type: mimeType });
recorder.addEventListener('dataavailable', event => {
if (typeof event.data === 'undefined') return;
if (event.data.size === 0) return;
chunks.push(event.data);
});
recorder.addEventListener('stop', () => {
const recording = new Blob(chunks, {
type: mimeType
});
renderRecording(recording, list);
chunks = [];
});
我们很快就会实现这个renderRecording
方法。我们只需要做更多的工作来启用按钮来开始和停止录制。
我们需要取消隐藏录制按钮,然后在单击时开始录制或停止录制,具体取决于录制器本身的状态。该代码如下所示:
chunks = [];
});
recordButton.removeAttribute('hidden');
recordButton.addEventListener('click', () => {
if (recorder.state === 'inactive') {
recorder.start();
recordButton.innerText = 'Stop';
} else {
recorder.stop();
recordButton.innerText = 'Record';
}
});
为了完成这个小应用程序,我们将把录音渲染成<audio>
元素并提供一个下载链接,以便用户可以将他们的录音保存到桌面。这里的关键是我们可以使用Blob
我们创建的URL.createObjectURL
方法将其转换为 URL 。然后,该URL可以用作为src
一个的<audio>
元素和作为href
锚定的。为了让锚下载文件,我们设置了download
属性。
此功能主要是创建 DOM 元素并在录制时间之外制作文件名。将其添加到您的renderError
函数下方。
function renderRecording(blob, list) {
const blobUrl = URL.createObjectURL(blob);
const li = document.createElement('li');
const audio = document.createElement('audio');
const anchor = document.createElement('a');
anchor.setAttribute('href', blobUrl);
const now = new Date();
anchor.setAttribute(
'download',
`recording-${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDay().toString().padStart(2, '0')}--${now.getHours().toString().padStart(2, '0')}-${now.getMinutes().toString().padStart(2, '0')}-${now.getSeconds().toString().padStart(2, '0')}.webm`
);
anchor.innerText = 'Download';
audio.setAttribute('src', blobUrl);
audio.setAttribute('controls', 'controls');
li.appendChild(audio);
li.appendChild(anchor);
list.appendChild(li);
}
测试一下
在 Web 浏览器中打开该页面,然后单击“获取麦克风”按钮。接受权限对话框,然后单击开始录制。为自己录制一条消息并从页面播放。
WebM 文件
如果您下载其中一个录音,您可能会发现您没有能够播放 WebM 文件的媒体播放器。WebM 是一种音频和视频的开源格式,但它主要得到浏览器的支持。如果您有VLC 播放器,您可能可以播放音频,否则您可能想使用诸如convertio 之类的在线工具将其转换为 MP3 或 WAV 文件(或者如果您有胆量,可以在终端中使用ffmpeg)。
你的浏览器现在是一个记录器
该MediaRecorder
API是一个功能强大的新增加的浏览器。在这篇文章中,我们已经看到了它录制音频的能力,但它并不止于此。当前应用程序不保存音频文件,因此页面刷新会丢失它们。您可以使用 IndexedDB 保存它们或将它们发送到服务器。您还可以播放录音,想象一下在录制之前通过 Web Audio API 传递音频。如果 WebM 格式不是你的菜,你总是可以考虑在前端重新编码音频,尽管这可能是 WebAssembly(或你的服务器......)的工作。
如果您想尝试这篇文章中的代码,您可以查看现场演示。此GitHub 存储库中提供了所有代码,您也可以在Glitch上重新混合该项目。