Bei der Entwicklung für das Web bietet der WebRTC-Standard APIs für den Zugriff auf Kameras und Mikrofone, die mit dem Computer oder Smartphone verbunden sind. Diese Geräte werden allgemein als Mediengeräte bezeichnet und sind mit JavaScript über das Objekt navigator.mediaDevices
zugänglich, das die MediaDevices
-Schnittstelle implementiert. Über dieses Objekt können wir alle verbundenen Geräte auflisten, auf Geräteänderungen warten (wenn ein Gerät verbunden oder getrennt wird) und ein Gerät öffnen, um einen Media Stream abzurufen (siehe unten).
Am häufigsten wird dies über die Funktion getUserMedia()
verwendet. Sie gibt ein Versprechen zurück, das für die übereinstimmenden Mediengeräte in ein MediaStream
aufgelöst wird. Diese Funktion verwendet ein einzelnes MediaStreamConstraints
-Objekt, das unsere Anforderungen angibt. Um beispielsweise einfach das Standardmikrofon und die Standardkamera zu öffnen, würden wir wie folgt vorgehen.
Promise-Objekte verwenden
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);
});
„async/await“ verwenden
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);
}
Der Aufruf von getUserMedia()
löst eine Berechtigungsanfrage aus. Wenn der Nutzer die Berechtigung annimmt, wird das Versprechen mit einem MediaStream
aufgelöst, das ein Video und einen Audiotrack enthält. Wenn die Berechtigung verweigert wird, wird ein PermissionDeniedError
ausgelöst. Falls keine passenden Geräte verbunden sind, wird ein NotFoundError
ausgegeben.
Die vollständige API-Referenz für die MediaDevices
-Schnittstelle findest du unter MDN-Webdokumente.
Mediengeräte abfragen
Bei einer komplexeren Anwendung möchten wir höchstwahrscheinlich alle verbundenen Kameras und Mikrofone überprüfen und dem Nutzer das entsprechende Feedback geben. Dazu kann die Funktion enumerateDevices()
aufgerufen werden. Dadurch wird ein Versprechen zurückgegeben, das in ein Array von MediaDevicesInfo
aufgelöst wird, die alle bekannten Mediengeräte beschreiben. Damit können wir dem Nutzer eine UI präsentieren,
auf der er seine bevorzugte auswählen kann. Jeder MediaDevicesInfo
enthält ein Attribut namens kind
mit dem Wert audioinput
, audiooutput
oder videoinput
, das angibt, um welche Art von Mediengerät es sich handelt.
Promise-Objekte verwenden
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));
„async/await“ verwenden
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);
Warten auf Geräteänderungen
Die meisten Computer unterstützen das Anschließen verschiedener Geräte während der Laufzeit. Es kann sich dabei um eine über USB verbundene Webcam, ein Bluetooth-Headset oder eine Reihe externer Lautsprecher handeln. Damit dies ordnungsgemäß unterstützt wird, sollte eine Webanwendung auf Änderungen der Mediengeräte warten. Fügen Sie dazu navigator.mediaDevices
einen Listener für das Ereignis devicechange
hinzu.
// 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);
});
Medieneinschränkungen
Mit dem Einschränkungsobjekt, das die MediaStreamConstraints
-Schnittstelle implementieren muss und als Parameter an getUserMedia()
übergeben wird, kann ein Mediengerät geöffnet werden, das eine bestimmte Anforderung erfüllt. Diese Anforderung kann sehr locker definiert (Audio und/oder Video) oder sehr spezifisch (minimale Kameraauflösung oder genaue Geräte-ID) sein. Anwendungen, die die getUserMedia()
API verwenden, sollten zuerst die vorhandenen Geräte prüfen und dann mithilfe der Einschränkung deviceId
eine Einschränkung angeben, die genau mit dem Gerät übereinstimmt.
Außerdem werden Geräte, wenn möglich, gemäß den Einschränkungen konfiguriert. Wir können die Echounterdrückung auf Mikrofonen aktivieren oder eine bestimmte oder Mindestbreite und -höhe für das Video von der Kamera festlegen.
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);
}
Die vollständige Dokumentation zur MediaStreamConstraints
-Schnittstelle finden Sie in den MDN-Webdokumenten.
Lokale Wiedergabe
Sobald ein Mediengerät geöffnet wurde und ein MediaStream
verfügbar ist, können wir es einem Video- oder Audioelement zuweisen, um den Stream lokal abzuspielen.
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);
}
}
Der HTML-Code, der für ein typisches Videoelement erforderlich ist, das mit getUserMedia()
verwendet wird, hat in der Regel die Attribute autoplay
und playsinline
. Das Attribut autoplay
sorgt dafür, dass neue Streams, die dem Element zugewiesen sind, automatisch wiedergegeben werden.
Mit dem Attribut playsinline
können Videos in bestimmten mobilen Browsern inline und nicht nur im Vollbildmodus abgespielt werden. Außerdem wird die Verwendung von controls="false"
für Livestreams empfohlen, es sei denn, der Nutzer sollte die Möglichkeit haben, sie zu pausieren.
<html>
<head><title>Local video playback</title></head>
<body>
<video id="localVideo" autoplay playsinline controls="false"/>
</body>
</html>