Erste Schritte mit WebRTC

WebRTC ist ein neuer Schritt im langen Krieg für ein offenes und unbelastetes Web.

Brendan Eich, Erfinder des JavaScript

Kommunikation in Echtzeit ohne Plug-ins

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

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

  1. Öffnen Sie appr.tc in Ihrem Browser.
  2. Klicken Sie auf Beitreten, um einem Chatroom beizutreten und der App Zugriff auf Ihre Webcam zu gewähren.
  3. Öffnen Sie die URL am Ende der Seite in einem neuen Tab oder noch besser auf einem anderen Computer.

Kurzanleitung

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

  • Einen Überblick über WebRTC erhalten Sie im folgenden Google I/O-Video oder auf diesen Folien:
  • Wenn Sie die getUserMedia API noch nicht verwendet haben, lesen Sie Audio- und Videoinhalte in HTML5 erfassen und simpl.info getUserMedia.
  • Informationen zur RTCPeerConnection API findest du im folgenden Beispiel und unter 'simpl.info RTCPeerConnection'.
  • Informationen dazu, wie WebRTC Server für die Signalisierung sowie Firewall- und NAT-Traversal verwendet, finden Sie im Code und in den Konsolenprotokollen von appr.tc.
  • Sie möchten nicht warten und WebRTC gleich ausprobieren? Probieren Sie einige der über 20 Demos aus, in denen die WebRTC JavaScript APIs getestet werden.
  • Haben Sie Probleme mit Ihrem Computer und WebRTC? Rufen Sie die WebRTC-Fehlerbehebung auf.

Alternativ kannst du direkt mit dem WebRTC-Codelab starten. Dort wird Schritt für Schritt erklärt, wie du eine vollständige Videochat-App einschließlich eines einfachen Signalisierungsservers erstellst.

Nur eine kurze Entstehungsgeschichte von WebRTC

Eine der letzten großen Herausforderungen für das Web besteht darin, die menschliche Kommunikation über Sprach- und Videofunktionen zu ermöglichen: die Echtzeitkommunikation oder kurz RTC. RTC sollte in einer Web-App genauso natürlich sein wie die Eingabe von Text in eine Texteingabe. Ohne sie sind Ihre Möglichkeiten beschränkt, innovativ zu sein und neue Wege für die Interaktion der Menschen zu entwickeln.

In der Vergangenheit war RTC ein komplexes Unternehmen, für das teure Audio- und Videotechnologien intern lizenziert oder entwickelt werden mussten. Die Integration der RTC-Technologie in bestehende Inhalte, Daten und Dienste war schwierig und zeitaufwendig, insbesondere im Web.

Der Videochat von Gmail erfreut sich seit 2008 großer Beliebtheit. 2011 führte Google Hangouts ein, das wie Gmail Talk verwendet. Google erwarb GIPS, ein Unternehmen, das viele für RTC erforderliche Komponenten wie Codecs und Echounterdrückungstechniken entwickelt hat. Google hat die von GIPS entwickelten Technologien als Open Source zur Verfügung gestellt und sich mit relevanten Normungsgremien der Internet Engineering Task Force (IETF) und des World Wide Web Consortium (W3C) zusammengetan, um einen Konsens in der Branche zu erreichen. Im Mai 2011 entwickelte Ericsson die erste WebRTC-Implementierung.

WebRTC implementierte offene Standards für die Video-, Audio- und Datenkommunikation in Echtzeit ohne Plug-in. Das Bedürfnis war real:

  • Viele Webdienste nutzten RTC, erforderten jedoch Downloads, systemeigene Apps oder Plug-ins. Dazu gehörten Skype, Facebook und Hangouts.
  • Das Herunterladen, Installieren und Aktualisieren von Plug-ins ist komplex, fehleranfällig und ärgerlich.
  • Plug-ins sind schwierig bereitzustellen, zu debuggen, zu beheben, zu testen und zu warten. Außerdem sind möglicherweise eine Lizenzierung und die Einbindung in eine komplexe, teure Technologie erforderlich. Es ist oft schwierig, Nutzer davon zu überzeugen, Plug-ins überhaupt zu installieren.

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

