Erste Schritte mit WebRTC

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

Brendan Eich, Erfinder von JavaScript

Echtzeitkommunikation ohne Plug-ins

Stellen Sie sich eine Welt vor, in der Ihr Smartphone, Ihr Fernseher und Ihr Computer über eine gemeinsame Plattform kommunizieren können. Stellen Sie sich vor, Sie könnten Ihrer Web-App ganz einfach Videochats und Peer-to-Peer-Datenfreigabe hinzufügen. Das ist die Vision von WebRTC.

Du möchtest es selbst ausprobieren? WebRTC ist auf Desktop- und Mobilgeräten in Google Chrome, Safari, Firefox und Opera verfügbar. Eine gute Möglichkeit, um zu beginnen, 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 URL, die am Ende der Seite angezeigt wird, in einem neuen Tab oder besser noch auf einem anderen Computer.

Schnelleinstieg

Sie haben keine Zeit, diesen Artikel zu lesen, oder möchten nur den Code?

  • Einen Überblick über WebRTC erhalten Sie im folgenden Google I/O-Video oder in diesen Folien:
  • Wenn Sie die getUserMedia API noch nicht verwendet haben, lesen Sie die Informationen unter Audio und Video in HTML5 aufnehmen und simpl.info getUserMedia.
  • Informationen zur RTCPeerConnection API finden Sie im folgenden Beispiel und unter simpl.info RTCPeerConnection.
  • Informationen dazu, wie WebRTC Server für die Signalisierung sowie für Firewall- und NAT-Traversal verwendet, finden Sie im Code und in den Konsolenlogs von appr.tc.
  • Sie können es kaum erwarten und möchten WebRTC gleich ausprobieren? Mehr als 20 Demos, die die WebRTC JavaScript APIs nutzen
  • Hast du Probleme mit deinem Computer und WebRTC? Rufen Sie den WebRTC-Troubleshooter auf.

Alternativ können Sie auch direkt zum WebRTC-Codelab springen. Dort wird Schritt für Schritt erklärt, wie Sie eine vollständige Videochat-App erstellen, einschließlich eines einfachen Signalisierungsservers.

Eine sehr kurze Geschichte von WebRTC

Eine der letzten großen Herausforderungen für das Web ist die Sprach- und Videokommunikation zwischen Menschen, kurz RTC (Real-Time Communication). RTC sollte in einer Web-App so natürlich sein wie die Eingabe von Text in ein Texteingabefeld. Ohne sie sind Ihre Möglichkeiten, Innovationen zu entwickeln und neue Interaktionsmöglichkeiten zu schaffen, eingeschränkt.

Bisher war RTC ein komplexes Thema für Unternehmen, das die Lizenzierung oder Entwicklung teurer Audio- und Videotechnologien erforderte. Die Integration von RTC-Technologie in vorhandene Inhalte, Daten und Dienste war schwierig und zeitaufwendig, insbesondere im Web.

Der Gmail-Videochat wurde 2008 eingeführt und 2011 stellte Google Hangouts vor, das wie Gmail Talk verwendet. Google kaufte GIPS, ein Unternehmen, das viele für RTC erforderliche Komponenten wie Codecs und Techniken zur Echounterdrückung entwickelt hat. Google hat die von GIPS entwickelten Technologien als Open Source veröffentlicht und sich mit den zuständigen Normierungsgremien bei der Internet Engineering Task Force (IETF) und dem World Wide Web Consortium (W3C) ausgetauscht, um einen Branchenkonsens zu erzielen. Im Mai 2011 entwickelte Ericsson die erste Implementierung von WebRTC.

WebRTC implementierte offene Standards für die Kommunikation von Video, Audio und Daten in Echtzeit ohne Plug-ins. Der Bedarf war real:

  • Viele Webdienste nutzten RTC, erforderten 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 lästig.
  • Plug-ins sind schwierig bereitzustellen, zu debuggen, zu warten und zu testen. Außerdem können Lizenzen und die Integration in komplexe, teure Technologien erforderlich sein. Oft ist es schwierig, Nutzer überhaupt dazu zu bewegen, Plugins zu installieren.

Die Leitprinzipien des WebRTC-Projekts sind, dass seine APIs Open Source, kostenlos, standardisiert und in Webbrowser integriert sein 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 bekannt als getUserMedia) - 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. Sie können auch die tollen Beispiele von Chris Wilson ausprobieren, bei denen getUserMedia als Eingabe für Web Audio verwendet wird.

