Google is committed to advancing racial equity for Black communities. See how.
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Premiers pas avec les périphériques multimédias

Lors du développement pour le Web, la norme WebRTC fournit des API pour accéder aux caméras et microphones connectés à l'ordinateur ou au smartphone. Ces périphériques sont communément appelés Périphériques multimédia et sont accessibles avec JavaScript via l'objet navigator.mediaDevices , qui implémente l'interface MediaDevices . À partir de cet objet, nous pouvons énumérer tous les appareils connectés, écouter les changements d'appareil (lorsqu'un appareil est connecté ou déconnecté) et ouvrir un appareil pour récupérer un flux multimédia (voir ci-dessous).

La manière la plus courante de l'utiliser est la fonction getUserMedia() , qui renvoie une promesse qui se résoudra en un MediaStream pour les périphériques multimédias correspondants. Cette fonction prend un seul objet MediaStreamConstraints qui spécifie les exigences que nous avons. Par exemple, pour simplement ouvrir le microphone et la caméra par défaut, nous ferions ce qui suit.

Utiliser les promesses

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

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

L'appel à getUserMedia() déclenchera une demande d'autorisations. Si l'utilisateur accepte l'autorisation, la promesse est résolue avec un MediaStream contenant une vidéo et une piste audio. Si l'autorisation est refusée, une PermissionDeniedError est levée. Dans le cas où aucun périphérique correspondant n'est connecté, une NotFoundError sera lancée.

La référence complète de l'API pour l'interface MediaDevices est disponible dans la documentation Web MDN .

Interroger les périphériques multimédias

Dans une application plus complexe, nous voudrons probablement vérifier toutes les caméras et microphones connectés et fournir les commentaires appropriés à l'utilisateur. Cela peut être fait en appelant la fonction enumerateDevices() . Cela renverra une promesse qui se résout en un tableau de MediaDevicesInfo qui décrivent chaque périphérique multimédia connu. Nous pouvons l'utiliser pour présenter une interface utilisateur à l'utilisateur qui lui permet de choisir celle qu'il préfère. Chaque MediaDevicesInfo contient une propriété nommée kind avec la valeur audioinput , audiooutput ou videoinput , indiquant de quel type de périphérique multimédia il s'agit.

Utiliser les promesses

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

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

Écoute des changements d'appareils

La plupart des ordinateurs prennent en charge la connexion de divers périphériques pendant l'exécution. Il peut s'agir d'une webcam connectée par USB, d'un casque Bluetooth ou d'un ensemble de haut-parleurs externes. Afin de prendre en charge correctement cela, une application Web doit écouter les changements de périphériques multimédias. Cela peut être fait en ajoutant un écouteur à navigator.mediaDevices pour l'événement 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);
});
 

Contraintes médiatiques

L'objet contraintes, qui doit implémenter l'interface MediaStreamConstraints , que nous passons en paramètre à getUserMedia() nous permet d'ouvrir un périphérique multimédia qui correspond à une certaine exigence. Cette exigence peut être définie de manière très vague (audio et / ou vidéo) ou très spécifique (résolution minimale de la caméra ou identifiant exact de l'appareil). Il est recommandé que les applications qui utilisent l'API getUserMedia() vérifient d'abord les périphériques existants, puis spécifient une contrainte qui correspond au périphérique exact à l'aide de la contrainte deviceId . Les appareils seront également, si possible, configurés en fonction des contraintes. Nous pouvons activer l'annulation d'écho sur les microphones ou définir une largeur et une hauteur spécifiques ou minimales de la vidéo de la caméra.

 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 documentation complète de l'interface MediaStreamConstraints se trouve sur la documentation Web MDN .

Lecture locale

Une fois qu'un périphérique multimédia a été ouvert et que nous avons un MediaStream disponible, nous pouvons l'attribuer à un élément vidéo ou audio pour lire le flux localement.

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

Le HTML nécessaire pour un élément vidéo typique utilisé avec getUserMedia() aura généralement les attributs autoplay et playsinline . L'attribut de autoplay entraînera la lecture automatique des nouveaux flux affectés à l'élément. L'attribut playsinline permet de lire la vidéo en ligne, plutôt qu'en plein écran, sur certains navigateurs mobiles. Il est également recommandé d'utiliser controls="false" pour les diffusions en direct, sauf si l'utilisateur doit pouvoir les mettre en pause.

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