Signatur
Beschreibung
navigator.mediaDevices.getDisplayMedia() ist die Standard-API für Bildschirmfreigabe im Browser. Beim Aufruf zeigt der Browser einen eigenen Auswahldialog an. Darin wählt der Benutzer einen ganzen Bildschirm, ein einzelnes Anwendungsfenster oder einen Browser-Tab aus. Das zurückgegebene Promise wird mit einem MediaStream erfüllt, der mindestens eine Videospur enthält. Je nach Browser und Auswahl kann auch eine Audiospur dabei sein, etwa der Ton eines Tabs.
Typische Anwendungsfälle sind Videokonferenzen über WebRTC (Spur per RTCPeerConnection.addTrack() senden), Bildschirmaufnahmen mit MediaRecorder, Screenshots über ein <video>- und <canvas>-Element sowie Vorschauen beim Präsentieren.
Anders als bei getUserMedia() kann die Webseite keine bestimmte Quelle vorgeben. Die Auswahl trifft immer der Benutzer. Mit Einschränkungen (Constraints) und Hinweisen wie displaySurface lässt sich nur eine Voreinstellung für den Dialog vorschlagen. Der Aufruf muss aus einer Benutzeraktion heraus erfolgen, etwa einem Klick (vorübergehende Benutzeraktivierung). Außerdem ist ein sicherer Kontext (HTTPS oder localhost) nötig.
Die Freigabe endet, wenn der Benutzer in der Browser-Oberfläche auf „Freigabe beenden“ klickt. Dann wird auf der Videospur das Ereignis ended ausgelöst. Darauf sollte die Anwendung immer reagieren und ihre Oberfläche entsprechend zurücksetzen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | object | { video: true } | Optionales Konfigurationsobjekt mit den folgenden Eigenschaften. |
| $options.video | boolean | MediaTrackConstraints | true | Einschränkungen für die Videospur, z. B. { frameRate: 30, width: { max: 1920 }, displaySurface: 'monitor' | 'window' | 'browser' }. false ist nicht erlaubt und führt zu einem TypeError. |
| $options.audio | boolean | MediaTrackConstraints | false | Fordert zusätzlich Audio an, z. B. Tab-Ton oder Systemton. Ob Audio tatsächlich geliefert wird, hängt von Browser, Betriebssystem und gewählter Quelle ab. |
| $options.preferCurrentTab | boolean | false | Schlägt den aktuellen Tab als Quelle im Dialog vor (nur Chromium). |
| $options.selfBrowserSurface | 'include' | 'exclude' | Legt fest, ob der aktuelle Tab im Dialog angeboten wird. 'exclude' verhindert den „Spiegelsaal“-Effekt (nur Chromium). |
|
| $options.surfaceSwitching | 'include' | 'exclude' | Legt fest, ob der Browser eine Schaltfläche anbietet, mit der der Benutzer während der Freigabe den Tab wechseln kann (nur Chromium). | |
| $options.systemAudio | 'include' | 'exclude' | Legt fest, ob Systemton für ganze Bildschirme angeboten wird (nur Chromium). | |
| $options.monitorTypeSurfaces | 'include' | 'exclude' | Mit 'exclude' werden ganze Bildschirme im Dialog ausgeblendet (nur Chromium). |
|
| $options.controller | CaptureController | Ein CaptureController, mit dem sich die Freigabe weiter steuern lässt, z. B. per setFocusBehavior() (Chromium). |
Rückgabewert
MediaStream erfüllt wird. Der Stream enthält eine Videospur und optional eine Audiospur. Das Promise wird zurückgewiesen mit NotAllowedError (Benutzer bricht ab oder Berechtigungsrichtlinie verbietet den Zugriff), InvalidStateError (keine Benutzeraktivierung oder Dokument nicht aktiv), NotFoundError (keine Quelle verfügbar), NotReadableError (Betriebssystem blockiert den Zugriff), OverconstrainedError oder TypeError (z. B. bei video: false oder nicht erlaubten Constraints wie min/exact).Beispiele
Bildschirmfreigabe per Klick starten und anzeigen
const button = document.querySelector('#share');
const video = document.querySelector('#preview');
button.addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: { frameRate: 30, displaySurface: 'window' },
audio: false
});
video.srcObject = stream;
await video.play();
const [track] = stream.getVideoTracks();
console.log('Freigegeben:', track.getSettings().displaySurface);
// Benutzer beendet die Freigabe über die Browser-Oberfläche
track.addEventListener('ended', () => {
video.srcObject = null;
console.log('Freigabe beendet');
});
} catch (err) {
if (err.name === 'NotAllowedError') {
console.warn('Freigabe abgelehnt oder abgebrochen');
} else {
console.error(err);
}
}
});
Bildschirmaufnahme mit MediaRecorder als WebM herunterladen
const recordScreen = async (durationMs = 5000) => {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true // Tab-Ton, sofern verfügbar
});
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
const chunks = [];
recorder.addEventListener('dataavailable', (e) => chunks.push(e.data));
recorder.addEventListener('stop', () => {
const blob = new Blob(chunks, { type: 'video/webm' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'aufnahme.webm';
a.click();
URL.revokeObjectURL(a.href);
stream.getTracks().forEach((t) => t.stop());
});
recorder.start();
setTimeout(() => recorder.stop(), durationMs);
};
document.querySelector('#record').addEventListener('click', () => recordScreen());
Screenshot eines Fensters als PNG erzeugen
const takeScreenshot = async () => {
const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const video = document.createElement('video');
video.srcObject = stream;
video.muted = true;
await video.play();
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0);
stream.getTracks().forEach((t) => t.stop()); // Freigabe sofort beenden
const dataUrl = canvas.toDataURL('image/png');
console.log(`Screenshot ${canvas.width}x${canvas.height}`);
return dataUrl;
};
document.querySelector('#shot').addEventListener('click', takeScreenshot);
Freigabe in WebRTC-Verbindung ersetzen (Kamera → Bildschirm)
const switchToScreen = async (peerConnection) => {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: { width: { max: 1920 }, height: { max: 1080 } }
});
const [screenTrack] = stream.getVideoTracks();
screenTrack.contentHint = 'detail'; // Text scharf halten
const sender = peerConnection
.getSenders()
.find((s) => s.track?.kind === 'video');
await sender.replaceTrack(screenTrack);
console.log('Bildschirm wird gesendet');
};