En Google, luchamos por la equidad racial de la comunidad negra. Más información

Introducción a los dispositivos multimedia

Al desarrollar para la web, el estándar WebRTC proporciona API para acceder a cámaras y micrófonos conectados a la computadora o teléfono inteligente. Estos dispositivos se denominan comúnmente como dispositivos de medios y se puede acceder con JavaScript a través de la navigator.mediaDevices objeto, que implementa el MediaDevices de interfaz. Desde este objeto podemos enumerar todos los dispositivos conectados, escuchar los cambios de dispositivo (cuando un dispositivo está conectado o desconectado) y abrir un dispositivo para recuperar un flujo de medios (ver más abajo).

La forma más común de esto se utiliza es a través de la función getUserMedia() , que devuelve una promesa que se resolverá a un MediaStream para los dispositivos de medios coincidentes. Esta función toma un solo MediaStreamConstraints objeto que especifica los requisitos que tenemos. Por ejemplo, para abrir simplemente el micrófono y la cámara predeterminados, haríamos lo siguiente.

Usar promesas

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);
    });

Usando 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);
}

La llamada a getUserMedia() dará lugar a una solicitud de permisos. Si el usuario acepta la autorización, la promesa se resuelve con una MediaStream que contiene un vídeo y una pista de audio. Si se deniega el permiso, un PermissionDeniedError es lanzada. En caso de que no hay dispositivos coincidentes conectados, un NotFoundError será lanzada.

La referencia de la API completa para el MediaDevices interfaz está disponible en el MDN documentos web .

Consultar dispositivos multimedia

En una aplicación más compleja, lo más probable es que deseemos comprobar todas las cámaras y micrófonos conectados y proporcionar la retroalimentación adecuada al usuario. Esto se puede hacer llamando a la función enumerateDevices() . Esto devolverá una promesa que se resuelve en una matriz de MediaDevicesInfo que describen cada dispositivo de medios conocida. Podemos usar esto para presentar una interfaz de usuario al usuario que les permita elegir la que prefieran. Cada MediaDevicesInfo contiene una propiedad denominada kind con el valor audioinput , audiooutput o videoinput , indicando qué tipo de dispositivo de medios que es.

Usar promesas

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));

Usando 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);

Escuchar cambios en los dispositivos

La mayoría de las computadoras admiten la conexión de varios dispositivos durante el tiempo de ejecución. Podría ser una cámara web conectada por USB, unos auriculares Bluetooth o un conjunto de altavoces externos. Para admitir esto de manera adecuada, una aplicación web debe escuchar los cambios de los dispositivos multimedia. Esto puede hacerse mediante la adición de un oyente a navigator.mediaDevices para la devicechange evento.

// 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);
});

Limitaciones de los medios

Las limitaciones de objeto, que debe implementar la MediaStreamConstraints interfaz, que se pasa como parámetro a getUserMedia() nos permite abrir un dispositivo de medios que coincide con un cierto requisito. Este requisito puede estar definido de manera muy vaga (audio y / o video) o muy específico (resolución mínima de la cámara o una identificación exacta del dispositivo). Se recomienda que las aplicaciones que utilizan el getUserMedia() API compruebe primero los dispositivos existentes y luego especifica una restricción que corresponda al dispositivo exacta con el deviceId restricción. Los dispositivos también, si es posible, se configurarán de acuerdo con las restricciones. Podemos habilitar la cancelación de eco en micrófonos o establecer un ancho y alto específico o mínimo del video de la cámara.

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);
}

La documentación completa para la MediaStreamConstraints interfaz se puede encontrar en los documentos web MDN .

Reproducción local

Una vez que un dispositivo de medios ha sido abierto y tenemos un MediaStream disponibles, podemos asignar a un elemento de vídeo o de audio para reproducir la secuencia localmente.

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);
    }
}

El código HTML necesario para un elemento de vídeo típica utilizada con getUserMedia() por lo general tienen los atributos autoplay y playsinline . La autoplay atributo hará que nuevos flujos asignados al elemento para reproducir automáticamente. El playsinline atributo permite que el vídeo juego en línea, en lugar de sólo en pantalla completa, en algunos navegadores móviles. También se recomienda el uso de controls="false" para transmisiones en directo, a menos que el usuario debe ser capaz de hacer una pausa en ellos.

<html>
<head><title>Local video playback</video></head>
<body>
    <video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>