RTCPeerConnection: Eine einfache Demo und eine voll funktionsfähige Video-Chat-App finden Sie unter WebRTC-Beispiele für Peer-Verbindungen bzw. appr.tc. Diese App verwendet adapter.js, ein von Google mit Unterstützung der WebRTC-Community verwaltetes JavaScript-Shim, um Browserunterschiede und Spezifikationsänderungen zu abstrahieren.

RTCDataChannel: WebRTC-Beispiele

Im WebRTC-Codelab wird gezeigt, wie Sie alle drei APIs verwenden, um eine einfache App für Videochats und die gemeinsame Nutzung von Dateien zu erstellen.

Ihre erste WebRTC-Anwendung

WebRTC-Apps müssen mehrere Dinge tun:

  • Audio-, Video- oder andere Daten streamen
  • Netzwerkinformationen wie IP-Adressen und Ports abrufen und mit anderen WebRTC-Clients (Peers) austauschen, um eine Verbindung zu ermöglichen, auch über NATs und Firewalls.
  • Koordinieren Sie die Signalisierungskommunikation, um Fehler zu melden und Sitzungen zu starten oder zu schließen.
  • Informationen zu Media und Clientfunktionen wie Auflösung und Codecs austauschen.
  • Streaming von Audio, Video oder Daten kommunizieren.

WebRTC implementiert die folgenden APIs, um Streamingdaten zu erfassen und zu übertragen:

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

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

MediaStream API (auch als getUserMedia API bezeichnet)

Die MediaStream API stellt synchronisierte Media-Streams dar. Bei einem Stream, der von Kamera- und Mikrofoneingaben stammt, sind Video- und Audiotracks beispielsweise synchronisiert. Verwechseln Sie MediaStreamTrack nicht mit dem <track>-Element, das völlig anders ist.

Die MediaStream API lässt sich am besten anhand von Beispielen verstehen:

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

Jede MediaStream hat eine Eingabe, die möglicherweise eine von getUserMedia() generierte MediaStream ist, und eine Ausgabe, die möglicherweise an ein Videoelement oder ein RTCPeerConnection übergeben wird.

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

Jede MediaStream hat eine label, z. B. 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. Ein Array von MediaStreamTracks wird von den Methoden getAudioTracks() und getVideoTracks() zurückgegeben.

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. Jeder MediaStreamTrack hat eine Art ('video' oder 'audio'), einen 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 keinen Audio-Track. Es sind aber auch Anwendungsfälle denkbar, 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 ihren Bildschirm freigibt.

Ein MediaStream kann an ein Videoelement angehängt werden, indem das srcObject-Attribut festgelegt wird. Bisher wurde dies durch Festlegen des Attributs src auf eine mit URL.createObjectURL() erstellte Objekt-URL erreicht. 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);
});

In Chromium-basierten Apps und Erweiterungen kann auch getUserMedia verwendet werden. Wenn Sie dem Manifest Berechtigungen für audioCapture und/oder videoCapture hinzufügen, kann die Berechtigung nur einmal bei der Installation angefordert und erteilt werden. Danach wird der Nutzer nicht mehr um die Berechtigung für den Zugriff auf die Kamera oder das Mikrofon gebeten.

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

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

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

  • Webcam Toy ist eine Fotokabinen-App, die WebGL verwendet, um Fotos, die geteilt oder lokal gespeichert werden können, seltsame und wunderbare Effekte hinzuzufügen.
  • FaceKat ist ein Spiel, das auf Gesichtserkennung basiert und mit headtrackr.js entwickelt wurde.
  • ASCII Camera verwendet die Canvas API, um ASCII-Bilder zu generieren.
ASCII-Bild, das von idevelop.ro/ascii-camera generiert wurde
gUM ASCII art!

Einschränkungen

