iT邦幫忙

2025 iThome 鐵人賽

DAY 10
3
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 10

Day 10 - 攝影機、麥克風全開!用 MediaDevices Web API 開鏡頭、分享螢幕、錄音

  • 分享至 

  • xImage
  •  

前幾天好累,今天來點輕鬆又有趣的!😇

今天要介紹的是瀏覽器裡的 HTML5 MediaDevices API,透過它我們可以直接存取 麥克風攝影機,這也是現代視訊會議、線上課程、直播平台的基礎技術之一。 🎥
最後也會延伸提到 MediaRecorder,教你怎麼把錄到的聲音存下來,讓你的網頁不只會開啟攝影機,還能 錄音!🎙️


MediaDevices 是什麼?

在 JavaScript 裡,我們可以透過 navigator.mediaDevices 這個物件來操作多媒體裝置:

  • getUserMedia():請求使用者的攝影機、麥克風存取權限,回傳 MediaStream
  • enumerateDevices():列出可用的音訊、視訊裝置(例如筆電內建鏡頭、外接攝影機)。
  • getDisplayMedia():讓使用者選擇要分享的螢幕或視窗,常見於 Google Meet、Zoom 的「分享畫面」。

支援度:主流瀏覽器(Chrome、Firefox、Safari、Edge)皆已支援,但還是要注意版本的差異與行動裝置的特性。


getUserMedia 基本用法

最常見的需求就是「打開攝影機」,語法相當直覺:

// 建立 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


延伸應用

getUserMedia 不只是打開攝影機而已,還能玩出更多花樣:

  • 麥克風錄音:搭配 MediaRecorder,可以將音訊存下來。
  • 螢幕分享:使用 getDisplayMedia(),就能取得畫面內容。
  • 裝置切換:配合 enumerateDevices(),讓使用者在前鏡頭 / 後鏡頭間切換。

getDisplayMedia 基本用法

const stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: false });
document.querySelector('video').srcObject = stream;

getDisplayMedia

enumerateDevices 基本用法

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices.forEach((device) => {
    console.log(device.kind, device.label);
  });
});

延伸:MediaRecorder 基本用法

既然都能存取攝影機和麥克風,也能抓到畫面,不提到錄音就太可惜了~ 所以這裡也簡單說明 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

  • Stream 內含 video track,但容器是 audio-only → 改用「只含音訊軌」的 MediaStream
  • 沒有音訊軌(權限拒絕、裝置被佔用)→ 確認 getAudioTracks().length > 0
  • MIME 不支援 → 先用 MediaRecorder.isTypeSupported() 挑一個真的可用的。

瀏覽器安全限制

這類 API 屬於高敏感度的權限操作,因此有幾個強制規則:

  1. 必須 HTTPS:除了 localhost 以外,瀏覽器只允許在 HTTPS 環境存取。
  2. 使用者同意:彈出提示框(允許 / 拒絕),只有同意後才能使用。
  3. 權限控管
    • 使用者可以永久允許或封鎖特定網站。
    • 一旦封鎖,除非重新設定,網站無法再彈出請求。

範例 Demo

上面我們用簡單程式碼展示了基本的 MediaDevices Web API。
如果想直接體驗完整的互動效果,可以參考這個線上範例:

MediaDevices


👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 9 - 用 Drag and Drop API 拖曳 DOM 元素
下一篇
Day 11 - 錄製螢幕畫面與聲音!MediaDevices + MediaRecorder
系列文
從 Canvas 到各式各樣的 Web API 之旅12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言