Nello sviluppo per il web, lo standard WebRTC fornisce API per l'accesso
videocamere e microfoni collegati al computer o allo smartphone. Questi dispositivi
sono comunemente noti come dispositivi multimediali e sono accessibili con JavaScript
tramite l'oggetto navigator.mediaDevices
, che implementa l'elemento MediaDevices
a riga di comando. Da questo oggetto possiamo enumerare tutti i dispositivi connessi, ascoltare
modifiche al dispositivo (quando un dispositivo è connesso o disconnesso) e apri un dispositivo
per recuperare uno stream multimediale (vedi di seguito).
Il modo più comune utilizzato per questo scopo è tramite la funzione getUserMedia()
, che
restituisce una promessa che si risolverà in un MediaStream
per i contenuti multimediali corrispondenti
dispositivi mobili. Questa funzione prende un singolo oggetto MediaStreamConstraints
che
specifica i nostri requisiti. Ad esempio, per aprire
microfono e fotocamera predefiniti, procederemo nel seguente modo.
Utilizzo delle promesse
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);
});
Utilizzo asincrono/Attendi
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 chiamata a getUserMedia()
attiverà una richiesta di autorizzazione. Se l'utente
accetta l'autorizzazione, la promessa viene risolta con un MediaStream
contenente
un video e una traccia audio. Se l'autorizzazione viene negata,
PermissionDeniedError
viene lanciata. Nel caso in cui non ci siano dispositivi corrispondenti
connesso, verrà restituito un NotFoundError
.
Il riferimento completo dell'API per l'interfaccia MediaDevices
è disponibile all'indirizzo MDN web
documenti.
Esecuzione di query sui dispositivi multimediali
In una richiesta più complessa, probabilmente vorrai controllare tutte le
videocamere e microfoni collegati e fornire il feedback appropriato alle
utente. A questo scopo, puoi richiamare la funzione enumerateDevices()
. In questo modo
restituiscono una promessa che si risolve in un array di MediaDevicesInfo
che descrive
ogni dispositivo multimediale noto. Possiamo usarlo per presentare all'utente una UI che,
scegli quello che preferiscono. Ogni MediaDevicesInfo
contiene una proprietà denominata
kind
con il valore audioinput
, audiooutput
o videoinput
, che indica
di che tipo di dispositivo multimediale si tratta.
Utilizzo delle promesse
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));
Utilizzo asincrono/Attendi
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);
Ascolto dei cambiamenti dei dispositivi
La maggior parte dei computer supporta il collegamento di diversi dispositivi in fase di runtime. Potrebbe essere un
webcam connessa tramite USB, cuffie Bluetooth o set di altoparlanti esterni. Nella
per supportarlo correttamente, un'applicazione web deve rilevare le modifiche
dei dispositivi multimediali. A questo scopo, puoi aggiungere un listener
navigator.mediaDevices
per l'evento 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);
});
Vincoli dei contenuti multimediali
L'oggetto constraints, che deve implementare l'elemento MediaStreamConstraints
dell'interfaccia utente, che passiamo come parametro a getUserMedia()
, ci consente di aprire
dispositivo multimediale
che soddisfa un determinato requisito. Questo requisito può essere molto
definiti in modo generico (audio e/o video) o molto specifici (numero minimo di videocamere
risoluzione massima o un ID dispositivo esatto). È consigliabile che le applicazioni che utilizzano
l'API getUserMedia()
controlla prima i dispositivi esistenti, quindi specifica
vincolo che corrisponde esattamente al dispositivo utilizzando il vincolo deviceId
.
I dispositivi verranno anche, se possibile, configurati in base ai vincoli. Me
puoi attivare la cancellazione dell'eco sui microfoni o impostare una larghezza minima o specifica
e l'altezza del video dalla videocamera.
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);
}
È disponibile la documentazione completa per l'interfaccia MediaStreamConstraints
sul web MDN
documenti.
Riproduzione locale
Una volta aperto un dispositivo multimediale e disponibile un MediaStream
,
può assegnarlo a un elemento video o audio per riprodurlo 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);
}
}
Il codice HTML necessario per un tipico elemento video utilizzato con getUserMedia()
di solito hanno gli attributi autoplay
e playsinline
. autoplay
riprodurrà automaticamente i nuovi stream assegnati all'elemento.
L'attributo playsinline
consente di riprodurre il video in linea, anziché solo per intero.
schermo su alcuni browser mobile. È inoltre consigliabile utilizzare
controls="false"
per i live streaming, a meno che l'utente non possa mettere in pausa
che li rappresentano.
<html>
<head><title>Local video playback</title></head>
<body>
<video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>