Mit Einschränkungen können Sie Werte für die Videoauflösung für getUserMedia() festlegen. Dies ermöglicht auch die Unterstützung anderer Einschränkungen, z. B. Seitenverhältnis, Ausrichtung (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 unzulässigen Einschränkungswert festlegen, wird DOMException oder OverconstrainedError zurückgegeben, wenn beispielsweise die angeforderte Auflösung nicht verfügbar ist. Eine Demo finden Sie unter WebRTC-Beispiele getUserMedia: Auflösung auswählen.

Bildschirm- und Tabaufnahme

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

Es ist auch möglich, die Bildschirmaufnahme als MediaStream-Quelle in Chrome zu verwenden, indem Sie die experimentelle chromeMediaSource-Einschränkung verwenden. Die Bildschirmaufnahme erfordert HTTPS und sollte nur für die Entwicklung verwendet werden, da sie über ein Befehlszeilenflag aktiviert wird, wie in diesem Beitrag beschrieben.

Signalisierung: Sitzungssteuerung, Netzwerk- und Medieninformationen

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

Stattdessen können WebRTC-App-Entwickler ein beliebiges Messaging-Protokoll wie SIP oder XMPP und einen beliebigen geeigneten Duplex-Kommunikationskanal (bidirektional) auswählen. Im Beispiel appr.tc werden XHR und die Channel API als Signalisierungsmechanismus verwendet. Im codelab wird Socket.io auf einem Node-Server verwendet.

Mit der Signalisierung werden drei Arten von Informationen ausgetauscht:

  • Sitzungssteuerungsnachrichten: zum Initialisieren oder Schließen der Kommunikation und zum Melden von Fehlern.
  • Netzwerkkonfiguration: Welche IP-Adresse und welchen Port hat Ihr Computer nach außen?
  • Media-Funktionen: Welche Codecs und Auflösungen können von Ihrem Browser und dem Browser, mit dem er kommunizieren möchte, verarbeitet werden?

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 Signaling-Prozess in Aktion zeigt. Der Code setzt das Vorhandensein eines Signalmechanismus voraus, der in der Methode createSignalingChannel() erstellt wurde. In Chrome und Opera ist RTCPeerConnection derzeit mit einem Präfix versehen.

// 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 den Prozess, bei dem Netzwerkschnittstellen und Ports mithilfe des ICE-Frameworks gefunden werden.

  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 Signalisierungskanal an Bob, z. B. WebSocket oder einen anderen Mechanismus.
  3. Wenn Bob eine Kandidatennachricht von Alice erhält, ruft er addIceCandidate auf, um den Kandidaten der Beschreibung des Remote-Peers hinzuzufügen.

WebRTC-Clients (auch als Peers oder in diesem Beispiel als Alice und Bob bezeichnet) müssen auch lokale und Remote-Audio- und ‑Videomedieninformationen wie Auflösung und Codec-Funktionen ermitteln und austauschen. Der Austausch von Informationen zur Medienkonfiguration erfolgt durch den Austausch eines Angebots und einer Antwort über das Session Description Protocol (SDP):

  1. Alice führt die Methode RTCPeerConnection createOffer() aus. Die Rückgabe davon wird an RTCSessionDescription übergeben – die lokale Sitzungsbeschreibung von Alice.
  2. Im Callback legt Alice die lokale Beschreibung mit setLocalDescription() fest und sendet diese Sitzungsbeschreibung dann über den Signalisierungskanal an Bob. RTCPeerConnection beginnt erst mit dem Sammeln von Kandidaten, wenn setLocalDescription() aufgerufen wird. Dies ist im JSEP-IETF-Entwurf festgelegt.
  3. Bob legt die Beschreibung, die Alice ihm gesendet hat, mit setRemoteDescription() als Remote-Beschreibung fest.
  4. Bob führt die Methode RTCPeerConnection createAnswer() aus und übergibt ihr 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 ein RTCSessionDescription übergeben. Bob legt dies 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. Serialisiert sieht ein SDP-Objekt 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, aber beide Prozesse müssen abgeschlossen sein, bevor das Audio- und Videostreaming zwischen Peers beginnen kann.

Die zuvor beschriebene Architektur für Angebot/Antwort wird als JavaScript Session Establishment Protocol (JSEP) bezeichnet. (Im Demovideo von Ericsson für die erste WebRTC-Implementierung wird der Prozess der Signalisierung und des Streamings in einer hervorragenden Animation erklärt.)

JSEP-Architekturdiagramm
JSEP-Architektur

Sobald der Signalisierungsprozess abgeschlossen ist, können Daten direkt zwischen Anrufer und Angerufenem gestreamt werden. Falls das nicht möglich ist, erfolgt die Übertragung über einen Vermittlungsserver (weitere Informationen dazu finden Sie unten). Das Streaming ist die Aufgabe von RTCPeerConnection.

RTCPeerConnection

RTCPeerConnection ist die WebRTC-Komponente, die für die stabile und effiziente Kommunikation von Streamingdaten zwischen Peers zuständig ist.

Das folgende Diagramm zeigt die WebRTC-Architektur und die Rolle von RTCPeerConnection. Wie Sie sehen, sind die grünen Teile komplex.

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

Aus JavaScript-Sicht ist das Wichtigste, was Sie aus diesem Diagramm lernen können, dass RTCPeerConnection Webentwickler vor den unzähligen Komplexitäten schützt, die darunter lauern. Die von WebRTC verwendeten Codecs und Protokolle leisten einen großen Beitrag, um die Echtzeitkommunikation auch über unzuverlässige Netzwerke zu ermöglichen:

  • Verdeckung von Paketverlust
  • Echounterdrückung
  • Bandbreitenanpassung
  • Dynamische Jitter-Zwischenspeicherung
  • Automatische Verstärkungsregelung
  • Rauschunterdrückung
  • Bildbereinigung

Der vorherige W3C-Code zeigt ein vereinfachtes Beispiel für WebRTC aus der Perspektive der Signalisierung. Im Folgenden finden Sie Anleitungen für zwei funktionierende WebRTC-Apps. Das erste ist ein einfaches Beispiel, um RTCPeerConnection zu demonstrieren, und das zweite ist ein voll funktionsfähiger Video-Chat-Client.

RTCPeerConnection ohne Server

Der folgende Code stammt aus den WebRTC-Beispielen für Peer-Verbindungen, die lokale und Remote-RTCPeerConnection (und lokales und Remote-Video) auf einer Webseite enthalten. Das ist zwar nicht sehr nützlich, da Anrufer und Angerufener sich auf derselben Seite befinden, aber es macht die Funktionsweise der RTCPeerConnection API etwas deutlicher, da die RTCPeerConnection-Objekte auf der Seite Daten und Nachrichten direkt austauschen können, ohne dass zwischengeschaltete Signalisierungsmechanismen erforderlich sind.

In diesem Beispiel steht pc1 für den lokalen Peer (Anrufer) und pc2 für den Remote-Peer (Empfänger).

Anrufer

  1. Erstellen Sie eine neue RTCPeerConnection und fügen Sie den Stream aus getUserMedia() hinzu: ```js // Servers is an optional configuration file. (Siehe die Diskussion zu TURN und STUN 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 dass eine Signalisierung erforderlich ist, da sich Anrufer und Angerufener auf derselben Seite befinden: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Callee

  1. Erstelle pc2 und zeige den Stream von pc1 in einem Videoelement an: js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API- und Plus-Server

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

  • Nutzer entdecken sich gegenseitig und tauschen Details aus der realen Welt aus, z. B. Namen.
  • 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
  • Relayserver, falls die Peer-to-Peer-Kommunikation fehlschlägt

NAT-Traversal, Peer-to-Peer-Netzwerke und die Anforderungen für die Entwicklung einer Server-App für die Nutzerermittlung und ‑signalisierung werden in diesem Artikel nicht behandelt. Das STUN-Protokoll und seine Erweiterung TURN werden vom ICE-Framework verwendet, damit RTCPeerConnection NAT-Traversal und andere Netzwerkunregelmäßigkeiten bewältigen kann.

ICE ist ein Framework zum Verbinden von Peers, z. B. zwei Videochat-Clients. Zuerst versucht ICE, Peers direkt über UDP mit der niedrigsten möglichen Latenz zu verbinden. STUN-Server haben dabei eine einzige Aufgabe: Sie ermöglichen es einem Peer hinter einem 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.

Kandidaten für Verbindungen finden
Verbindungskandidaten werden gesucht

Wenn UDP fehlschlägt, versucht ICE, TCP zu verwenden. Wenn eine direkte Verbindung fehlschlägt, insbesondere aufgrund von NAT-Traversal und Firewalls in Unternehmen, verwendet ICE einen zwischengeschalteten (Relay-)TURN-Server. ICE verwendet also zuerst STUN mit UDP, um Peers direkt zu verbinden. Wenn das fehlschlägt, wird auf einen TURN-Relay-Server zurückgegriffen. Der Ausdruck Kandidaten finden bezieht sich auf den Prozess des Findens von Netzwerkschnittstellen und ‑ports.

WebRTC-Datenpfade
WebRTC-Datenpfade

WebRTC-Entwickler Justin Uberti bietet weitere Informationen zu ICE, STUN und TURN in der WebRTC-Präsentation auf der Google I/O 2013. 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 Video-Chat-Demo unter appr.tc. Diese App verwendet adapter.js, ein Shim, um Apps vor Spezifikationsänderungen und Präfixunterschieden zu schützen.

Der Code ist in seiner Protokollierung bewusst ausführlich. Sehen Sie sich die Konsole an, um die Reihenfolge der Ereignisse zu verstehen. Im Folgenden wird der Code ausführlich beschrieben.

Netzwerktopologien

WebRTC unterstützt in der aktuellen Implementierung nur die Eins-zu-eins-Kommunikation, könnte aber 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 selektives Stream-Forwarding sowie das Mischen oder Aufzeichnen von Audio und Video durchführen kann.

Topologiediagramm der Multipoint Control Unit
Beispiel für die Topologie einer Multipoint Control Unit

Viele vorhandene WebRTC-Apps demonstrieren nur die Kommunikation zwischen Webbrowsern. Mit Gateway-Servern kann eine WebRTC-App, die in einem Browser ausgeführt wird, jedoch mit Geräten wie Telefonen (auch als PSTN bezeichnet) und mit VOIP-Systemen interagieren. Im Mai 2012 hat Doubango Telecom den mit WebRTC und WebSocket entwickelten sipml5-SIP-Client als Open Source veröffentlicht. Dieser ermöglicht (neben anderen potenziellen Anwendungen) Videoanrufe zwischen Browsern und Apps, die unter iOS und Android ausgeführt werden. Auf der Google I/O haben Tethr und Tropo ein Framework für die Katastrophenkommunikation in einem Aktenkoffer vorgestellt, das eine OpenBTS-Zelle verwendet, um die Kommunikation zwischen Mobiltelefonen und Computern über WebRTC zu ermöglichen. Telefonieren ohne Mobilfunkanbieter!

Tethr/Tropo-Demo bei der Google I/O 2012
Tethr/Tropo: Disaster communications in a briefcase

RTCDataChannel API<

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

Die RTCDataChannel API ermöglicht den Peer-to-Peer-Austausch beliebiger Daten mit niedriger Latenz und hohem Durchsatz. Informationen zu Einzelseiten-Demos und zum Erstellen einer einfachen Dateiübertragungs-App finden Sie unter WebRTC-Beispiele bzw. 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 Channels mit Priorisierung
  • Zuverlässige und unzuverlässige Semantik für die Zustellung
  • Integrierte Sicherheit (DTLS) und Staukontrolle
  • Nutzung mit oder ohne Audio oder Video

Die Syntax ist bewusst ähnlich wie bei 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 Browsern. Daher kann RTCDataChannel viel schneller als WebSocket sein, auch wenn ein Relay-Server (TURN) erforderlich ist, wenn das Hole Punching zur Bewältigung von Firewalls und NATs fehlschlägt.

RTCDataChannel ist in Chrome, Safari, Firefox, Opera und Samsung Internet verfügbar. Im Spiel Cube Slam wird die API verwendet, um den Spielstatus zu kommunizieren. Spiele einen Freund oder den 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 Protokollspezifikation der IETF.

Sicherheit

Es gibt verschiedene Möglichkeiten, wie eine Echtzeitkommunikations-App oder ein entsprechendes Plug-in die Sicherheit beeinträchtigen kann. Beispiel:

  • Unverschlüsselte Medien oder Daten können zwischen Browsern oder zwischen einem Browser und einem Server abgefangen werden.
  • Eine App kann Video oder Audio ohne Wissen des Nutzers aufzeichnen und weitergeben.
  • 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 der Signalisierungsmechanismen, 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 aktualisiert, wenn der Browser aktualisiert wird.
  • Der Zugriff auf Kamera und Mikrofon muss explizit gewährt werden. Wenn die Kamera oder das Mikrofon aktiv sind, wird dies in der Benutzeroberfläche deutlich angezeigt.

Eine ausführliche Beschreibung der Sicherheit für Streamingmedien wird in diesem Artikel nicht behandelt. Weitere Informationen finden Sie in der von der IETF vorgeschlagenen WebRTC-Sicherheitsarchitektur.

Fazit

Die APIs und Standards von WebRTC können Tools für die Inhaltserstellung und Kommunikation demokratisieren und dezentralisieren, einschließlich Telefonie, Gaming, Videoproduktion, Musikproduktion und Nachrichtenbeschaffung.

Disruptiver geht es kaum.

Wie der Blogger Phil Edholm schreibt, „könnten WebRTC und HTML5 möglicherweise dieselbe Transformation für die Echtzeitkommunikation ermöglichen, die der ursprüngliche Browser für Informationen ermöglicht hat“.

Entwicklertools

Weitere Informationen

Standards und Protokolle

Zusammenfassung der WebRTC-Unterstützung

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 unter iOS sowie 11.1 und höher unter MacOS
  • UC 11.8 und höher unter Android
  • Samsung Internet 4 und höher

RTCPeerConnection API

  • Chrome für Computer ab Version 20; Chrome für Android ab Version 29 (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 unter iOS sowie 11.1 und höher unter MacOS
  • Samsung Internet 4 und höher

RTCDataChannel API

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

Ausführlichere Informationen zur plattformübergreifenden Unterstützung von APIs wie getUserMedia und RTCPeerConnection finden Sie unter caniuse.com und Chrome Platform Status.

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