Мультимедиа-устройства

Обновлено: 2024-03-12
4 мин

Мультимедиа-устройства

Начало работы с мультимедийными устройствами

При web-разработке WebRTC-стандарт предоставляет API для доступа к камерам и микрофонам, подключенным к компьютеру или смартфону. Эти устройства обычно называются мультимедийными устройствами, и к ним можно получить доступ с помощью Java-скрипта через объект 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/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 доступен по ссылке https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices

Обращение к мультимедиа-устройствам

В более сложных приложениях, мы скорее всего захотим проверить все подключенные камеры и микрофоны и дать соответствующий отчет пользователю. Это можно сделать через запрос функции 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/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-гарнитура или внешние динамики. Чтобы должным образом поддерживать все это, веб-приложение должно отслеживать изменения в статусах мультимедиа-устройств. Это можно сделать, добавив «отслеживатель» в 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(), позволяет нам открывать мультимедиа-устройство, которое отвечает определенным требованиям. Эти требования могут быть как очень расплывчатыми (аудио и/или видео), так и очень специфичными (минимальное разрешение камеры или точный ID устройства). Рекомендуем, чтобы приложения, использующие 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 можно найти по ссылке: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints

Локальное воспроизведение

Как только мультимедиа-устройство открыто и есть доступный 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</video></head>
<body>
    <video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>