Erste Schritte mit WebRTC

WebRTC ist eine neue Front im langen Kampf für ein offenes und unbeschwertes Web.

Brendan Eich, Erfinder von JavaScript

Echtzeitkommunikation ohne Plug-ins

Stellen Sie sich vor, Ihr Smartphone, Ihr Fernseher und Ihr Computer könnten über eine gemeinsame Plattform kommunizieren. Stellen Sie sich vor, es wäre ganz einfach, Ihrer Webanwendung Videochat und Peer-to-Peer-Datenfreigabe hinzuzufügen. Das ist die Vision von WebRTC.

Möchten Sie es einmal ausprobieren? WebRTC ist auf Computern und Mobilgeräten in Google Chrome, Safari, Firefox und Opera verfügbar. Ein guter Ausgangspunkt ist die einfache Videochat-App unter appr.tc:

  1. Öffnen Sie appr.tc in Ihrem Browser.
  2. Klicken Sie auf Teilnehmen, um einem Chatroom beizutreten und der App die Verwendung Ihrer Webcam zu erlauben.
  3. Öffnen Sie die am Ende der Seite angezeigte URL in einem neuen Tab oder, noch besser, auf einem anderen Computer.

Schnelleinstieg

Sie haben keine Zeit, diesen Artikel zu lesen, oder benötigen nur den Code?

  • Sehen Sie sich das folgende Google I/O-Video oder diese Folien an, um einen Überblick über WebRTC zu erhalten:
  • Wenn Sie die getUserMedia API noch nicht verwendet haben, lesen Sie die Hilfeartikel Audio und Video in HTML5 erfassen und simpl.info getUserMedia.
  • Weitere Informationen zur RTCPeerConnection API findest du im folgenden Beispiel und unter „simpl.info RTCPeerConnection“.
  • Informationen dazu, wie WebRTC Server für die Signalisierung und Firewall- und NAT-Durchläufe verwendet, finden Sie in den Code- und Konsolenprotokollen von appr.tc.
  • Sie können nicht warten und möchten WebRTC sofort ausprobieren? Probieren Sie einige der über 20 Demos aus, die die WebRTC JavaScript APIs nutzen.
  • Hast du Probleme mit deinem Computer und WebRTC? Weitere Informationen finden Sie im WebRTC-Troubleshooter.

Alternativ können Sie direkt mit dem WebRTC Codelab beginnen. In dieser Anleitung wird Schritt für Schritt erklärt, wie Sie eine vollständige Videochat-App mit einem einfachen Signalisierungsserver erstellen.

Eine kurze Geschichte von WebRTC

Eine der letzten großen Herausforderungen für das Web besteht darin, die Kommunikation zwischen Menschen über Sprache und Video zu ermöglichen: Echtzeitkommunikation, kurz RTC. RTC sollte in einer Webanwendung so natürlich sein wie das Eingeben von Text in eine Texteingabe. Ohne sie sind Ihre Möglichkeiten, innovativ zu sein und neue Interaktionsmöglichkeiten zu entwickeln, eingeschränkt.

Bisher war RTC eher für Unternehmen gedacht und komplex, da teure Audio- und Videotechnologien lizenziert oder intern entwickelt werden mussten. Die Einbindung der RTC-Technologie in vorhandene Inhalte, Daten und Dienste war schwierig und zeitaufwendig, insbesondere im Web.

Der Gmail-Videochat wurde 2008 populär und 2011 führte Google Hangouts ein, das wie Gmail auf Talk basiert. Google hat GIPS gekauft, ein Unternehmen, das viele für RTC erforderliche Komponenten entwickelt hat, z. B. Codecs und Echounterdrückungstechniken. Google hat die von GIPS entwickelten Technologien als Open Source veröffentlicht und sich mit den relevanten Standardsorganisationen der Internet Engineering Task Force (IETF) und des World Wide Web Consortium (W3C) in Verbindung gesetzt, um einen Branchenkonsens zu erzielen. Im Mai 2011 entwickelte Ericsson die erste Implementierung von WebRTC.