Wo sind wir jetzt?

WebRTC wird in verschiedenen Apps verwendet, z. B. in Google Meet. WebRTC ist auch in WebKitGTK+- und Qt-native Apps integriert.

WebRTC implementiert diese drei APIs: – MediaStream (auch als getUserMedia bezeichnet) – RTCPeerConnectionRTCDataChannel

Die APIs sind in diesen beiden Spezifikationen definiert:

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

getUserMedia: Demos und Code finden Sie unter WebRTC-Beispiele oder Chris Wilsons spannende Beispiele, in denen getUserMedia als Eingabe für Web-Audio verwendet wird.

RTCPeerConnection: Eine einfache Demo und eine voll funktionsfähige App für Videoanrufe finden Sie unter WebRTC-Beispiele für Peer-Verbindung bzw. appr.tc. Diese App verwendet adapter.js, einen JavaScript-Shim, der von Google mit Unterstützung der WebRTC-Community verwaltet wird, um Browserunterschiede und Spezifikationsänderungen zu entfernen.

RTCDataChannel: Um dies in Aktion zu sehen, sehen Sie sich in den WebRTC-Beispielen eine der Datenkanal-Demos an.

Im WebRTC-Codelab erfährst du, wie du mit allen drei APIs eine einfache App für Videoanrufe und Dateifreigabe erstellen kannst.

Erste WebRTC-

WebRTC-Apps müssen mehrere Dinge tun:

  • Streaming von Audio-, Video- oder anderen Daten abrufen.
  • Sie können Netzwerkinformationen wie IP-Adressen und Ports abrufen und mit anderen WebRTC-Clients (sogenannten Peers) austauschen, um selbst über NATs und Firewalls eine Verbindung herzustellen.
  • Koordinieren der Signalkommunikation, um Fehler zu melden und Sitzungen zu initiieren oder zu beenden.
  • Informationen über Medien- und Clientfunktionen wie Auflösung und Codecs austauschen.
  • Audio-, Video- oder Datenstreams kommunizieren

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

  • MediaStream erhält Zugriff auf die Datenstreams, z. B. über die Kamera und das Mikrofon des Nutzers.
  • RTCPeerConnection ermöglicht Audio- oder Videoanrufe mit Verschlüsselungs- und Bandbreitenverwaltungsfunktionen.
  • RTCDataChannel ermöglicht die Peer-to-Peer-Kommunikation generischer Daten.

(Die Netzwerk- und Signalaspekte von WebRTC werden weiter unten ausführlich besprochen.)

MediaStream API (auch getUserMedia API genannt)

Die MediaStream API steht für synchronisierte Medienstreams. Ein Stream, der von der Kamera- und Mikrofoneingabe entnommen wird, hat beispielsweise synchronisierte Video- und Audiotracks. Verwechseln Sie MediaStreamTrack nicht mit dem Element <track>, bei dem es sich ganz anders handelt.

Am einfachsten verstehen Sie die MediaStream API am besten, wenn Sie sie sich in der Natur ansehen:

  1. Rufen Sie in Ihrem Browser WebRTC-Beispiele getUserMedia auf.
  2. Öffnen Sie die Konsole.
  3. Prüfen Sie die globale Variable stream.

Jede MediaStream hat eine Eingabe, bei der es sich um eine von getUserMedia() generierte MediaStream handeln kann, und eine Ausgabe, die an ein Videoelement oder ein RTCPeerConnection übergeben werden kann.

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

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

