เมื่อพัฒนาสำหรับเว็บ มาตรฐาน WebRTC จะมี API สำหรับการเข้าถึงกล้องและไมโครโฟนที่เชื่อมต่อกับคอมพิวเตอร์หรือสมาร์ทโฟน อุปกรณ์เหล่านี้เรียกกันโดยทั่วไปว่าอุปกรณ์สื่อ และเข้าถึงได้ด้วย JavaScript ผ่านออบเจ็กต์ navigator.mediaDevices
ซึ่งใช้อินเทอร์เฟซ MediaDevices
จากออบเจ็กต์นี้ เราสามารถแจกแจงอุปกรณ์ที่เชื่อมต่อทั้งหมด คอยดูการเปลี่ยนแปลงของอุปกรณ์ (เมื่ออุปกรณ์เชื่อมต่อหรือไม่ได้เชื่อมต่อ) และเปิดอุปกรณ์เพื่อเรียกข้อมูลสตรีมสื่อ (ดูด้านล่าง)
วิธีที่ใช้โดยทั่วไปคือการใช้ฟังก์ชัน getUserMedia()
ซึ่งจะแสดงผลสัญญาที่จะระบุค่าเป็น MediaStream
สำหรับอุปกรณ์สื่อที่ตรงกัน ฟังก์ชันนี้จะใช้ออบเจ็กต์ MediaStreamConstraints
รายการเดียวที่ระบุข้อกำหนดที่เรามี ตัวอย่างเช่น ในการเปิดไมโครโฟนและกล้องเริ่มต้น
เราจะดำเนินการต่อไปนี้
การใช้คำสัญญา
const constraints = {
'video': true,
'audio': true
}
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
console.log('Got MediaStream:', stream);
})
.catch(error => {
console.error('Error accessing media devices.', error);
});
การใช้อะซิงโครนัส/รอ
const openMediaDevices = async (constraints) => {
return await navigator.mediaDevices.getUserMedia(constraints);
}
try {
const stream = openMediaDevices({'video':true,'audio':true});
console.log('Got MediaStream:', stream);
} catch(error) {
console.error('Error accessing media devices.', error);
}
การเรียก getUserMedia()
จะเรียกใช้คำขอสิทธิ์ หากผู้ใช้ยอมรับสิทธิ์ดังกล่าว ระบบจะแก้ปัญหาสัญญาด้วย MediaStream
ที่มีวิดีโอและแทร็กเสียง 1 แทร็ก หากสิทธิ์ถูกปฏิเสธ ระบบจะส่ง PermissionDeniedError
ในกรณีที่ไม่มีอุปกรณ์ที่ตรงกันที่เชื่อมต่ออยู่ ระบบจะส่ง NotFoundError
เอกสารอ้างอิง API ทั้งหมดสำหรับอินเทอร์เฟซ MediaDevices
สามารถดูได้ที่เอกสารในเว็บ MDN
กำลังค้นหาอุปกรณ์สื่อ
ในแอปพลิเคชันที่ซับซ้อนขึ้น เรามักต้องการตรวจสอบกล้องและไมโครโฟนที่เชื่อมต่ออยู่ทั้งหมด และให้ความคิดเห็นที่เหมาะสมแก่ผู้ใช้ ซึ่งทำได้ด้วยการเรียกใช้ฟังก์ชัน enumerateDevices()
ซึ่งจะแสดงผลสัญญาที่แปลค่าเป็นอาร์เรย์ของ MediaDevicesInfo
ที่อธิบายอุปกรณ์สื่อที่รู้จักแต่ละเครื่อง เราสามารถใช้ UI นี้เพื่อนำเสนอ UI แก่ผู้ใช้ แล้วผู้ใช้ให้เลือก URL ที่ต้องการ MediaDevicesInfo
แต่ละรายการมีพร็อพเพอร์ตี้ชื่อ kind
ที่มีค่า audioinput
, audiooutput
หรือ videoinput
ซึ่งบ่งบอกว่าเป็นอุปกรณ์สื่อประเภทใด
การใช้คำสัญญา
function getConnectedDevices(type, callback) {
navigator.mediaDevices.enumerateDevices()
.then(devices => {
const filtered = devices.filter(device => device.kind === type);
callback(filtered);
});
}
getConnectedDevices('videoinput', cameras => console.log('Cameras found', cameras));
การใช้อะซิงโครนัส/รอ
async function getConnectedDevices(type) {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(device => device.kind === type)
}
const videoCameras = getConnectedDevices('videoinput');
console.log('Cameras found:', videoCameras);
กำลังฟังการเปลี่ยนแปลงของอุปกรณ์
คอมพิวเตอร์ส่วนใหญ่รองรับการเสียบอุปกรณ์หลายเครื่องระหว่างรันไทม์ โดยอาจเป็นเว็บแคมที่เชื่อมต่อด้วย USB ชุดหูฟังบลูทูธ หรือชุดลำโพงภายนอก เพื่อให้รองรับการดำเนินการนี้ได้อย่างเหมาะสม เว็บแอปพลิเคชันควรติดตามการเปลี่ยนแปลงของอุปกรณ์สื่อ ซึ่งทำได้ด้วยการเพิ่ม Listener ไปยัง navigator.mediaDevices
สำหรับเหตุการณ์ devicechange
// Updates the select element with the provided set of cameras
function updateCameraList(cameras) {
const listElement = document.querySelector('select#availableCameras');
listElement.innerHTML = '';
cameras.map(camera => {
const cameraOption = document.createElement('option');
cameraOption.label = camera.label;
cameraOption.value = camera.deviceId;
}).forEach(cameraOption => listElement.add(cameraOption));
}
// Fetch an array of devices of a certain type
async function getConnectedDevices(type) {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(device => device.kind === type)
}
// Get the initial set of cameras connected
const videoCameras = getConnectedDevices('videoinput');
updateCameraList(videoCameras);
// Listen for changes to media devices and update the list accordingly
navigator.mediaDevices.addEventListener('devicechange', event => {
const newCameraList = getConnectedDevices('video');
updateCameraList(newCameraList);
});
ข้อจำกัดของสื่อ
ออบเจ็กต์ข้อจำกัดซึ่งต้องใช้อินเทอร์เฟซ MediaStreamConstraints
ที่เราส่งผ่านเป็นพารามิเตอร์ไปยัง getUserMedia()
ช่วยให้เราเปิดอุปกรณ์สื่อที่ตรงกับข้อกำหนดบางอย่างได้ ข้อกำหนดนี้อาจมีคำจำกัดความแบบคร่าวๆ (เสียงและ/หรือวิดีโอ) หรือที่เฉพาะเจาะจงมาก (ความละเอียดของกล้องขั้นต่ำหรือรหัสอุปกรณ์ที่แน่นอน) ขอแนะนำให้แอปพลิเคชันที่ใช้ getUserMedia()
API ตรวจสอบอุปกรณ์ที่มีอยู่ก่อน จากนั้นระบุข้อจำกัดที่ตรงกับอุปกรณ์ที่แน่นอนโดยใช้ข้อจำกัด deviceId
นอกจากนี้ หากเป็นไปได้ อุปกรณ์จะได้รับการกำหนดค่าตามข้อจำกัดด้วย เราเปิดใช้การตัดเสียงก้องบนไมโครโฟนหรือตั้งค่าความกว้างและความสูงขั้นต่ำของวิดีโอจากกล้องได้
async function getConnectedDevices(type) {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(device => device.kind === type)
}
// Open camera with at least minWidth and minHeight capabilities
async function openCamera(cameraId, minWidth, minHeight) {
const constraints = {
'audio': {'echoCancellation': true},
'video': {
'deviceId': cameraId,
'width': {'min': minWidth},
'height': {'min': minHeight}
}
}
return await navigator.mediaDevices.getUserMedia(constraints);
}
const cameras = getConnectedDevices('videoinput');
if (cameras && cameras.length > 0) {
// Open first available video camera with a resolution of 1280x720 pixels
const stream = openCamera(cameras[0].deviceId, 1280, 720);
}
ดูเอกสารประกอบฉบับเต็มสำหรับอินเทอร์เฟซ MediaStreamConstraints
ได้ที่เอกสารในเว็บ MN
การเล่นในเครื่อง
เมื่อเปิดอุปกรณ์สื่อและเรามี MediaStream
พร้อมใช้งาน เราจะกำหนดอุปกรณ์ดังกล่าวให้กับองค์ประกอบวิดีโอหรือเสียงเพื่อเล่นสตรีมในเครื่องได้
async function playVideoFromCamera() {
try {
const constraints = {'video': true, 'audio': true};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const videoElement = document.querySelector('video#localVideo');
videoElement.srcObject = stream;
} catch(error) {
console.error('Error opening video camera.', error);
}
}
HTML ที่จำเป็นสำหรับองค์ประกอบวิดีโอทั่วไปที่ใช้กับ getUserMedia()
มักมีแอตทริบิวต์ autoplay
และ playsinline
แอตทริบิวต์ autoplay
จะทำให้สตรีมใหม่ที่กำหนดให้กับองค์ประกอบเล่นโดยอัตโนมัติ
แอตทริบิวต์ playsinline
อนุญาตให้เล่นวิดีโอในหน้า แทนการเล่นแบบเต็มหน้าจอบนเบราว์เซอร์ในอุปกรณ์เคลื่อนที่บางเบราว์เซอร์ นอกจากนี้ ขอแนะนำให้ใช้ controls="false"
สำหรับสตรีมแบบสดด้วย เว้นแต่ผู้ใช้ควรหยุดชั่วคราวได้
<html>
<head><title>Local video playback</title></head>
<body>
<video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>