WebRTC implementiert offene Standards für die Echtzeitkommunikation von Video, Audio und Daten ohne Plug-in. Die Nachfrage war real:

  • Viele Webdienste nutzten RTC, benötigten aber Downloads, native Apps oder Plug-ins. Dazu gehörten Skype, Facebook und Hangouts.
  • Das Herunterladen, Installieren und Aktualisieren von Plug-ins ist komplex, fehleranfällig und mühsam.
  • Plugins sind schwierig bereitzustellen, zu debuggen, zu beheben, zu testen und zu verwalten. Außerdem erfordern sie möglicherweise eine Lizenzierung und Integration mit komplexer, teurer Technologie. Es ist oft schwierig, Nutzer dazu zu bewegen, überhaupt Plugins zu installieren.

Die Leitprinzipien des WebRTC-Projekts sind, dass die APIs Open Source, kostenlos, standardisiert, in Webbrowser integriert und effizienter als bestehende Technologien sein sollen.

Wo stehen wir jetzt?

WebRTC wird in verschiedenen Apps wie Google Meet verwendet. WebRTC wurde auch in WebKitGTK+ und native Qt-Apps integriert.

WebRTC implementiert diese drei APIs: - MediaStream (auch als getUserMedia bezeichnet) - RTCPeerConnection - RTCDataChannel

Die APIs sind in diesen beiden Spezifikationen definiert:

Alle drei APIs werden auf Mobilgeräten und Computern von Chrome, Safari, Firefox, Edge und Opera unterstützt.

getUserMedia: Demos und Code finden Sie unter WebRTC-Beispiele oder in den tollen Beispielen von Chris Wilson, in denen getUserMedia als Eingabe für Webaudio verwendet wird.

RTCPeerConnection: Eine einfache Demo und eine voll funktionsfähige Videochat-App finden Sie unter WebRTC-Beispiele für die Peer-Verbindung bzw. appr.tc. Diese App verwendet adapter.js, ein JavaScript-Shim, das von Google mithilfe der WebRTC-Community gepflegt wird, um Browserunterschiede und Spezifikationsänderungen zu abstrahieren.

RTCDataChannel: Eine Demo für Datenkanäle findest du in den WebRTC-Samples.

Im WebRTC-Codelab wird gezeigt, wie Sie mit allen drei APIs eine einfache App für Videochats und die Dateifreigabe erstellen.

Erste Schritte mit WebRTC

WebRTC-Apps müssen mehrere Dinge tun:

  • Streaming von Audio, Video oder anderen Daten
  • Netzwerkinformationen wie IP-Adressen und Ports abrufen und mit anderen WebRTC-Clients (sogenannte Peers) austauschen, um eine Verbindung zu ermöglichen, auch über NATs und Firewalls.
  • Signalkommunikation koordinieren, um Fehler zu melden und Sitzungen zu starten oder zu beenden.
  • Informationen zu Medien- und Clientfunktionen austauschen, z. B. Auflösung und Codecs
  • Streaming von Audio, Video oder Daten

Für die Erfassung und Kommunikation von Streamingdaten implementiert WebRTC die folgenden APIs:

  • MediaStream erhält Zugriff auf Datenstreams, z. B. von der Kamera und dem Mikrofon des Nutzers.
  • RTCPeerConnection ermöglicht Audio- oder Videoanrufe mit Verschlüsselungs- und Bandbreitenverwaltung.
  • RTCDataChannel ermöglicht die Peer-to-Peer-Kommunikation von generischen Daten.

(Die Netzwerk- und Signalisierungsaspekte von WebRTC werden später ausführlicher behandelt.)

MediaStream API (auch getUserMedia API genannt)

Die MediaStream API stellt synchronisierte Medienstreams dar. Ein Stream, der beispielsweise von der Kamera und dem Mikrofon aufgenommen wird, hat synchronisierte Video- und Audiotracks. (Verwechseln Sie MediaStreamTrack nicht mit dem Element <track>, das völlig anders ist.)

Am einfachsten lässt sich die MediaStream API verstehen, wenn Sie sie in der Praxis sehen:

  1. Rufen Sie in Ihrem Browser WebRTC-Beispiele getUserMedia auf.
  2. Öffnen Sie die Konsole.
  3. Prüfen Sie die Variable stream, die sich im globalen Gültigkeitsbereich befindet.