Für das getUserMedia-Beispiel gibt stream.getAudioTracks() ein leeres Array zurück (da kein Audio vorhanden ist) und bei der Annahme, dass eine funktionierende Webcam verbunden ist, gibt stream.getVideoTracks() ein Array von einem MediaStreamTrack zurück, der den Stream von der Webcam darstellt. Jeder MediaStreamTrack hat einen Typ ('video' oder 'audio') und einen label (etwa 'FaceTime HD Camera (Built-in)') und repräsentiert einen oder mehrere Audio- oder Videokanäle. In diesem Fall gibt es nur einen Videotrack und keinen Ton, aber es ist leicht vorzustellen, Anwendungsfälle mit mehr als einer zu bieten, z. B. eine Chat-App, die Streams von der Frontkamera, eine Rückkamera, ein Mikrofon und eine App teilt, die ihren Bildschirm teilt.

Eine MediaStream kann durch Festlegen des Attributs srcObject an ein Videoelement angehängt werden. Bisher wurde das src-Attribut auf eine Objekt-URL festgelegt, die mit URL.createObjectURL() erstellt wurde. Dies 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 enthalten. Wenn Sie dem Manifest die Berechtigungen audioCapture und/oder videoCapture hinzufügen, kann die Berechtigung bei der Installation nur einmal angefordert und gewährt werden. Danach wird der Nutzer nicht mehr um die Berechtigung für den Kamera- oder Mikrofonzugriff gebeten.

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

Damit soll ein MediaStream für jede Streamingdatenquelle aktiviert werden, nicht nur für eine Kamera oder ein Mikrofon. Dies ermöglicht das Streaming von gespeicherten Daten oder beliebigen Datenquellen wie Sensoren oder anderen Eingaben.

getUserMedia() wird in Kombination mit anderen JavaScript APIs und Bibliotheken wirklich zum Leben erweckt:

  • Webcam Toy ist eine Fotobox-App, die mithilfe von WebGL seltsame und wunderbare Effekte auf Fotos verleiht, die anschließend geteilt oder lokal gespeichert werden können.
  • FaceKat ist ein Gesichtserkennungsspiel, das mit headtrackr.js entwickelt wurde.
  • Die ASCII-Kamera verwendet die Canvas API, um ASCII-Bilder zu generieren.
Von idevelop.ro/ascii-camera generierte ASCII-Bild
gUM-ASCII-Art!

Einschränkungen

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

Ein Beispiel findest du unter WebRTC-Beispiele getUserMedia: Auflösung auswählen.

Wenn Sie einen unzulässigen Einschränkungswert festlegen, wird ein DOMException oder OverconstrainedError zurückgegeben, wenn beispielsweise die angeforderte Lösung nicht verfügbar ist. Wie das funktioniert, siehst du in einer Demo unter WebRTC-Beispiele getUserMedia: Auflösung auswählen.

Bildschirm- und Tabaufnahme

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

Es ist auch möglich, mit der experimentellen Einschränkung chromeMediaSource die Bildschirmaufnahme als MediaStream-Quelle in Chrome zu verwenden. Beachte, dass für Bildschirmaufnahmen HTTPS erforderlich ist und sollte nur für die Entwicklung verwendet werden, da die Funktion über ein Befehlszeilen-Flag aktiviert wird, wie in diesem Beitrag erläutert.

Signalisierung: Sitzungssteuerung, Netzwerk- und Medieninformationen

WebRTC verwendet RTCPeerConnection, um Streamingdaten zwischen Browsern (auch als Peers bezeichnet) zu kommunizieren, benötigt aber auch einen Mechanismus, um die Kommunikation zu koordinieren und Steuernachrichten zu senden. Dies wird als Signalisierung bezeichnet. Signalisierungsmethoden und -protokolle werden von WebRTC nicht vorgegeben. Die Signalisierung ist nicht Teil der RTCPeerConnection API.

