前幾天好累,今天來點輕鬆又有趣的!😇
今天要介紹的是瀏覽器裡的 HTML5 MediaDevices API,透過它我們可以直接存取 麥克風 與 攝影機,這也是現代視訊會議、線上課程、直播平台的基礎技術之一。 🎥
最後也會延伸提到 MediaRecorder,教你怎麼把錄到的聲音存下來,讓你的網頁不只會開啟攝影機,還能 錄音!🎙️
在 JavaScript 裡,我們可以透過 navigator.mediaDevices
這個物件來操作多媒體裝置:
getUserMedia()
:請求使用者的攝影機、麥克風存取權限,回傳 MediaStream
。enumerateDevices()
:列出可用的音訊、視訊裝置(例如筆電內建鏡頭、外接攝影機)。getDisplayMedia()
:讓使用者選擇要分享的螢幕或視窗,常見於 Google Meet、Zoom 的「分享畫面」。支援度:主流瀏覽器(Chrome、Firefox、Safari、Edge)皆已支援,但還是要注意版本的差異與行動裝置的特性。
最常見的需求就是「打開攝影機」,語法相當直覺:
// 建立 video
(() => {
let v = document.querySelector('#cam');
if (!v) {
v = document.createElement('video');
v.id = 'cam';
v.autoplay = true;
v.muted = true;
v.playsInline = true;
v.style.width = '360px';
v.style.height = '270px';
document.body.appendChild(v);
}
})();
// 請求使用者的攝影機、麥克風存取權限
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then((stream) => {
document.querySelector('#cam').srcObject = stream;
})
.catch((err) => {
console.error(err.name, err.message);
});
video: true
→ 請求影像audio: true
→ 請求聲音MediaStream
丟進 <video>
的 srcObject
就能直接播放!getUserMedia
不只是打開攝影機而已,還能玩出更多花樣:
MediaRecorder
,可以將音訊存下來。getDisplayMedia()
,就能取得畫面內容。enumerateDevices()
,讓使用者在前鏡頭 / 後鏡頭間切換。const stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: false });
document.querySelector('video').srcObject = stream;
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices.forEach((device) => {
console.log(device.kind, device.label);
});
});
既然都能存取攝影機和麥克風,也能抓到畫面,不提到錄音就太可惜了~ 所以這裡也簡單說明 MediaRecorder 並加上範例!
最小可行:只錄音訊(避免常見 NotSupportedError)
錄音時使用 純音訊的 MediaStream,不要把同時含有視訊軌的 Stream 丟進音訊容器。
// 1) 先拿到麥克風權限(可同時拿 video,但錄音只取 audio)
const camStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
// 2) 只取音訊軌來建一個新的 MediaStream(關鍵)
const audioStream = new MediaStream(camStream.getAudioTracks());
// 3) 挑一個瀏覽器支援的音訊 MIME
function pickAudioMime() {
if (!(window.MediaRecorder && MediaRecorder.isTypeSupported)) return {};
const candidates = [
'audio/webm;codecs=opus', // Chromium 系
'audio/webm',
'audio/ogg;codecs=opus', // Firefox
'audio/mp4' // Safari
];
for (const t of candidates) {
if (MediaRecorder.isTypeSupported(t)) return { mimeType: t };
}
return {};
}
// 4) 開始/停止錄音
// 每次有錄到資料就把 Blob 片段塞進 recordedChunks 陣列
const chunks = [];
const recorder = new MediaRecorder(audioStream, pickAudioMime());
recorder.ondataavailable = (e) => { if (e.data && e.data.size) chunks.push(e.data); };
// 停止錄音時把所有片段合併成一個 Blob,建立 URL,生成一個下載連結
recorder.onstop = () => {
const type = chunks[0]?.type || 'audio/webm';
const blob = new Blob(chunks, { type });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `recording-${Date.now()}.${type.includes('mp4') ? 'mp4' : (type.includes('ogg') ? 'ogg' : 'webm')}`;
a.click();
URL.revokeObjectURL(url);
};
recorder.start(); // 錄音開始(可改成 recorder.start(1000) 每秒切片)
// ... 一段時間後
recorder.stop(); // 觸發 onstop,產出檔案
NotSupportedError
?MediaStream
。getAudioTracks().length > 0
。MediaRecorder.isTypeSupported()
挑一個真的可用的。這類 API 屬於高敏感度的權限操作,因此有幾個強制規則:
localhost
以外,瀏覽器只允許在 HTTPS 環境存取。上面我們用簡單程式碼展示了基本的 MediaDevices Web API。
如果想直接體驗完整的互動效果,可以參考這個線上範例:
👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