Jede MediaStream hat eine Eingabe, die eine von getUserMedia() generierte MediaStream sein kann, und eine Ausgabe, die an ein Videoelement oder eine RTCPeerConnection übergeben werden kann.

Die getUserMedia()-Methode nimmt einen MediaStreamConstraints-Objektparameter entgegen und gibt ein Promise zurück, das in ein MediaStream-Objekt aufgelöst wird.

Jede MediaStream hat eine label, z. B. 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. Die Methoden getAudioTracks() und getVideoTracks() geben ein Array von MediaStreamTracks zurück.

Im Beispiel getUserMedia gibt stream.getAudioTracks() ein leeres Array zurück, da kein Audio vorhanden ist. Wenn eine funktionierende Webcam angeschlossen ist, gibt stream.getVideoTracks() ein Array mit einem MediaStreamTrack zurück, das den Stream von der Webcam darstellt. Jede MediaStreamTrack hat eine Art ('video' oder 'audio'), eine label (z. B. 'FaceTime HD Camera (Built-in)') und stellt einen oder mehrere Audio- oder Videokanäle dar. In diesem Fall gibt es nur einen Videotrack und kein Audio. Es ist jedoch leicht, sich Anwendungsfälle vorzustellen, in denen es mehr gibt, z. B. eine Chat-App, die Streams von der Frontkamera, der Rückkamera, dem Mikrofon und einer App erhält, die den Bildschirm teilt.

Ein MediaStream kann mit einem Videoelement verknüpft werden, indem das srcObject-Attribut festgelegt wird. Bisher wurde das Attribut src auf eine mit URL.createObjectURL() erstellte Objekt-URL festgelegt. Diese Methode wurde jedoch eingestellt.

getUserMedia kann auch als Eingabeknoten für die Web Audio API verwendet werden:

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

Chromium-basierte Apps und Erweiterungen können auch getUserMedia einbinden. Wenn Sie dem Manifest audioCapture- und/oder videoCapture-Berechtigungen hinzufügen, kann die Berechtigung bei der Installation nur einmal angefordert und gewährt werden. Danach wird der Nutzer nicht mehr um die Berechtigung zum Zugriff auf die Kamera oder das Mikrofon gebeten.

Die Berechtigung muss nur einmal für getUserMedia() erteilt werden. Beim ersten Mal wird in der infobar des Browsers die Schaltfläche „Zulassen“ angezeigt. Der HTTP-Zugriff auf getUserMedia() wurde Ende 2015 von Chrome eingestellt, da er als leistungsstarke Funktion eingestuft wurde.

Ziel ist es, eine MediaStream für jede Streaming-Datenquelle zu ermöglichen, nicht nur für eine Kamera oder ein Mikrofon. So wäre das Streaming von gespeicherten Daten oder beliebigen Datenquellen wie Sensoren oder anderen Eingaben möglich.

getUserMedia() kommt erst in Kombination mit anderen JavaScript-APIs und ‑Bibliotheken richtig zur Geltung:

  • Webcam Toy ist eine Fotobooth-App, mit der Fotos mit WebGL seltsame und wundervolle Effekte hinzugefügt werden können, die geteilt oder lokal gespeichert werden können.
  • FaceKat ist ein Spiel mit Gesichtserkennung, das mit headtrackr.js erstellt wurde.
  • ASCII Camera verwendet die Canvas API, um ASCII-Bilder zu generieren.
ASCII-Bild, generiert von idevelop.ro/ascii-camera
gUM-ASCII-Art!

Einschränkungen

Mit Einschränkungen können Sie Werte für die Videoauflösung für getUserMedia() festlegen. Außerdem können so andere Einschränkungen unterstützt werden, z. B. Seitenverhältnis, Aufnahmemodus (Front- oder Rückkamera), Framerate, Höhe und Breite sowie eine applyConstraints()-Methode.

Ein Beispiel finden Sie unter WebRTC-Beispiele getUserMedia: Auflösung auswählen.

Wenn Sie einen nicht zulässigen Einschränkungswert festlegen, wird DOMException oder OverconstrainedError zurückgegeben, wenn beispielsweise eine angeforderte Auflösung nicht verfügbar ist. Eine Demo dazu findest du unter WebRTC-Beispiele getUserMedia: Auflösung auswählen.

