Einführung
Die Audio-/Videoaufnahme war lange Zeit der „heilige Gral“ der Webentwicklung. Viele Jahre lang waren wir auf Browser-Plug-ins (Flash oder Silverlight) angewiesen, um unsere Arbeit zu erledigen. Komm schon!
HTML5 als Lösung. Es ist vielleicht nicht offensichtlich, aber mit dem Aufkommen von HTML5 hat sich der Zugriff auf Gerätehardware stark erhöht. Geolocation (GPS), die Orientation API (Beschleunigungsmesser), WebGL (GPU) und die Web Audio API (Audiohardware) sind perfekte Beispiele. Diese Funktionen sind unglaublich leistungsstark und bieten JavaScript-APIs auf hoher Ebene, die auf den zugrunde liegenden Hardwarefunktionen des Systems basieren.
In dieser Anleitung wird eine neue API, GetUserMedia, vorgestellt, mit der Web-Apps auf die Kamera und das Mikrofon eines Nutzers zugreifen können.
Der Weg zu getUserMedia()
Wenn Sie die Geschichte der getUserMedia()
API nicht kennen, ist es interessant zu erfahren, wie wir zu ihr gekommen sind.
In den letzten Jahren haben sich mehrere Varianten von „Media Capture APIs“ entwickelt. Viele erkannten die Notwendigkeit, auf native Geräte im Web zugreifen zu können, aber das führte dazu, dass jeder und seine Mutter eine neue Spezifikation erstellten. Die Dinge wurden so unübersichtlich, dass das W3C schließlich beschloss, eine Arbeitsgruppe zu gründen. Ihr einziger Zweck? Den Wahnsinn verstehen Die Device APIs Policy (DAP) Working Group (Arbeitsgruppe für Geräte-APIs) hat die Aufgabe, die Vielzahl von Vorschlägen zu konsolidieren und zu standardisieren.
Ich versuche, das Geschehene im Jahr 2011 zusammenzufassen…
Runde 1: HTML Media Capture
HTML Media Capture war der erste Versuch des DAP, die Media Capture-Funktion im Web zu standardisieren. Dazu wird <input type="file">
überladen und es werden neue Werte für den Parameter accept
hinzugefügt.
Wenn Sie Nutzern erlauben möchten, mit der Webcam einen Schnappschuss von sich selbst zu machen, ist das mit capture=camera
möglich:
<input type="file" accept="image/*;capture=camera">
Das Aufnehmen von Videos oder Audioinhalten funktioniert ähnlich:
<input type="file" accept="video/*;capture=camcorder"> <input type="file" accept="audio/*;capture=microphone">
Ganz schön, oder? Besonders gut gefällt mir, dass eine Dateieingabe wiederverwendet wird. Semantisch macht das viel Sinn. Diese spezielle „API“ hat jedoch den Nachteil, dass keine Echtzeiteffekte möglich sind (z.B. Live-Webcam-Daten in ein <canvas>
rendern und WebGL-Filter anwenden). Mit HTML Media Capture können Sie nur eine Mediadatei aufzeichnen oder einen Snapshot erstellen.
Support:
- Android 3.0-Browser: Eine der ersten Implementierungen. In diesem Video sehen Sie, wie das funktioniert.
- Chrome für Android (0.16)
- Firefox Mobile 10.0
- iOS6 Safari und Chrome (teilweise Unterstützung)
Runde 2: Geräteelement
Viele fanden, dass HTML Media Capture zu einschränkend war. Daher wurde eine neue Spezifikation entwickelt, die alle Arten von (zukünftigen) Geräten unterstützt. Es überrascht nicht, dass für das Design ein neues Element erforderlich war, das <device>
-Element>, das zum Vorgänger von getUserMedia()
wurde.
Opera war einer der ersten Browser, in denen erste Implementierungen der Videoaufnahme auf Grundlage des <device>
-Elements erstellt wurden. Kurz danach (am selben Tag, um genau zu sein) beschloss die WhatWG, das <device>
-Tag zugunsten eines anderen aufstrebenden Tags zu verwerfen, diesmal einer JavaScript-API namens navigator.getUserMedia()
. Eine Woche später veröffentlichte Opera neue Builds, die die aktualisierte getUserMedia()
-Spezifikation unterstützten. Später in diesem Jahr schloss sich Microsoft an und veröffentlichte ein Lab für IE9, das die neue Spezifikation unterstützte.
So hätte <device>
ausgesehen:
<device type="media" onchange="update(this.data)"></device> <video autoplay></video> <script> function update(stream) { document.querySelector('video').src = stream.url; } </script>
Support:
<device>
war leider noch nie in einem veröffentlichten Browser enthalten. Eine API weniger, um die man sich kümmern muss :) <device>
hatte jedoch zwei große Vorteile: 1. Sie war semantisch und 2. Sie konnte problemlos erweitert werden, um mehr als nur Audio-/Videogeräte zu unterstützen.
Atme tief durch. Das geht so schnell!
Runde 3: WebRTC
Das <device>
-Element ist schließlich ausgestorben.
Die Suche nach einer geeigneten Capture-API wurde durch die größere WebRTC-Initiative (Web Real Time Communications) beschleunigt. Diese Spezifikation wird von der W3C WebRTC Working Group überwacht. Google, Opera, Mozilla und einige andere haben Implementierungen.
getUserMedia()
bezieht sich auf WebRTC, da es das Gateway zu dieser Gruppe von APIs ist. Sie bietet die Möglichkeit, auf den lokalen Kamera-/Mikrofonstream des Nutzers zuzugreifen.
Support:
getUserMedia()
wird seit Chrome 21, Opera 18 und Firefox 17 unterstützt.
Erste Schritte
Mit navigator.mediaDevices.getUserMedia()
können wir endlich ohne Plug-in auf Webcam- und Mikrofoneingaben zugreifen. Der Zugriff auf die Kamera ist jetzt nur noch einen Anruf entfernt, nicht mehr eine Installation. Sie ist direkt in den Browser integriert. Bist du schon gespannt?
Funktionserkennung
Die Funktionserkennung ist ein einfacher Test auf das Vorhandensein von navigator.mediaDevices.getUserMedia
:
if (navigator.mediaDevices?.getUserMedia) { // Good to go! } else { alert("navigator.mediaDevices.getUserMedia() is not supported"); }
Zugriff auf ein Eingabegerät erhalten
Wenn Sie die Webcam oder das Mikrofon verwenden möchten, müssen wir Sie um Erlaubnis bitten. Der erste Parameter für navigator.mediaDevices.getUserMedia()
ist ein Objekt, das die Details und Anforderungen für jeden Medientyp angibt, auf den Sie zugreifen möchten. Wenn Sie beispielsweise auf die Webcam zugreifen möchten, sollte der erste Parameter {video: true}
sein. Wenn Sie sowohl das Mikrofon als auch die Kamera verwenden möchten, übergeben Sie {video: true, audio: true}
:
<video autoplay></video> <script> navigator.mediaDevices .getUserMedia({ video: true, audio: true }) .then((localMediaStream) => { const video = document.querySelector("video"); video.srcObject = localMediaStream; }) .catch((error) => { console.log("Rejected!", error); }); </script>
Ok. Woran liegt das? Die Media Capture API ist ein perfektes Beispiel dafür, wie neue HTML5-APIs zusammenarbeiten. Es funktioniert in Verbindung mit unseren anderen HTML5-Freunden <audio>
und <video>
. Beachten Sie, dass wir kein src
-Attribut festlegen und keine <source>
-Elemente im <video>
-Element einfügen. Anstatt dem Video eine URL zu einer Mediendatei zu übergeben, legen wir srcObject
auf das LocalMediaStream
-Objekt fest, das die Webcam darstellt.
Außerdem weise ich <video>
an, autoplay
, da es sonst auf dem ersten Frame eingefroren wäre. Das Hinzufügen von controls
funktioniert ebenfalls wie erwartet.
Media-Einschränkungen festlegen (Auflösung, Höhe, Breite)
Mit dem ersten Parameter für getUserMedia()
können auch weitere Anforderungen (oder Einschränkungen) für den zurückgegebenen Media-Stream angegeben werden. Anstatt nur anzugeben, dass Sie grundlegenden Zugriff auf Videos benötigen (z.B. {video: true}
), können Sie beispielsweise zusätzlich festlegen, dass der Stream in HD sein muss:
const hdConstraints = { video: { width: { exact: 1280} , height: { exact: 720 } }, }; const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
const vgaConstraints = { video: { width: { exact: 640} , height: { exact: 360 } }, }; const stream = await navigator.mediaDevices.getUserMedia(hdConstraints);
Weitere Konfigurationen finden Sie in der Constraints API.
Media-Quelle auswählen
Mit der Methode enumerateDevices()
der Schnittstelle MediaDevices
wird eine Liste der verfügbaren Media-Ein- und ‑Ausgabegeräte wie Mikrofone, Kameras und Headsets angefordert. Das zurückgegebene Promise wird mit einem Array von MediaDeviceInfo
-Objekten aufgelöst, die die Geräte beschreiben.
In diesem Beispiel wird das letzte gefundene Mikrofon und die letzte gefundene Kamera als Media-Stream-Quelle ausgewählt:
if (!navigator.mediaDevices?.enumerateDevices) { console.log("enumerateDevices() not supported."); } else { // List cameras and microphones. navigator.mediaDevices .enumerateDevices() .then((devices) => { let audioSource = null; let videoSource = null; devices.forEach((device) => { if (device.kind === "audioinput") { audioSource = device.deviceId; } else if (device.kind === "videoinput") { videoSource = device.deviceId; } }); sourceSelected(audioSource, videoSource); }) .catch((err) => { console.error(`${err.name}: ${err.message}`); }); } async function sourceSelected(audioSource, videoSource) { const constraints = { audio: { deviceId: audioSource }, video: { deviceId: videoSource }, }; const stream = await navigator.mediaDevices.getUserMedia(constraints); }
Hier finden Sie eine tolle Demo von Sam Dutton, in der gezeigt wird, wie Nutzer die Media-Quelle auswählen können.
Sicherheit
Browser zeigen beim Aufrufen von navigator.mediaDevices.getUserMedia()
ein Berechtigungsdialogfeld an, in dem Nutzer den Zugriff auf ihre Kamera/ihr Mikrofon gewähren oder verweigern können. Hier sehen Sie beispielsweise das Berechtigungsdialogfeld von Chrome:

Fallback bereitstellen
Für Nutzer, die navigator.mediaDevices.getUserMedia()
nicht unterstützen, besteht eine Möglichkeit darin, auf eine vorhandene Videodatei zurückzugreifen, wenn die API nicht unterstützt wird und/oder der Aufruf aus irgendeinem Grund fehlschlägt:
if (!navigator.mediaDevices?.getUserMedia) { video.src = "fallbackvideo.webm"; } else { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); video.srcObject = stream; }