บทนำ
การบันทึกเสียง/วิดีโอเป็น "คัมภีร์ไบเบิล" ในการพัฒนาเว็บมาอย่างยาวนาน เป็นเวลาหลายปีที่เราต้องใช้ปลั๊กอินเบราว์เซอร์ (Flash หรือ Silverlight) เพื่อทำงาน ไปกันเถอะ
HTML5 จะช่วยแก้ปัญหานี้ได้ เรื่องนี้อาจไม่ชัดเจนนัก แต่การเพิ่มขึ้นของ HTML5 ส่งผลให้การเข้าถึงฮาร์ดแวร์ของอุปกรณ์เพิ่มขึ้นอย่างมาก ตัวอย่างที่ชัดเจน ได้แก่ ตำแหน่งทางภูมิศาสตร์ (GPS), Orientation API (เครื่องวัดความเร่ง), WebGL (GPU) และ Web Audio API (ฮาร์ดแวร์เสียง) ฟีเจอร์เหล่านี้มีประสิทธิภาพสูงมาก โดยแสดง JavaScript API ระดับสูงที่ทำงานร่วมกับความสามารถของฮาร์ดแวร์พื้นฐานของระบบ
บทแนะนํานี้จะแนะนำ API ใหม่อย่าง GetUserMedia ซึ่งช่วยให้เว็บแอปเข้าถึงกล้องและไมโครโฟนของผู้ใช้ได้
เส้นทางสู่ getUserMedia()
หากคุณไม่ทราบประวัติความเป็นมา การสร้าง getUserMedia()
API นั้นน่าสนใจทีเดียว
"Media Capture API" หลายรูปแบบได้พัฒนาขึ้นในช่วง 2-3 ปีที่ผ่านมา ผู้คนจำนวนมากตระหนักถึงความจำเป็นในการเข้าถึงอุปกรณ์แบบเนทีฟบนเว็บ แต่นั่นทำให้ทุกคนต้องร่วมกันจัดทำข้อกำหนดใหม่ ทุกอย่างยุ่งเหยิงจน W3C ตัดสินใจจัดตั้งกลุ่มทำงานในที่สุด วัตถุประสงค์เดียวของบุคคลนั้น มาทำความเข้าใจความบ้าคลั่งนี้กัน คณะทำงานด้านนโยบาย Device API (DAP) ได้รับมอบหมายให้รวบรวมและกำหนดมาตรฐานให้กับข้อเสนอจำนวนมาก
เราจะลองสรุปสิ่งที่เกิดขึ้นในปี 2011…
รอบที่ 1: การจับภาพสื่อ HTML
การจับภาพสื่อ HTML เป็นการใช้งาน DAP ครั้งแรกในการกำหนดมาตรฐานการจับภาพสื่อบนเว็บ โดยทํางานโดยการโอเวอร์โหลด <input type="file">
และเพิ่มค่าใหม่สําหรับพารามิเตอร์ accept
หากต้องการให้ผู้ใช้ถ่ายภาพตนเองด้วยเว็บแคม คุณสามารถดำเนินการดังกล่าวได้โดยใช้ capture=camera
ดังนี้
<input type="file" accept="image/*;capture=camera">
การบันทึกวิดีโอหรือเสียงจะคล้ายกัน โดยทำดังนี้
<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">
ฟังดูดีใช่ไหม เราชอบมากที่ฟีเจอร์นี้นําอินพุตไฟล์มาใช้ซ้ำได้ ในแง่ความหมายแล้ว ข้อความนี้ฟังดูสมเหตุสมผลมาก ข้อจำกัดของ "API" นี้อยู่ที่ความสามารถในการทำเอฟเฟกต์แบบเรียลไทม์ (เช่น แสดงผลข้อมูลเว็บแคมแบบสดเป็น <canvas>
และใช้ฟิลเตอร์ WebGL)
HTML Media Capture ให้คุณบันทึกไฟล์สื่อหรือถ่ายภาพหน้าจอได้เท่านั้น
การสนับสนุน:
- เบราว์เซอร์ Android 3.0 -เป็นหนึ่งในการใช้งานครั้งแรก ดูวิธีใช้งานได้ในวิดีโอนี้
- Chrome สำหรับ Android (0.16)
- Firefox Mobile 10.0
- Safari และ Chrome ของ iOS6 (รองรับบางส่วน)
รอบที่ 2: องค์ประกอบอุปกรณ์
หลายคนคิดว่า HTML Media Capture จํากัดเกินไป จึงมีการเปิดตัวข้อกําหนดใหม่ซึ่งรองรับอุปกรณ์ทุกประเภท (ในอนาคต) ไม่น่าแปลกใจเลยที่การออกแบบนี้ต้องใช้องค์ประกอบใหม่อย่างองค์ประกอบ <device>
ซึ่งกลายเป็นรุ่นก่อนหน้าของ getUserMedia()
Opera เป็นหนึ่งในเบราว์เซอร์แรกๆ ที่เริ่มใช้งานครั้งแรกการจับภาพวิดีโอโดยอิงตามองค์ประกอบ <device>
หลังจากนั้นไม่นาน (ในวันเดียวกัน) WhatWG ตัดสินใจยกเลิกการใช้แท็ก <device>
และใช้แท็กอื่นที่กำลังมาแรงแทน ซึ่งคราวนี้เป็น JavaScript API ที่ชื่อว่า navigator.getUserMedia()
1 สัปดาห์ต่อมา Opera ได้เปิดตัวบิลด์ใหม่ซึ่งรองรับข้อกำหนด getUserMedia()
ที่อัปเดตแล้ว ต่อมาในปีนั้น Microsoft ก็ได้เข้าร่วมด้วยโดยเปิดตัวห้องทดลองสำหรับ IE9 ที่รองรับข้อกำหนดใหม่
<device>
จะมีลักษณะดังนี้
<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
function update(stream) {
document.querySelector('video').src = stream.url;
}
</script>
การสนับสนุน:
ขออภัย ไม่มีเบราว์เซอร์ที่เผยแพร่ซึ่งรวม <device>
ไว้ด้วย
คงไม่ต้องกังวลเรื่อง API อีก 1 รายการแล้ว :) แต่ <device>
มีข้อดี 2 อย่าง 1.) เป็นเซแมนติก และ 2.) ขยายการทำงานเพื่อรองรับอุปกรณ์อื่นๆ นอกเหนือจากอุปกรณ์เสียง/วิดีโอได้
หายใจเข้าลึกๆ ข้อมูลนี้เปลี่ยนแปลงอย่างรวดเร็ว
รอบที่ 3: WebRTC
องค์ประกอบ <device>
ในที่สุดก็สูญพันธุ์ไป
ความเร็วในการค้นหา API การจับภาพที่เหมาะสมเพิ่มขึ้นด้วยการใช้งาน WebRTC (Web Real Time Communications) มากขึ้น ข้อกำหนดเฉพาะดังกล่าวอยู่ภายใต้การควบคุมดูแลของกลุ่มทำงาน WebRTC ของ W3C Google, Opera, Mozilla และบางรายอื่นๆ มีการใช้งาน
getUserMedia()
เกี่ยวข้องกับ WebRTC เนื่องจากเป็นเกตเวย์ไปยังชุด API ดังกล่าว
ซึ่งจะเป็นช่องทางเข้าถึงสตรีมกล้อง/ไมโครโฟนในเครื่องของผู้ใช้
การสนับสนุน:
getUserMedia()
ได้รับการรองรับตั้งแต่ Chrome 21, Opera 18 และ Firefox 17
เริ่มต้นใช้งาน
navigator.mediaDevices.getUserMedia()
ช่วยให้เราสามารถเข้าถึงอินพุตจากเว็บแคมและไมโครโฟนโดยไม่ต้องใช้ปลั๊กอินได้ในที่สุด
ตอนนี้คุณเข้าถึงกล้องได้ด้วยการโทรเพียงสายเดียวโดยไม่ต้องติดตั้งแอป เนื้อหาจะฝังอยู่ในเบราว์เซอร์โดยตรง ตื่นเต้นไหม
การตรวจหาองค์ประกอบ
การตรวจหาองค์ประกอบคือการตรวจสอบง่ายๆ ว่า navigator.mediaDevices.getUserMedia
มีอยู่หรือไม่
if (navigator.mediaDevices?.getUserMedia) {
// Good to go!
} else {
alert("navigator.mediaDevices.getUserMedia() is not supported");
}
การเข้าถึงอุปกรณ์อินพุต
หากต้องการใช้เว็บแคมหรือไมโครโฟน เราจะต้องขอสิทธิ์
พารามิเตอร์แรกสำหรับ navigator.mediaDevices.getUserMedia()
คือออบเจ็กต์ที่ระบุรายละเอียดและข้อกำหนดสำหรับสื่อแต่ละประเภทที่คุณต้องการเข้าถึง เช่น หากต้องการเข้าถึงเว็บแคม พารามิเตอร์แรกควรเป็น {video: true}
หากต้องการใช้ทั้งไมโครโฟนและกล้อง ให้ดำเนินการต่อไปนี้ใน {video: true, audio: true}
<video autoplay></video>
<script>
navigator.mediaDevices
.getUserMedia({ video: true, audio: true })
.then((localMediaStream) => {
const video = document.querySelector("video");
video.srcObject = localMediaStream;
})
.catch((error) => {
console.log("Rejected!", error);
});
</script>
โอเค เกิดอะไรขึ้น การจับภาพสื่อเป็นตัวอย่างที่สมบูรณ์แบบของการทำงานร่วมกันของ HTML5 API ใหม่ ซึ่งทำงานร่วมกับ <audio>
และ <video>
ซึ่งเป็นเพื่อนร่วมทาง HTML5 คนอื่นๆ
โปรดทราบว่าเราไม่ได้ตั้งค่าแอตทริบิวต์ src
หรือรวมองค์ประกอบ <source>
ในองค์ประกอบ <video>
เราจะตั้งค่า srcObject
เป็นออบเจ็กต์ LocalMediaStream
ที่แสดงถึงเว็บแคมแทนการส่ง URL ของไฟล์สื่อไปยังวิดีโอ
และบอก <video>
ให้ autoplay
ด้วย ไม่เช่นนั้นภาพจะค้างอยู่ที่เฟรมแรก การเพิ่ม controls
ก็ทํางานตามที่คาดไว้เช่นกัน
การตั้งค่าข้อจำกัดของสื่อ (ความละเอียด ความสูง ความกว้าง)
พารามิเตอร์แรกสำหรับ getUserMedia()
ยังใช้เพื่อระบุข้อกำหนดเพิ่มเติม (หรือข้อจำกัด) ในสตรีมสื่อที่แสดงผลได้ด้วย ตัวอย่างเช่น แทนที่จะระบุว่าคุณต้องการสิทธิ์เข้าถึงวิดีโอขั้นพื้นฐาน (เช่น {video: true}
) คุณอาจกำหนดเพิ่มเติมให้สตรีมเป็น HD ได้ด้วย
const hdConstraints = {
video: { width: { exact: 1280} , height: { exact: 720 } },
};
const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
const vgaConstraints = {
video: { width: { exact: 640} , height: { exact: 360 } },
};
const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
ดูการกําหนดค่าเพิ่มเติมได้ใน constraints API
การเลือกแหล่งที่มาของสื่อ
เมธอด enumerateDevices()
ของอินเทอร์เฟซ MediaDevices
จะขอรายการอุปกรณ์อินพุตและเอาต์พุตสื่อที่ใช้ได้ เช่น ไมโครโฟน กล้อง ชุดหูฟัง และอื่นๆ Promise ที่แสดงผลจะได้รับการแก้ไขด้วยอาร์เรย์ของออบเจ็กต์ MediaDeviceInfo
ที่อธิบายอุปกรณ์
ในตัวอย่างนี้ ระบบจะเลือกไมโครโฟนและกล้องที่พบล่าสุดเป็นแหล่งที่มาของสตรีมสื่อ
if (!navigator.mediaDevices?.enumerateDevices) {
console.log("enumerateDevices() not supported.");
} else {
// List cameras and microphones.
navigator.mediaDevices
.enumerateDevices()
.then((devices) => {
let audioSource = null;
let videoSource = null;
devices.forEach((device) => {
if (device.kind === "audioinput") {
audioSource = device.deviceId;
} else if (device.kind === "videoinput") {
videoSource = device.deviceId;
}
});
sourceSelected(audioSource, videoSource);
})
.catch((err) => {
console.error(`${err.name}: ${err.message}`);
});
}
async function sourceSelected(audioSource, videoSource) {
const constraints = {
audio: { deviceId: audioSource },
video: { deviceId: videoSource },
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
}
ดูการสาธิตที่ยอดเยี่ยมของ Sam Dutton เกี่ยวกับวิธีอนุญาตให้ผู้ใช้เลือกแหล่งที่มาของสื่อ
ความปลอดภัย
เมื่อเรียกใช้ navigator.mediaDevices.getUserMedia()
เบราว์เซอร์จะแสดงกล่องโต้ตอบสิทธิ์ ซึ่งให้ผู้ใช้มีตัวเลือกในการให้หรือปฏิเสธสิทธิ์เข้าถึงกล้อง/ไมโครโฟน ตัวอย่างเช่น นี่เป็นกล่องโต้ตอบสิทธิ์ของ Chrome
การให้คำอธิบายสำรอง
สําหรับผู้ใช้ที่ไม่รองรับ navigator.mediaDevices.getUserMedia()
ตัวเลือกหนึ่งคือใช้ไฟล์วิดีโอที่มีอยู่หากระบบไม่รองรับ API และ/หรือการเรียกใช้ไม่สําเร็จด้วยเหตุผลบางประการ
if (!navigator.mediaDevices?.getUserMedia) {
video.src = "fallbackvideo.webm";
} else {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
}