Bildschirm- und Tab-Aufnahmen

Mit Chrome-Apps können Sie auch ein Live-Video eines einzelnen Browsertabs oder des gesamten Desktops über die APIs chrome.tabCapture und chrome.desktopCapture teilen. Eine Demo und weitere Informationen finden Sie unter Bildschirmfreigabe mit WebRTC. Der Artikel ist schon ein paar Jahre alt, aber immer noch interessant.)

Mit der experimentellen Einschränkung chromeMediaSource können Sie auch Bildschirmaufnahmen als MediaStream-Quelle in Chrome verwenden. Für die Bildschirmaufnahme ist HTTPS erforderlich und sie sollte nur für die Entwicklung verwendet werden, da sie wie in diesem Beitrag erläutert über ein Befehlszeilen-Flag aktiviert wird.

Signalisierung: Informationen zur Sitzungssteuerung, zum Netzwerk und zu Medien

WebRTC verwendet RTCPeerConnection, um Streamingdaten zwischen Browsern (auch als Peers bezeichnet) zu übertragen. Es ist jedoch auch ein Mechanismus erforderlich, um die Kommunikation zu koordinieren und Steuernachrichten zu senden. Dieser Vorgang wird als Signalisierung bezeichnet. Signalisierungsmethoden und ‑protokolle werden von WebRTC nicht spezifiziert. Signalisierung ist nicht Teil der RTCPeerConnection API.

Stattdessen können WebRTC-App-Entwickler das gewünschte Messaging-Protokoll wie SIP oder XMPP und einen geeigneten Duplex-Kommunikationskanal (d. h. einen zweikanaligen Kommunikationskanal) auswählen. Im Beispiel appr.tc werden XHR und die Channel API als Signalmechanismus verwendet. Im Codelab wird Socket.io auf einem Node-Server verwendet.

Über Signalisierung werden drei Arten von Informationen ausgetauscht:

  • Sitzungssteuerungsnachrichten: zum Initialisieren oder Schließen der Kommunikation und zum Melden von Fehlern.
  • Netzwerkkonfiguration: Wie lauten die IP-Adresse und der Port Ihres Computers für die Außenwelt?
  • Medienfunktionen: Welche Codecs und Auflösungen können von Ihrem Browser und dem Browser verarbeitet werden, mit dem er kommunizieren möchte?

Der Austausch von Informationen über die Signalisierung muss erfolgreich abgeschlossen sein, bevor das Peer-to-Peer-Streaming beginnen kann.

Angenommen, Alice möchte mit Bob kommunizieren. Hier ist ein Codebeispiel aus der W3C WebRTC-Spezifikation, das den Signalisierungsprozess veranschaulicht. Der Code setzt voraus, dass ein Signalmechanismus vorhanden ist, der in der Methode createSignalingChannel() erstellt wurde. In Chrome und Opera wird derzeit RTCPeerConnection vorangestellt.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

Zuerst tauschen Alice und Bob Netzwerkinformationen aus. (Der Ausdruck Kandidaten finden bezieht sich auf das Finden von Netzwerkschnittstellen und ‑ports mit dem ICE-Framework.)

  1. Alice erstellt ein RTCPeerConnection-Objekt mit einem onicecandidate-Handler, der ausgeführt wird, wenn Netzwerkkandidaten verfügbar werden.
  2. Alice sendet serialisierte Kandidatendaten über den verwendeten Signalkanal an Bob, z. B. WebSocket oder einen anderen Mechanismus.
  3. Wenn Bob eine Kandidatnachricht von Alice erhält, ruft er addIceCandidate auf, um den Kandidaten der Beschreibung des Remote-Peers hinzuzufügen.

