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 le retour approprié à 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 appareils 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 requis pour un élément vidéo typique utilisé avec getUserMedia()
aura généralement les attributs autoplay
et playsinline
. L'attribut 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, à moins que l'utilisateur ne puisse les mettre en pause.
<html>
<head><title>Local video playback</video></head>
<body>
<video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>