GetUserMedia: примеры (JAVASCRIPT)
getUserMedia(constraints: MediaStreamConstraints): PromiseОсновы функции getUserMedia
Метод getUserMedia() является частью API WebRTC и предоставляет доступ к медиаустройствам пользователя, таким как камера и микрофон, через браузер. Функция используется для захвата аудио и видео потоков в реальном времени для последующей обработки, записи или передачи.
Метод вызывается через объект navigator.mediaDevices. Основной сценарий применения - видеозвонки, запись видео и аудио, фотографирование через веб-камеру, анализ медиаданных.
Аргументы функции
Функция принимает один обязательный аргумент - объект ограничений (constraints):
audio: Boolean или объект с настройками аудиоvideo: Boolean или объект с настройками видеоpreferCurrentTab(новое): Предпочтение захвата с текущей вкладки
Возвращаемое значение
Функция возвращает Promise, который разрешается объектом MediaStream, содержащим запрошенные медиапотоки. В случае ошибки Promise отклоняется с объектом DOMException.
Базовые примеры использования
Пример 1: Запрос доступа только к камере
async function getCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: false
});
console.log('Получен видеопоток');
return stream;
} catch (error) {
console.error('Ошибка доступа к камере:', error);
}
}// Результат: MediaStream объект с видеодорожкой
Пример 2: Запрос аудио и видео с ограничениями
const constraints = {
audio: {
sampleRate: 44100,
channelCount: 2
},
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 },
facingMode: 'user'
}
};
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
console.log('Разрешение видео:', stream.getVideoTracks()[0].getSettings().width);
})
.catch(err => {
console.log(err.name + ': ' + err.message);
});// Результат при успехе: разрешение видео близкое к 1280x720
Альтернативные API в JavaScript
getDisplayMedia() - захват содержимого экрана или окна приложения. Используется для скринкастинга и записи презентаций.
async function captureScreen() {
try {
return await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
});
} catch (err) {
console.error('Ошибка захвата экрана:', err);
}
}enumerateDevices() - получение списка доступных медиаустройств без запроса разрешений. Помогает предварительно определить доступное оборудование.
Выбор API зависит от задачи: getUserMedia для камеры/микрофона, getDisplayMedia для захвата экрана.
Решения на других языках программирования
Python (OpenCV) - библиотека для захвата видео с камеры
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow('Camera', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()Java (JavaCV) - кроссплатформенное решение для работы с медиа
C++ (libwebrtc) - низкоуровневая библиотека WebRTC
Основное отличие JavaScript реализации - работа в песочнице браузера с обязательным запросом разрешения пользователя.
Распространенные ошибки
Ошибка 1: Необработанный отказ в разрешении
// Неправильно
navigator.mediaDevices.getUserMedia({ video: true });
// Правильно
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
// обработка успеха
})
.catch(error => {
if (error.name === 'NotAllowedError') {
console.log('Пользователь отказал в доступе');
} else if (error.name === 'NotFoundError') {
console.log('Устройство не найдено');
}
});Ошибка 2: Несовместимые ограничения
// Может вызвать OverconstrainedError
const constraints = {
video: {
width: { exact: 5000 }, // Неподдерживаемое значение
height: { exact: 5000 }
}
};История изменений API
Раньше метод был доступен как navigator.getUserMedia(), но теперь является частью navigator.mediaDevices. Добавлена поддержка Promise вместо callback.
В современных браузерах добавлены новые возможности:
- Свойство
preferCurrentTabдля Screen Capture API - Улучшенная обработка устройств с несколькими камерами
- Поддержка HDR видео в некоторых реализациях
- Автоматический выбор качества в зависимости от сетевых условий
Расширенные сценарии применения
Пример 1: Запись аудио с визуализацией
let audioContext, analyser, microphone;
async function startAudioAnalysis() {
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: false,
noiseSuppression: false,
autoGainControl: false
}
});
audioContext = new AudioContext();
analyser = audioContext.createAnalyser();
microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(analyser);
analyser.fftSize = 2048;
// Визуализация аудио
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
function draw() {
analyser.getByteTimeDomainData(dataArray);
// отрисовка волны
requestAnimationFrame(draw);
}
draw();
}Пример 2: Переключение между камерами
let currentStream;
async function switchCamera() {
if (currentStream) {
currentStream.getTracks().forEach(track => track.stop());
}
const devices = await navigator.mediaDevices.enumerateDevices();
const videoDevices = devices.filter(device => device.kind === 'videoinput');
if (videoDevices.length < 2) {
console.log('Только одна камера доступна');
return;
}
const currentDevice = currentStream
? currentStream.getVideoTracks()[0].getSettings().deviceId
: null;
const nextDevice = videoDevices.find(
device => device.deviceId !== currentDevice
);
currentStream = await navigator.mediaDevices.getUserMedia({
video: { deviceId: { exact: nextDevice.deviceId } }
});
// Применение нового потока к видео элементу
videoElement.srcObject = currentStream;
}Пример 3: Захват с логированием метаданных
async function captureWithMetadata() {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
advanced: [{
width: 1920,
height: 1080,
frameRate: { ideal: 60 }
}]
}
});
const videoTrack = stream.getVideoTracks()[0];
const settings = videoTrack.getSettings();
const capabilities = videoTrack.getCapabilities();
console.log('Текущие настройки:', {
resolution: `${settings.width}x${settings.height}`,
frameRate: settings.frameRate,
deviceId: settings.deviceId
});
console.log('Возможности устройства:', {
supportedResolutions: capabilities.width ?
`от ${capabilities.width.min} до ${capabilities.width.max}` : 'не определено',
supportedFramerates: capabilities.frameRate ?
`от ${capabilities.frameRate.min} до ${capabilities.frameRate.max}` : 'не определено'
});
return stream;
}