WebRTC-Clients (auch als Peers bezeichnet, in diesem Beispiel Alice und Bob) müssen außerdem lokale und Remote-Audio- und Videomedieninformationen wie Auflösung und Codec-Funktionen ermitteln und austauschen. Für den Austausch von Informationen zur Medienkonfiguration wird ein Angebot und eine Antwort mit dem Session Description Protocol (SDP) ausgetauscht:

  1. Alice führt die Methode RTCPeerConnection createOffer() aus. Das Ergebnis wird an RTCSessionDescription übergeben, die lokale Sitzungsbeschreibung von Alice.
  2. Im Rückruf legt Alice die lokale Beschreibung mit setLocalDescription() fest und sendet diese Sitzungsbeschreibung dann über ihren Signalisierungskanal an Bob. Hinweis: RTCPeerConnection beginnt erst mit der Suche nach Kandidaten, wenn setLocalDescription() aufgerufen wird. Dies ist im IETF-Entwurf für JSEP festgelegt.
  3. Bob verwendet setRemoteDescription(), um die Beschreibung, die Alice ihm gesendet hat, als Remote-Beschreibung festzulegen.
  4. Bob führt die Methode RTCPeerConnection createAnswer() aus und übergibt die Remote-Beschreibung, die er von Alice erhalten hat, damit eine lokale Sitzung generiert werden kann, die mit ihrer kompatibel ist. Dem createAnswer()-Callback wird eine RTCSessionDescription übergeben. Bob legt diese als lokale Beschreibung fest und sendet sie an Alice.
  5. Wenn Alice die Sitzungsbeschreibung von Bob erhält, legt sie diese mit setRemoteDescription als Remote-Beschreibung fest.
  6. Ping!

RTCSessionDescription-Objekte sind Blobs, die dem Session Description Protocol (SDP) entsprechen. Ein serialisiertes SDP-Objekt sieht so aus:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

Die Erfassung und der Austausch von Netzwerk- und Medieninformationen können gleichzeitig erfolgen. Beide Prozesse müssen jedoch abgeschlossen sein, bevor das Audio- und Videostreaming zwischen Peers beginnen kann.

Die zuvor beschriebene Offer/Answer-Architektur wird JavaScript Session Establishment Protocol (JSEP) genannt. Im Demovideo von Ericsson für die erste WebRTC-Implementierung wird der Signalisierungs- und Streamingvorgang in einer hervorragenden Animation veranschaulicht.

JSEP-Architekturdiagramm
JSEP-Architektur

Sobald der Signalisierungsprozess erfolgreich abgeschlossen wurde, können Daten direkt zwischen dem Anrufer und dem Angerufenen per Peer-to-Peer-Streaming übertragen werden. Andernfalls erfolgt die Übertragung über einen vermittelnden Relay-Server (mehr dazu später). Das Streaming wird von RTCPeerConnection ausgeführt.

RTCPeerConnection

RTCPeerConnection ist die WebRTC-Komponente, die für eine stabile und effiziente Kommunikation von Streamingdaten zwischen Peers sorgt.

Im folgenden Diagramm ist die WebRTC-Architektur mit der Rolle von RTCPeerConnection dargestellt. Wie Sie sehen, sind die grünen Teile komplex.

WebRTC-Architekturdiagramm
WebRTC-Architektur (von webrtc.org)

Aus JavaScript-Sicht ist das Wichtigste an diesem Diagramm, dass RTCPeerConnection Webentwickler vor den unzähligen Komplexitäten schützt, die sich dahinter verbergen. Die von WebRTC verwendeten Codecs und Protokolle leisten einen großen Beitrag, um die Echtzeitkommunikation auch über unsichere Netzwerke hinweg zu ermöglichen:

  • Paketverlustmaskierung
  • Echounterdrückung
  • Bandbreitenanpassung
  • Dynamische Jitter-Pufferung
  • Automatische Verstärkungsregelung
  • Rauschunterdrückung
  • Bildbereinigung

Der vorherige W3C-Code zeigt ein vereinfachtes Beispiel für WebRTC aus Sicht der Signalisierung. Im Folgenden finden Sie Schritt-für-Schritt-Anleitungen für zwei funktionierende WebRTC-Apps. Das erste ist ein einfaches Beispiel zur Veranschaulichung von RTCPeerConnection und das zweite ist ein voll funktionsfähiger Videochat-Client.

RTCPeerConnection ohne Server

