شروع کار با دستگاه های رسانه ای

هنگام توسعه برای وب، استاندارد WebRTC APIهایی را برای دسترسی به دوربین ها و میکروفون های متصل به رایانه یا تلفن هوشمند ارائه می دهد. این دستگاه‌ها معمولاً به عنوان Media Devices شناخته می‌شوند و می‌توان با جاوا اسکریپت از طریق شی 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);
    });

استفاده از async/wait

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 web docs موجود است.

پرس و جو از دستگاه های رسانه ای

در یک برنامه پیچیده تر، ما به احتمال زیاد می خواهیم تمام دوربین ها و میکروفون های متصل را بررسی کنیم و بازخورد مناسب را به کاربر ارائه دهیم. این کار را می توان با فراخوانی تابع 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));

استفاده از async/wait

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، یک هدست بلوتوث یا مجموعه ای از بلندگوهای خارجی باشد. به منظور پشتیبانی مناسب از این، یک برنامه وب باید به تغییرات دستگاه های رسانه گوش دهد. این را می توان با افزودن شنونده به 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 را می توان در اسناد وب 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>