במהלך הפיתוח לאינטרנט, תקן 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);
});
שימוש באסינכרוני/await
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
שמכיל
סרטון אחד וטראק אחד של אודיו. אם ההרשאה נדחית,
זריקה של PermissionDeniedError
. למקרה שאין מכשירים תואמים
מחובר, ייפסל NotFoundError
.
הפניית ה-API המלאה של הממשק MediaDevices
זמינה ב-MDN באינטרנט
מסמכים.
שליחת שאילתות למכשירי מדיה
באפליקציה מורכבת יותר, סביר להניח שנרצה לבדוק את כל
ממצלמות ומיקרופונים מחוברים ולספק את המשוב המתאים
משתמש. כדי לעשות זאת, שולחים קריאה לפונקציה enumerateDevices()
. הפעולה הזו תגרור
מחזירה הבטחה שפונה למערך של MediaDevicesInfo
שמתאר
כל מכשיר מדיה ידוע. אנחנו יכולים להשתמש בזה כדי להציג למשתמש ממשק משתמש,
הם יבחרו את זה שהם מעדיפים. כל 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));
שימוש באסינכרוני/await
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, אוזניות Bluetooth או קבוצת רמקולים חיצוניים. לחשבון
כדי לתמוך בכך באופן תקין, אפליקציית אינטרנט צריכה להאזין לשינויים
של מכשירים לאחסון מדיה. כדי לעשות זאת, אפשר להוסיף את ה-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()
, מאפשר לנו לפתוח
מכשיר מדיה שתואם לדרישה מסוימת. הדרישה הזו יכולה להיות
מוגדר באופן חלש (אודיו ו/או וידאו), או ספציפי מאוד (מצלמה מינימלית
או מזהה מכשיר מדויק). מומלץ שאפליקציות שמשתמשות
ה-API של getUserMedia()
בודק קודם את המכשירים הקיימים ואז מציין
אילוץ שתואם למכשיר המדויק באמצעות האילוץ 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
באתר האינטרנט של MDN
מסמכים.
הפעלה מקומית
ברגע שפותחים מכשיר מדיה ויש לנו 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>