Stattdessen können WebRTC-App-Entwickler ein beliebiges Messaging-Protokoll wie SIP oder XMPP sowie einen geeigneten Duplex-Kommunikationskanal (Zwei-Wege-Kommunikationskanal) auswählen. Im Beispiel appr.tc werden XHR und die Channel API als Signalisierungsmechanismus verwendet. Das Codelab verwendet Socket.io, das auf einem Knotenserver ausgeführt wird.

Mithilfe von Signalen werden drei Arten von Informationen ausgetauscht:

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

Der Informationsaustausch durch Signalisierung muss erfolgreich abgeschlossen sein, bevor Peer-to-Peer-Streaming beginnen kann.

Stellen Sie sich zum Beispiel vor, Alice möchte mit Bob kommunizieren. Hier sehen Sie ein Codebeispiel aus der W3C WebRTC-Spezifikation, das den Signalisierungsprozess in Aktion zeigt. Der Code geht davon aus, dass ein Signalmechanismus vorhanden ist, der in der Methode createSignalingChannel() erstellt wurde. Beachten Sie außerdem, dass in Chrome und Opera derzeit das Präfix RTCPeerConnection vorangestellt ist.

// 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 suchen bezieht sich auf den Prozess zum Suchen von Netzwerkschnittstellen und Ports mithilfe des ICE-Frameworks.

  1. Alice erstellt ein RTCPeerConnection-Objekt mit einem onicecandidate-Handler, der ausgeführt wird, wenn Netzwerkkandidaten verfügbar werden.
  2. Alice sendet serielle Kandidatendaten an Bob über einen von ihr verwendeten Signalisierungskanal, zum Beispiel über WebSocket oder einen anderen Mechanismus.
  3. Wenn Bob eine Kandidatennachricht von Alice erhält, ruft er addIceCandidate auf, um den Kandidaten zur Remote-Peer-Beschreibung hinzuzufügen.

WebRTC-Clients (in diesem Beispiel auch Peer oder Alice und Bob) müssen lokale und Remote-Audio- und Videomedieninformationen wie Auflösung und Codec ermitteln und austauschen. Die Signalisierung zum 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. Bei der Rückgabe wird eine RTCSessionDescription – die lokale Sitzungsbeschreibung von Alice übergeben.
  2. Im Callback legt Alice die lokale Beschreibung mithilfe von setLocalDescription() fest und sendet diese Sitzungsbeschreibung über ihren Signalisierungskanal an Bob. Hinweis: RTCPeerConnection beginnt erst dann mit dem Zusammentragen von Kandidaten, wenn setLocalDescription() aufgerufen wurde. Dies ist im JSEP IETF-Entwurf kodifiziert.
  3. Bob legt mit setRemoteDescription() die Beschreibung fest, die Alice ihm als Remote-Beschreibung gesendet hat.
  4. Bob führt die RTCPeerConnection-Methode createAnswer() aus und übergibt ihr die Remote-Beschreibung, die er von Alice erhalten hat, sodass eine lokale Sitzung generiert werden kann, die mit ihrer kompatibel ist. Dem createAnswer()-Callback wird ein RTCSessionDescription-Wert übergeben. Bob legt dies als lokale Beschreibung fest und sendet sie an Alice.
  5. Wenn Alice die Sitzungsbeschreibung von Bob erhält, legt sie sie 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

Der Erwerb und der Austausch von Netzwerk- und Medieninformationen kann gleichzeitig erfolgen, aber beide Prozesse müssen abgeschlossen sein, bevor Audio- und Videostreaming zwischen Peers beginnen kann.

Die zuvor beschriebene Architektur für Angebot und Antwort heißt JavaScript Session Einrichtung Protocol (JSEP). Im Demovideo von Ericsson zur ersten WebRTC-Implementierung gibt es eine hervorragende Animation, die den Prozess der Signalisierung und des Streamings erklärt.

JSEP-Architekturdiagramm
JSEP-Architektur