Der folgende Code stammt aus WebRTC-Beispiel-Peer-Verbindung, in der sich lokale und Remote-RTCPeerConnection (sowie lokales und Remote-Video) auf einer Webseite befinden. Das ist nicht sehr nützlich, da sich der Aufrufer und der Aufrufempfänger auf derselben Seite befinden. Es veranschaulicht jedoch die Funktionsweise der RTCPeerConnection API, da die RTCPeerConnection-Objekte auf der Seite Daten und Nachrichten direkt austauschen können, ohne dass Zwischensignalmechanismen verwendet werden müssen.

In diesem Beispiel steht pc1 für den lokalen Peer (Caller) und pc2 für den Remote-Peer (Callee).

Anrufer

  1. Erstelle eine neue RTCPeerConnection und füge den Stream aus getUserMedia() hinzu: ```js // Servers ist eine optionale Konfigurationsdatei. (Weitere Informationen zu TURN und STUN findest du weiter unten.) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. Erstellen Sie ein Angebot und legen Sie es als lokale Beschreibung für pc1 und als Remote-Beschreibung für pc2 fest. Das kann direkt im Code erfolgen, ohne Signalisierung, da sich sowohl der Anrufer als auch der Angerufene auf derselben Seite befinden: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Aufgerufener

  1. Erstelle pc2 und zeige es in einem Videoelement an, wenn der Stream von pc1 hinzugefügt wurde: js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API plus-Server

In der Praxis benötigt WebRTC jedoch Server, auch wenn sie einfach sind. Daher kann Folgendes passieren:

  • Nutzer finden sich gegenseitig und tauschen reale Details wie Namen aus.
  • WebRTC-Client-Apps (Peers) tauschen Netzwerkinformationen aus.
  • Peers tauschen Daten zu Medien aus, z. B. Videoformat und Auflösung.
  • WebRTC-Client-Apps durchlaufen NAT-Gateways und Firewalls.

Mit anderen Worten: WebRTC benötigt vier Arten von serverseitigen Funktionen:

  • Nutzersuche und -kommunikation
  • Signalisierung
  • NAT-/Firewall-Durchlauf
  • Relay-Server für den Fall, dass die Peer-to-Peer-Kommunikation fehlschlägt

NAT-Weiterleitung, Peer-to-Peer-Netzwerk und die Anforderungen zum Erstellen einer Server-App für die Nutzersuche und Signalisierung fallen nicht in den Rahmen dieses Artikels. Das STUN-Protokoll und seine Erweiterung TURN werden vom ICE-Framework verwendet, damit RTCPeerConnection NAT-Durchlauf und andere Netzwerkschwankungen bewältigen kann.

ICE ist ein Framework zum Verbinden von Peers, z. B. zwei Videoanruf-Clients. Zuerst versucht ICE, Peers direkt mit der niedrigsten möglichen Latenz über UDP zu verbinden. Bei diesem Vorgang haben STUN-Server nur eine Aufgabe: Sie ermöglichen einem Peer hinter einer NAT, seine öffentliche Adresse und seinen Port zu ermitteln. Weitere Informationen zu STUN und TURN finden Sie unter Backend-Dienste für eine WebRTC-App erstellen.

Potenzielle Kontakte finden
Potenzielle Kontakte finden

Wenn UDP fehlschlägt, versucht ICE TCP. Wenn die direkte Verbindung fehlschlägt, insbesondere aufgrund von NAT-Durchlauf und Firewalls in Unternehmen, verwendet ICE einen vermittelnden (Relay-)TURN-Server. Mit anderen Worten: ICE verwendet zuerst STUN mit UDP, um Peers direkt zu verbinden, und wechselt bei einem Fehler zu einem TURN-Relay-Server. Der Ausdruck Kandidaten finden bezieht sich auf das Finden von Netzwerkschnittstellen und ‑ports.

WebRTC-Datenpfade
WebRTC-Datenpfade

Der WebRTC-Entwickler Justin Uberti bietet in der WebRTC-Präsentation der Google I/O 2013 weitere Informationen zu ICE, STUN und TURN. (Die Folien der Präsentation enthalten Beispiele für TURN- und STUN-Serverimplementierungen.)

Ein einfacher Videochat-Client

Eine gute Möglichkeit, WebRTC mit Signalisierung und NAT-/Firewall-Durchlauf über einen STUN-Server auszuprobieren, ist die Videochat-Demo unter appr.tc. Diese App verwendet adapter.js, ein Shim, das Apps vor Spezifikationsänderungen und Präfixunterschieden schützt.

Der Code ist bei der Protokollierung bewusst ausführlich. In der Konsole sehen Sie die Reihenfolge der Ereignisse. Im Folgenden wird der Code ausführlich erläutert.

Netzwerktopologien

WebRTC unterstützt derzeit nur die Eins-zu-Eins-Kommunikation, kann aber auch in komplexeren Netzwerkszenarien verwendet werden, z. B. mit mehreren Peers, die direkt oder über eine Multipoint Control Unit (MCU) miteinander kommunizieren. Eine MCU ist ein Server, der eine große Anzahl von Teilnehmern verarbeiten und eine selektive Streamweiterleitung sowie das Mischen oder Aufzeichnen von Audio und Video ermöglichen kann.

Topologiediagramm der Multipoint Control Unit
Beispiel für eine Multipoint Control Unit-Topologie

Viele vorhandene WebRTC-Apps zeigen nur die Kommunikation zwischen Webbrowsern. Gateway-Server können jedoch eine WebRTC-App, die in einem Browser ausgeführt wird, dazu veranlassen, mit Geräten wie Telefonen (auch PSTN genannt) und VOIP-Systemen zu interagieren. Im Mai 2012 veröffentlichte Doubango Telecom den sipml5 SIP-Client als Open Source. Er wurde mit WebRTC und WebSocket entwickelt und ermöglicht unter anderem Videoanrufe zwischen Browsern und Apps, die auf iOS- und Android-Geräten ausgeführt werden. Auf der Google I/O haben Tethr und Tropo ein Framework für die Notfallkommunikation in einem Aktenkoffer vorgestellt. Dabei wurde eine OpenBTS-Zelle verwendet, um die Kommunikation zwischen Smartphones und Computern über WebRTC zu ermöglichen. Telefonkommunikation ohne Mobilfunkanbieter!

Tethr/Tropo-Demo bei der Google I/O 2012
Tethr/Tropo: Notfallkommunikation in einem Aktenkoffer

RTCDataChannel API<

Neben Audio und Video unterstützt WebRTC die Echtzeitkommunikation für andere Datentypen.

Die RTCDataChannel API ermöglicht den Peer-to-Peer-Austausch beliebiger Daten mit niedriger Latenz und hohem Durchsatz. Demo-Seiten und Informationen zum Erstellen einer einfachen Dateiübertragungs-App finden Sie unter WebRTC-Beispiele und im WebRTC-Codelab.

Es gibt viele potenzielle Anwendungsfälle für die API, darunter:

  • Gaming
  • Remote-Desktop-Apps
  • Echtzeit-Textchat
  • Dateiübertragung
  • Dezentrale Netzwerke

Die API bietet mehrere Funktionen, mit denen Sie RTCPeerConnection optimal nutzen und eine leistungsstarke und flexible Peer-to-Peer-Kommunikation ermöglichen können:

  • RTCPeerConnection-Sitzungseinrichtung nutzen
  • Mehrere gleichzeitige Kanäle mit Priorisierung
  • Zuverlässige und unzuverlässige Übermittlungssemantik
  • Integrierte Sicherheit (DTLS) und Überlastungskontrolle
  • Sie können mit oder ohne Audio oder Video verwendet werden.

Die Syntax ähnelt bewusst WebSocket mit einer send()-Methode und einem message-Ereignis:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

Die Kommunikation erfolgt direkt zwischen den Browsern. Daher kann RTCDataChannel viel schneller als WebSocket sein, auch wenn ein Relay-Server (TURN) erforderlich ist, wenn das Tunneling zur Umgehung von Firewalls und NATs fehlschlägt.

RTCDataChannel ist in Chrome, Safari, Firefox, Opera und Samsung Internet verfügbar. Im Spiel Cube Slam wird der Spielstatus über die API übertragen. Spielen Sie mit einem Freund oder mit dem Bären. Die innovative Plattform Sharefest ermöglichte die Dateifreigabe über RTCDataChannel und peerCDN bot einen Einblick, wie WebRTC die Peer-to-Peer-Inhaltsverteilung ermöglichen könnte.

Weitere Informationen zu RTCDataChannel finden Sie in der Entwurfsprotokollspezifikation der IETF.

Sicherheit

Es gibt mehrere Möglichkeiten, wie eine Echtzeit-Kommunikations-App oder ein Echtzeit-Kommunikations-Plug-in die Sicherheit gefährden kann. Beispiel:

  • Nicht verschlüsselte Medien oder Daten können zwischen Browsern oder zwischen einem Browser und einem Server abgefangen werden.
  • Eine App kann Video- oder Audioinhalte ohne Wissen des Nutzers aufnehmen und verbreiten.
  • Malware oder Viren können zusammen mit einem scheinbar harmlosen Plug-in oder einer scheinbar harmlosen App installiert werden.

WebRTC bietet mehrere Funktionen, um diese Probleme zu vermeiden:

  • WebRTC-Implementierungen verwenden sichere Protokolle wie DTLS und SRTP.
  • Die Verschlüsselung ist für alle WebRTC-Komponenten, einschließlich Signalmechanismen, obligatorisch.
  • WebRTC ist kein Plug-in. Die Komponenten werden in der Browser-Sandbox und nicht in einem separaten Prozess ausgeführt. Komponenten müssen nicht separat installiert werden und werden immer dann aktualisiert, wenn der Browser aktualisiert wird.
  • Der Zugriff auf die Kamera und das Mikrofon muss explizit gewährt werden. Wenn die Kamera oder das Mikrofon aktiv sind, muss dies in der Benutzeroberfläche deutlich angezeigt werden.

Eine vollständige Diskussion der Sicherheit für Streamingmedien würde den Rahmen dieses Artikels sprengen. Weitere Informationen finden Sie in der vorgeschlagenen WebRTC-Sicherheitsarchitektur der IETF.

Fazit

Die APIs und Standards von WebRTC können Tools zur Erstellung und Kommunikation von Inhalten demokratisieren und dezentralisieren, einschließlich Telefonie, Gaming, Videoproduktion, Musikproduktion und Nachrichtenerhebung.

Technologie kann nicht revolutionärer sein.

Wie Blogger Phil Edholm ausdrückte, „könnten WebRTC und HTML5 potenziell die gleiche Transformation für die Echtzeitkommunikation ermöglichen wie der ursprüngliche Browser für Informationen“.

Entwicklertools

Weitere Informationen

Standards und Protokolle

WebRTC-Support – Zusammenfassung

MediaStream- und getUserMedia-APIs

  • Chrome für Computer 18.0.1008 und höher; Chrome für Android 29 und höher
  • Opera 18 und höher; Opera für Android 20 und höher
  • Opera 12, Opera Mobile 12 (basierend auf der Presto-Engine)
  • Firefox 17 und höher
  • Microsoft Edge 16 und höher
  • Safari 11.2 und höher auf iOS und 11.1 und höher auf macOS
  • UC 11.8 und höher auf Android
  • Samsung Internet 4 und höher

RTCPeerConnection API

  • Chrome für Computer Version 20 und höher; Chrome für Android Version 29 und höher (ohne Flag)
  • Opera 18 und höher (standardmäßig aktiviert); Opera für Android 20 und höher (standardmäßig aktiviert)
  • Firefox 22 und höher (standardmäßig aktiviert)
  • Microsoft Edge 16 und höher
  • Safari 11.2 und höher auf iOS und 11.1 und höher auf macOS
  • Samsung Internet 4 und höher

RTCDataChannel API

  • Experimentelle Version in Chrome 25, aber stabilere Version (mit Interoperabilität mit Firefox) in Chrome 26 und höher; Chrome für Android 29 und höher
  • Stabile Version (mit Firefox-Interoperabilität) in Opera 18 und höher; Opera für Android 20 und höher
  • Firefox 22 und höher (standardmäßig aktiviert)

Weitere Informationen zur plattformübergreifenden Unterstützung von APIs wie getUserMedia und RTCPeerConnection finden Sie unter caniuse.com und Chrome-Plattformstatus.

Native APIs für RTCPeerConnection sind auch in der Dokumentation auf webrtc.org verfügbar.