תחילת העבודה עם מכשירי מדיה

במהלך הפיתוח לאינטרנט, תקן 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>