Sobald der Signalisierungsprozess erfolgreich abgeschlossen wurde, können die Daten direkt Peer-to-Peer, zwischen dem Aufrufer und dem Aufgerufenen oder, falls dies fehlschlägt, über einen zwischengeschalteten Relay-Server gestreamt werden (dazu später mehr). Streaming ist die Aufgabe von RTCPeerConnection.

RTCPeerConnection

RTCPeerConnection ist die WebRTC-Komponente, die eine stabile und effiziente Kommunikation von Streamingdaten zwischen Peers ermöglicht.

Im Folgenden finden Sie ein WebRTC-Architekturdiagramm, das die Rolle von RTCPeerConnection zeigt. Wie Sie sehen werden, sind die grünen Teile komplex!

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

Aus der Perspektive von JavaScript ist zu erkennen, dass RTCPeerConnection Webentwickler vor den unzähligen Komplexitäten schützt, die dahinterstecken. Die von WebRTC verwendeten Codecs und Protokolle erfordern einen enormen Arbeitsaufwand, um die Echtzeitkommunikation selbst über unzuverlässige Netzwerke zu ermöglichen:

  • Verschleierung von Paketverlust
  • Echounterdrückung
  • Bandbreitenanpassung
  • Zwischenspeichern von dynamischem Jitter
  • Automatische Verstärkungsregelung
  • Rauschunterdrückung und -unterdrückung
  • Bildbereinigung

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

RTCPeerConnection ohne Server

Der folgende Code stammt aus WebRTC-Beispielen für eine Peer-Verbindung, die eine lokale und Remote-RTCPeerConnection (sowie lokale und Remote-Videos) auf einer Webseite hat. Dies stellt nichts sehr Nützliches dar – Aufrufer und Aufgerufene befinden sich auf derselben Seite, aber es macht die Funktionsweise der RTCPeerConnection API ein wenig verständlicher, da die RTCPeerConnection-Objekte auf der Seite Daten und Nachrichten direkt austauschen können, ohne zwischengeschaltete Signalmechanismen zu verwenden.

In diesem Beispiel stellt pc1 den lokalen Peer (Aufrufer) und pc2 den Remote-Peer (Aufgerufene) dar.

Anrufer

  1. Erstellen Sie einen neuen RTCPeerConnection und fügen Sie den Stream aus getUserMedia() hinzu: ```js // Server ist eine optionale Konfigurationsdatei. Weitere Informationen finden Sie in der Diskussion zu turn und STUN. pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEvery((track) => { pc1.addTrack(track, localStream); });
  1. Erstelle ein Angebot und lege es als lokale Beschreibung für pc1 und als Remote-Beschreibung für pc2 fest. Das kann direkt im Code erfolgen, ohne Signalisierung zu verwenden, da sich der Anrufer und der Aufgerufene 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. Erstellen Sie pc2. Wenn der Stream von pc1 hinzugefügt wird, wird er in einem Videoelement angezeigt: 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 für WebRTC Server, die so einfach sind. Daher kann Folgendes passieren:

  • Nutzer entdecken einander und tauschen reale Details wie Namen aus.
  • WebRTC-Client-Apps (Peers) tauschen Netzwerkinformationen aus.
  • Andere tauschen Daten über Medien wie das Videoformat und die Auflösung aus.
  • WebRTC-Client-Apps durchlaufen NAT-Gateways und Firewalls.

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

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

NAT-Traversal, Peer-to-Peer-Netzwerk und die Anforderungen zum Erstellen einer Server-App für Nutzererkennung und Signalisierung werden in diesem Artikel nicht behandelt. Es reicht aus, zu sagen, dass das STUN-Protokoll und seine Erweiterung, turn, vom ICE-Framework verwendet werden, damit RTCPeerConnection mit NAT-Traversal und anderen Sicherheitslücken im Netzwerk umgehen kann.

ICE ist ein Framework für die Vernetzung ähnlicher Apps, z. B. von zwei Videochat-Clients. Anfangs versucht ICE, Peers direkt mit der geringstmöglichen Latenz über UDP zu verbinden. Bei diesem Prozess haben STUN-Server nur eine Aufgabe: es einem Peer hinter einer NAT zu ermöglichen, seine öffentliche Adresse und seinen Port zu ermitteln. Weitere Informationen zu STUN und Turn finden Sie unter Back-End-Dienste erstellen, die für eine WebRTC-App erforderlich sind.

Verbindungskandidaten finden
Verbindungskandidaten finden

Wenn UDP fehlschlägt, versucht ICE TCP. Wenn eine direkte Verbindung fehlschlägt – insbesondere aufgrund von NAT-Traversal für Unternehmen und Firewalls – verwendet ICE einen Zwischen-(Relay)-Turn-Server. Mit anderen Worten: ICE verwendet zuerst STUN mit UDP, um Peers direkt zu verbinden, und greift bei einem Fehler auf einen turn-Relay-Server zurück. Der Ausdruck Kandidaten suchen bezieht sich auf den Prozess der Suche nach Netzwerkschnittstellen und -ports.

WebRTC-Datenpfade
WebRTC-Datenpfade

WebRTC-Entwickler Justin Uberti stellt in der Google I/O WebRTC-Präsentation 2013 weitere Informationen zu ICE, STUN und Turn bereit. Auf den Folien der Präsentation werden Beispiele für Implementierungen von Turn- und STUN-Servern gezeigt.

Ein einfacher Client für Videochats

Ein guter Ort, um WebRTC auszuprobieren, einschließlich Signalisierung und NAT/Firewall-Durchquerung mit einem STUN-Server, ist die Video-Chat-Demo unter appr.tc. Diese App verwendet adapter.js, einen Shim, der Apps vor Spezifikationsänderungen und Präfixunterschieden isoliert.

Der Code wird bewusst protokolliert. Sehen Sie sich die Reihenfolge der Ereignisse in der Konsole an. Im Folgenden finden Sie eine detaillierte Schritt-für-Schritt-Anleitung für den Code.

Netzwerktopologien

WebRTC unterstützt derzeit nur die 1:1-Kommunikation, kann aber in komplexeren Netzwerkszenarien verwendet werden, z. B. wenn mehrere Peers direkt miteinander oder über eine Multipoint Control Unit (MCU) miteinander kommunizieren. Dies ist ein Server, der eine große Anzahl von Teilnehmern verarbeiten und die selektive Streamweiterleitung sowie das Mischen oder Aufzeichnen von Audio und Video übernehmen kann.

Topologiediagramm für die Mehrpunktsteuerungseinheit
Beispiel für eine Multipoint-Steuerungseinheit

Viele bestehende WebRTC-Apps zeigen nur die Kommunikation zwischen Webbrowsern, aber Gatewayserver können eine WebRTC-App aktivieren, die in einem Browser ausgeführt wird, um mit Geräten wie Telefonen (auch PSTN genannt) und VOIP-Systemen zu interagieren. Im Mai 2012 stellte Doubango Telecom den sipml5 SIP-Client mit WebRTC und WebSocket als Open Source zur Verfügung. Dieser Client ermöglicht unter anderem Videoanrufe zwischen Browsern und Apps unter iOS und Android. Bei der Google I/O demonstrierten Tethr und Tropo ein Framework für die Katastrophenkommunikation in einem Aktentaschen. Dabei wurde eine OpenBTS-Zelle verwendet, um die Kommunikation zwischen Feature-Phones und Computern über WebRTC zu ermöglichen. Telefonkommunikation ohne Mobilfunkanbieter!

Tethr/Tropo-Demo auf der Google I/O 2012
Tethr/Tropo: Kommunikation im Notfall

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. Einseitige Demos und Informationen zum Erstellen einer einfachen App zur Dateiübertragung finden Sie in den WebRTC-Beispielen bzw. im WebRTC-Codelab.

Es gibt viele potenzielle Anwendungsfälle für die API, z. B.:

  • Spiele
  • Remote Desktop-Apps
  • Textchat in Echtzeit
  • Dateiübertragung
  • Dezentralisierte Netzwerke

Die API bietet mehrere Funktionen, um RTCPeerConnection optimal zu nutzen und eine leistungsstarke und flexible Peer-to-Peer-Kommunikation zu ermöglichen:

  • Einrichtung von RTCPeerConnection Sitzungen nutzen
  • Mehrere Kanäle mit Priorisierung gleichzeitig
  • Zuverlässige und unzuverlässige Bereitstellungssemantik
  • Integrierte Sicherheit (DTLS) und Überlastungssteuerung
  • Verwendung mit oder ohne Audio oder Video

Die Syntax ähnelt absichtlich der 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 findet direkt zwischen Browsern statt. Daher kann RTCDataChannel viel schneller sein als WebSocket, selbst wenn ein Relay-Server (Turn) erforderlich ist, wenn das Hole-Punching-Verfahren zur Bewältigung von Firewalls und NATs fehlschlägt.

RTCDataChannel ist in Chrome, Safari, Firefox, Opera und Samsung Internet verfügbar. Das Cube Slam-Spiel verwendet die API, um den Spielstatus zu kommunizieren. Spiele einen Freund oder spiele den Bären! Die innovative Plattform ShareFest ermöglichte die Dateifreigabe über RTCDataChannel und peerCDN. So erhielten wir einen Einblick, wie WebRTC die Peer-to-Peer-Verbreitung von Inhalten ermöglichen könnte.

Weitere Informationen zu RTCDataChannel finden Sie in der Protokollspezifikation des IETF-Frameworks.

Sicherheit

Es gibt mehrere Möglichkeiten, wie Apps oder Plug-ins für die Echtzeitkommunikation die Sicherheit gefährden. Beispiel:

  • Unverschlüsselte Medien oder Daten können zwischen Browsern oder zwischen einem Browser und einem Server abgefangen werden.
  • Apps können ohne das Wissen des Nutzers Video- oder Audioinhalte aufzeichnen und verbreiten.
  • Malware oder Viren können zusammen mit einem scheinbar harmlosen Plug-in oder App installiert werden.

WebRTC hat mehrere Funktionen, mit denen diese Probleme vermieden werden können:

  • 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 zusammen mit dem Browser aktualisiert.
  • Der Zugriff auf Kamera und Mikrofon muss explizit gewährt werden. Wenn die Kamera oder das Mikrofon aktiv ist, ist dies auf der Benutzeroberfläche deutlich zu erkennen.

Eine umfassende Beschreibung der Sicherheit beim Streaming von Medien wird in diesem Artikel nicht behandelt. Weitere Informationen finden Sie in der Vorgeschlagenen WebRTC-Sicherheitsarchitektur der IETF.

Fazit

Mit den APIs und Standards von WebRTC können Tools für die Erstellung und Kommunikation von Inhalten demokratisiert und dezentralisiert werden, darunter Telefonate, Gaming, Videoproduktion, Musikproduktion und Nachrichtensammlung.

Technologie kann so einfach wie möglich störend sein.

Der Blogger Phil Edholm formulierte es so: „Potenziellerseits könnten WebRTC und HTML5 die gleiche Transformation der Echtzeitkommunikation ermöglichen wie der ursprüngliche Browser für Informationen.“

Entwicklertools

Weitere Informationen

Standards und Protokolle

Zusammenfassung der WebRTC-Unterstützung

MediaStream- und getUserMedia-APIs

  • Chrome Desktop 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 und 11.1 und höher unter macOS
  • UC 11.8 und höher unter Android
  • Samsung Internet 4 und höher

RTCPeerConnection API

  • Chrome Desktop 20 und höher; Chrome für Android 29 und höher (ohne Flags)
  • 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 und 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-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-Plattform-Status.

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