new-web-technologies

“less known” client-side web technologies [Part 1]

Von am 30.10.2017

  1. Einleitung

 

Eine Homepage hier, eine Infoseite da,…
Mal ehrlich: Webtechnologien werden zum Großteil relativ einseitig genutzt -> zum Transport, Anzeigen und teilweise auch zum Generieren von Content.
Keine Frage: kleine, mittlere und große Agenturen, genauso wie auch “one-man-shows zum Erstellen von Internetseiten” sind ein gut funktionierendes Business – weil jedes Unternehmen heute einen oder mehrere gute Webauftritt(e) benötigt.
Aber es ist definitiv nicht das innovativste Business.

Auch wenn die Vermittlung und Strukturierung von Inhalten, die grafische Darstellung und die Benutzerfreundlichkeit bei jedem Projekt immer wieder eine neue Herausforderung darstellen..
Und auch, wenn kaum eine Seite oder ein Portal wirklich je komplett wie das andere ist (obwohl sich viele Dinge schon sehr einander annähern und der Mut zum Neuen oftmals der Sicherheit des bewährtem Einheitsbreies weicht) -> Letztendlich greifen die meisten Seiten im Internet auf dieselben (bewährten) Technologien und Techniken zurück.

Klar.. HTML und CSS zur inhaltlichen und grafischen Aufbereitung. Da gibt es nicht viel zu rütteln. Wobei es gerade schon bei CSS beginnt, dass bei Webentwicklern oftmals immer wieder dieselben Attribute Verwendung finden, statt sich auch einmal an “exotischere/neuere” Dinge zu wagen.

Ein Hauptgrund dabei, ist die Bestrebung (und meist Notwendigkeit) immer zu allen gängigen Browsern (auch zu älteren Versionen) kompatibel zu bleiben.
Damit gilt: während sich Webtechnologien, seit dem Aufkommen von HTML 5, in rasantem Tempo weiterentwickeln, hinkt die Nutzung neuer Dinge meist jahrelang hinterher.

Manchmal eben wegen benötigter Abwärtskompatibilität. Manchmal, weil die zur Verfügung gestellten neuen Technologien in erwähntem herkömmlichen Kontext – also traditionellen Webseiten – einfach gar nicht benötigt werden.
Wer benötigt schon wirklich WebGL 3D-Animationen (oder vielleicht sogar Interaktionen) auf einem reinen Informationsportal?
Manchmal aber auch, weil Webdeveloper mit bestimmten Neuerungen gar nicht erst in Berührung kommen und daher gar nicht wissen, dass es sie gibt.

 

Kein Wunder – reine WebApps (also interaktive Anwendungen, die ausschließlich über den Browser funktionieren) sind heute immer noch eher eine Nische -> vor allem im mobilen Bereich.
Viele “fancy technologies”, die mit HTML 5 kamen – und stetig dazu kommen – werden gar nicht erst evaluiert, da man bei “echten Anwendungen” dann doch eher auf der nativen (oder “hybriden”) Ebene bleibt.

Dabei könnten in den nächsten Jahren reine Webanwendungen eine echte Alternative zu herkömmlichen Apps bieten -> zumindest in manchen Anwendungsfeldern.
Die technologischen Möglichkeiten wachsen – längst schon sind Themen wie getrennte Ausführungs-Threads und das zur-Verfügung-stellen von offline Inhalten von allen modernen Browsern gut unterstützt.
Der Browser lässt daneben aber auch immer öfter direkte Kommunikation mit verbundener Hardware zu.
Umgehen mit Sensorendaten, Geräteinformationen und Connections zu externen Geräten/Beacons/…?
Vieles gibt es schon – und man kann schon fast sagen: was es noch nicht gibt, wird gerade standardisiert.

Das Thema Performance? Wenn man die Dinge nicht kennt, die sich in den letzten Jahren im Performance-Sektor von Webanwendungen getan haben, wird man überrascht sein, was da bereits seit einigen Jahren existiert, um JavaScript Code um ein gutes Stück schnell machen zu können (bei voller Abwärtskompatibilität).
Vor allem aber wurde in den letzten Jahren aber auch eine gänzlich neue Technologie entwickelt, die Webanwendungen performance-technisch auf ein neues Level bringen kann/soll. Eine Technologie, mit dem klingenden Namen “WebAssembly”, die mit dem Erscheinen von Safari 11, im vergangenen Monat (September 2017), bereits von allen aktuellen Browsern (Desktop und Mobile) unterstützt wird.
An dieser Stelle soll aber noch nicht gespoilert werden ;).

 

Es gibt viele Vorteile, welche sich aus reinen Webanwendungen ergeben, wie z.B. :

  • Unabhängigkeit von herstellerspezifischen App-Stores
  • direktes Anbieten von App-Services über die jeweiligen Homepages eines Unternehmens
  • wegfallen der Notwendigkeit einer Installation (eine Hürde, die für viele Anwender oftmals immer noch sehr groß ist und daher keinesfalls unterschätzt werden sollte)
  • […]

Damit wäre es nicht verwunderlich, wenn echte Webanwendungen in den nächsten Jahren – zumindest in einigen Einsatzgebieten – eine ernst(er) zu nehmende Konkurrenz zu nativen bzw. hybriden Anwendungen werden könnten -> gerade auch im mobilen Bereich.

 

In den kommenden Monaten wird sich diese 3-teilige Posting-Reihe mit “less known” Web Technologien (auf der Client Seite) beschäftigen.
Technologien, die sich entweder gerade noch in der Phase Standardisierung befinden (und daher von vielen Browsern noch gar nicht oder erst partiell/experimentell implementiert sind…).
Aber auch mit Technologien, die schon einen Schritt weiter sind, aber dennoch “wenig genutzt” bzw. dem “traditionellen Webentwickler” vielleicht einfach noch nicht richtig bekannt sind.

Dabei wird sich der erste Teil (im Folgenden) mit Technologien im Bereich “Communication & Media” beschäftigen. Der zweite Teil (im Dezember 2017) wird sich mit den Themen Offline Verfügbarkeit, Datenspeicherung und Threading befassen.
Der dritte Teil (März 2017) wird sich schließlich dem Thema “High-Performance” bei Webanwendungen widmen – und dort dann auch auf das zuvor angekündigte Thema „Webassemblies“ eingehen.
Ein Thema, das für jeden Web-Interessierten durchaus sehr spannend ist 😉 .
Das soll aber nicht heißen, dass im gleich Folgenden 1. Teil nicht auch etwas sehr Spannendes (hoffentlich noch für die meisten Leser relativ Unbekanntes) stecken sollte.

In jedem dieser drei Teile werden kurz unterschiedliche Technologien vorgestellt – wobei immer eine der vorgestellten Technologien (die schon etwas breitere Browserunterstützung genießt und damit bereits zum Basteln geeignet ist) etwas genauer behandelt wird.
Auf Basis dieser genauer vorgestellten Technologie wird in jedem Teil auch jeweils ein praktisches, selbst programmiertes, Beispiel vorgestellt.
Soviel sei verraten: In diesem Teil wird ein rein HTML5/JavaScript-basiertes Echtzeit-Schachspiel mit integriertem Videochat vorgestellt.

Es wird NICHT detailgenau auf die gesamte Programmierung dieser Beispiele eingegangen (das würde den Rahmen, zumindest bei dem ersten vorgestellten Beispiel, sprengen).
Aber es darauf eingegangen, wie die “Haupttechnologie”, die darin vorgestellt wird, verwendet wird.

Wichtig ist auch, dass in jedem Beispiel auch die vorgestellte “Haupttechnologie” aller vorhergehenden Teile mit einfließt.
Damit soll letztendlich in Teil 3 eine kleine, praktisch einsetzbare, Anwendung entstehen, die man aus App-Stores in unterschiedlichsten Ausführungen kennt.
Eine Anwendung , die sehr viele User in irgendeiner Form auf ihrem Smartphone installiert haben – die hier aber als wirklich reine WebApp umgesetzt werden soll und als solche noch kaum bis gar nicht bekannt sein dürfte.
Damit soll am Ende demonstriert werden, was moderne Browser heute bereits alles vollbringen können.

 

  1. First Chapter: Communication & Media

Web NFC

Web NFC existiert bislang nur als Draft, verspricht allerdings eine Kommunikation mittels NFC direkt aus dem Webbrowser -> in beide Richtungen.
Das mag auf den ersten Blick vielleicht nicht notwendig erscheinen, da NFC im Consumer Bereich meist für sehr spezielle Anwendungsfälle (wie etwa bargeldloses Zahlen oder Entwerten digitaler Tickets) eingesetzt wird. Für diese Anwendungsfälle lädt man sich ohnehin meist zuvor eine spezifische App auf das Smartphone.

Wirft man aber einen zweiten Blick auf dieses Thema, könnte Web NFC dennoch einer breiteren Masse sehr nützlich werden:
NFC Tags sind günstig, lassen sich einfach an verschiedensten Objekten anbringen und können Daten speichern.
So könnte es künftig z.B. sein, dass NFC Tags klassische QR Codes ersetzen und man z.B. über eigene Webanwendungen, oder über die Webseiten von Unternehmen/Institutionen, standortspezifische Informationen abrufen kann bzw. Aktionen durchgeführt werden können.

Ein Beispiel: Ein Museum kann Inhalte zu seinen Ausstellungsstücken über das gewohnte CMS einpflegen. Man kann diese Inhalte über die Webseite manuell aufrufen. Geht man aber durch das Gebäude, wird anhand der NFC Tags automatisch der jeweilige Inhalt geladen. Gerade bei Museen und Ausstellungen möchte man sich oft nicht immer eigene Apps runterladen.

Kurzer Überblick über die API
Wie bereits angedeutet, wird die API bislang von keinem Browser offiziell unterstützt. Die Drafts zur Spezifizierung/Standardisierung sehen folgende zwei Core-Funktionen vor, um einerseits Daten über NFC auszulesen bzw. andererseits Daten zu übertragen:

navigator.nfc.watch(callback, options)
 Registers for a notification about the data read from the NFC adapter specified by options.

navigator.nfc.push(message, options)
 Triggers sending the message (string, ArrayBuffer or NDEF record structure) to the NFC adapter specified by options.

 

Web Bluetooth API

Wohl ein wenig bekannter und auch weiter entwickelt ist die Web Bluetooth API.

In Chrome ist diese API bereits implementiert – auch wenn nicht auf jedem Betriebssystem alle Funktionen verfügbar sind (siehe hier: https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/implementation-status.md ).

Grundsätzlich kann man mit der API, z.B. mittels Einsatz von Bluetooth Beacons, auch sehr ähnliche Szenarien abbilden, wie mittels NFC.
Ihre Stärke spielt die Web Bluetooth API aber dabei aus, den Browser direkt mit Bluetooth bzw. Bluetooth LE Geräten kommunizieren lassen zu können.
Das mag auf den ersten Blick etwas unnötig erscheinen, wenn man an die üblichen Bluetooth-Geräte denkt: Mäuse, Tastaturen, Kopfhörer…
-> Denn diese sind ohnehin auf Betriebssystem Ebene installiert und die Inputs (also etwa die User Eingaben) bzw. Outputs (also etwa Audio-Daten für die Kopfhörer) werden über diese „Bridge“ übertragen, ohne dass der Browser hierbei irgendetwas spezielles leisten müsste.
Der Entwickler einer Webanwendung muss sich natürlich keine Gedanken machen, ob da letztendlich eine Bluetooth Maus verwendet wird, oder eine USB Maus, …

Interessant wird es aber, wenn man als Entwickler mit Services eines Bluetooth-Devices interagieren möchte, über die keine Standardbrücke durch das OS gelegt wird.
Und hier sind die Anwendungsfälle zahlreich. Moderne BluetoothLE Geräte verfügen über sogenannte „GATT-Services“.
Über diese Services können verschiedenste Werte/Daten von einem Gerät ausgelesen bzw. auch geschrieben werden – sogenannte „Characteristics“. Diese Characteristics können ihrerseits wieder über Properties verfügen.
Verfügt ein Characteristic über eine sogenanntes notification oder indicator Property, dann wird eine Änderung dieses Characteristics an den Client (in unserem Fall wäre das dann der Browser) mitgeteilt. In diesem Fall kann man z.B. EventHandler für relevante Characteristics definieren. Somit bekommt der Client (also hier der Browser) immer mit, wenn sich ein bestimmter Wert beim Sender verändert hat.

Ein Beispiel: Man verwendet etwa ein Arduino Board mit Temperatursensor, das zudem auch noch über Batterie betrieben werden kann. Dieses Board verfügt über einen BluetoothLE Sender. Hier könnte man nun zwei GATT Services implementieren: Einen für den Batteriestatus und einen für die gemessenen Temperaturwerte.
Der erste GATT Service könnte nun z.B. ein Characteristic enthalten, dass einen Wert für den momentanen Batteriestand darstellt – dieses verfügt über ein „indicate property“ und der Client kann daher bei einer Veränderung unmittelbar reagieren (z.B. dem Anwender den neuen Batteriestand ausgeben).

Ein anderes Characteristic von diesem Service könnte z.B. der maximal-Wert für die Batterie sein. Dieser verändert sich nicht und muss vom Client nur einmalig ausgelesen werden. Damit kann der Client auch immer prozentuell darstellen kann, wie voll die Batterie noch ist.

Das zweite GATT Service wäre in diesem Fall dann das „Interessante“ – es würde die gemessenen Daten des Temperatursensors als Characteristics zur Verfügung stellen… Also etwa die aktuelle Temperatur und eventuell auch die Luftfeuchtigkeit (je nachdem wie der Sensor funktioniert). Auf dieses Arduino Board können natürlich noch andere Sensoren platziert werden, die wiederum als eigene Services implementiert werden und ihr Werte als Characteristic zur Verfügung stellen und Änderungen bei diesen in aller Regel als notifications oder indicates sofort beim Client „melden“.

Damit ist der Browser plötzlich in der Lage, mit beliebigen externen Geräten zu kommunizieren und Daten zu empfangen (aber natürlich auch zu versenden) – ohne, dass er dafür über den Umweg eines Servers gehen müsste.

Kurzer Überblick über die API

navigator.bluetooth.requestDevice(serviceFilters)
 Scans for the device in range supporting the requested services. Returns a Promise.

device.gatt.connect()
 Returns a Promise resolved with the server object providing access to the services available on the device.

server.getPrimaryService(name)
 Returns a Promise resolved with the particular Bluetooth service on the device.

service.getCharacteristic(name)
 Returns a Promise resolved with the GATT characteristic object.

characteristic.readValue()
 Returns a Promise resolved with a raw value from the GATT characteristic.

characteristic.writeValue(value)
 Writes a new value for the GATT characteristic.

 

WebRTC

In Zeiten von Websocket-Verbindungen wirkt das klassische HTTP Request-Response Modell schon beinahe passé.
Kein Wunder – wurde das klassische Web „zu seiner Zeit“ ursprünglich eher als Medium konzeptioniert, das relativ statische Informationen auf Anfrage an den (anfragenden) Zielrechner übermitteln soll. Fertig.

Konzeptioniert und entwickelt zu einer Zeit, wo wahrscheinlich kaum jemand damit gerechnet hätte, wie sich die Anwendungen und Möglichkeiten des Webs – und auch die immer steigenden Anforderungen – des Mediums im Laufe der Zeit wandeln würden.
Vom statischen Informationsmedium hin, zu einem umfassenden, universellen, multimedialen Austausch- und Kommunikationsmedium.
Dabei muss an dieser Stelle unterschieden werden -> zwischen dem Internet, als reine technologische Infrastruktur (wie es auch in herkömmlichen Anwendungen, Spielen und Apps verwendet wird) und dem “Web”, das an dieser Stelle für Inhalte steht, die über das Internet klassisch mittels Browser konsumiert/ausgeführt werden.

Während ersteres theoretisch schon immer für alle Arten von Anwendungen herangezogen werden konnte (sieht man von hardwaretechnischen/infrastrukturellen Einschränkungen ab), hat sich letzteres Schritt für Schritt in “gesundem Maß” immer mit den Gegebenheiten weiterentwickelt.

Diese Weiterentwicklung war stets geprägt von drei Faktoren:

  1. Die zur Verfügung stehenden Technologien/Ressourcen/Bandbreiten -> es war kein Zufall, dass in den Zeiten, als noch analoge Modems zur Einwahl ins Internet benutzt wurden, das zuvor genannte klassische Verfahren der HTTP-Request-Response entwickelt und  HTTP als DAS Internet-Protokoll etabliert wurde. Für einen kontinuierlichen Austausch von Daten war das Web in seinen Ursprüngen eher weniger gedacht.
  2. Die Anforderungen -> wie bereits erwähnt: Zu Beginn des Internets/Webs, waren auch die Anforderungen ganz andere, als sie es heute sind. Doch mit steigenden Bandbreiten (und anderen Faktoren) haben sich auch die Wünsche/Anforderungen der Anwender weiterentwickelt. Und damit auch die Webtechnologien selbst.
  3. Die Plattformunabhängigkeit -> Wichtig war dabei stets, dass Webtechnologien immer auf unterschiedlichsten Plattformen (und innerhalb dieser, auch auf unterschiedlichen Browsern) funktionieren. Mit dem Aufkommen der ersten Touch-Smartphones wurde diese Anforderung nochmals um einiges wichtiger.

Analysiert man nun etwa den zweiten Punkt, so merkt man, dass durch innovative Ansätze (wie etwa die “Entwicklung” von AJAX) versucht wurde – innerhalb der gegebenen Limitationen – Webanwendungen um einiges dynamischer zu gestalten, als sie es bis dahin waren.
Und sie somit an neuere Anforderungen anzupassen.
Spätestens mit Aufkommen von HTML 5 und dessen multimedialen Elementen,  ging der Trend allmählich schrittweise dazu, die ursprünglichen Ideen/Hintergründe des klassischen Webs aus technologischer und aus anforderungstechnischer Sicht neu zu bewerten.
Es galt/gilt vieles zu hinterfragen und die ursprünglichen Konzepte & Limitationen allmählich “aufzubrechen” un zu modernisieren.

Gerade wenn man auf die Kommunikationsfähigkeiten eines modernen Browsers blickt, sind/werden dessen Kommunikationswege wesentlich vielfältiger, als “nur” über HTTP eine Response zu einem Request zu erhalten oder sogar auch “nur” über WebSockets eine persistente (bidirektionale, realtime) Verbindung zu einem Server aufzubauen.
WebNFC und die Web Bluetooth API haben bereits gezeigt, dass Browser künftig (bzw. zum Teil bereits heute) weitaus mehr können, als „lediglich“ mit Servern zu kommunizieren.

Damit soll am Ende (als „Hauptattraktion“) dieses Artikels nun WebRTC nähergebracht werden – eine Technologie die zwar, wie HTTP oder Websockets, über IP kommuniziert (also anders als Web NFC, oder die Web Bluetooth API) – dabei aber wiederum gänzlich ohne Server auskommt.
Also: Peer to Peer IP Kommunikation… mittels Browser!

WebRTC ist immer noch relativ unbekannt, obwohl die erste veröffentlichte Spezifikation mittlerweile bereits 6 Jahre zurückliegt (2011).
Seitdem wurde WebRTC kontinuierlich weiterentwickelt – es hat allerdings bis zum September dieses Jahres (2017) gedauert, bis die Technologie endlich vollständig in den aktuellsten Versionen aller wichtigen Browser vollständig implementiert wurde (zuletzt Safari)

WebRTC steht für for Web Real-Time Communication. Es bringt Web Browsern unterschiedlicher Geräte die Möglichkeit, direkt zu kommunizieren.
Damit lassen sich einfache (text basierte) Nachrichten genauso austauschen, wie binäre Daten. Sogar Realtime-Streaming zwischen den beiden Endpunkten ist möglich.
Und tatsächlich ist sogar gerade Letzteres eines der Haupteinsatzgebiete, warum WebRTC ursprünglich ins Leben gerufen wurde: Der Austausch zwischen Audio und Video Daten in Echtzeit -> zwischen zwei Browsern… ohne Plugins und ohne Installationen.

Eine der interessantesten Nebeneffekte, als die relativ komplexe Spezifikation von WebRTC in ihrem ersten Entwurf veröffentlicht wurde, war die Integration eines Standards, der Browsern den Zugriff auf Kameras und Mikrofone ermöglichen sollte.
Unter der Spezifikation von WebRTC wurde die JavaScript Funktion navigator.getUserMedia() eingeführt. Mit dieser Funktion können Audio/Video Streams initialisiert werden.
Und obwohl diese Funktion in erster Linie implementiert wurde, um solche Streams mittels WebRTC an einen anderen Browser zu versenden, lassen sich alleine durch diese „Nebenfunktion“ des WebRTC-Standards auch noch ganz andere Anwendungsfälle realisieren.
Etwa ein „Record, View & Store“ Tool für Audio/Video Daten direkt aus dem Browser… oder sogar ganze Audio- und Imageprocessing Anwendungen (z.B. QR Code Scanner) im Browser.
Später wurde diese Funktion durch „navigator.mediaDevices.getUserMedia()“ ersetzt. Deren Syntax ist etwas anders als die ursprüngliche Version, jedoch blieben Zweck und Möglichkeiten unverändert.

Kurzer Überblick über „navigator.mediaDevices.getUserMedia()“

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
     /* use the stream */
})

.catch(function(err) {
     /* handle the error */
});

Die Constraints geben an, was und wie es aufgezeichnet werden soll. Etwa:
Video, aber kein Audio

var constraints = { audio: false, video: true};

ODER: Video dabei mit einer Auflösung von 1280*720, kein Audio

var constraints = { audio: true, video: { width: 1280, height: 720 } };

 

Mit den Constraints lassen sich (je nach Browserversion/Status der Implementierung/Unterstützung durch Hardware und Betriebssystem) eine Vielzahl von Paramatern für das Audio/Video Capturing verwenden.
Etwa: Mindest-, Ideal- und Maximalauflösung des Videos, Framerate oder auch welches Mikro/welche Kamera verwendet werden soll, wenn mehrere vorhanden sind. Letzteres ist z.B. vor allem bei Mobile Devices wichtig (da diese meist über 2 Kameras verfügen).

Der erzeugte Stream lässt sich jetzt einer (zuvor aufgebauten) WebRTC Verbindung hinzufügen um ihn in Echtzeit zum anderen Endpunkt zu übertragen.
Eine solche, zuvor aufgebaute, WebRTC Verbindung wird durch ein Objekt (im folgenden Beispiel „RTCConnectionWithPeter“) dargestellt.

Beispiel:

navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
     RTCConnectionObjectWithPeter.addStream(stream);
})


Aufbauen einer WebRTC Connection – wirklich ganz ohne Server?

Wie zuvor bereits erwähnt, sind WebRTC Verbindungen Peer to Peer Verbindungen. Wird also wirklich kein Server benötigt?
Diese Frage lässt sich mit einem „Nein“ beantworten.
Während der Datenaustausch einer WebRTC Verbindung zwischen 2 Clients tatsächlich ohne weitere Zwischenstelle stattfindet, muss zum Aufbau dieser Verbindung zunächst ein sogenannter„ICE Server“ von beiden Stellen kontaktiert werden.

Von diesem ICE Server erhalten die Clients ein „ICE Candidate“ Objekt. Ein solcher ICE Candidate enthält Informationen darüber, wie zu einem Client eine Verbindung aufgebaut werden kann. Da sich die meisten Clients hinter Firewalls oder hinter Routern befinden, muss der ICE Server mit dem Client erst über einige komplexere Verfahren aushandeln, wie ein anderer Client später durch all diese Hürden eine Verbindung zu ihm aufbauen kann.
Dabei kommen Techniken wie „Hole Punching“ zum Einsatz, die etwa auch bei Online-Games eingesetzt werden.

Danach müssen jene zwei Clients, die miteinander kommunizieren möchten, ihre ICE Candidates austauschen.  Dieser Austausch erfolgt über einen sogenannten „Signal Server“. Ist das passiert, können die beiden Clients schließlich eine direkte Verbindung zueinander aufbauen.

Für all diese Schritte sind einige Funktionsaufrufe und Abfragen notwendig. Und natürlich das Vorhandensein eines ICE-, sowie eines Signal-Servers.
Zum Glück gibt es für diese Schritte mit „peer.js“ ein online Service mit entsprechender JavaScript API. PeerJS macht den Verbindungsaufbau über WebRTC sehr einfach.
Man kann den ICE und Signaling Service von „peer.js“ als Cloud nutzen, indem man einfach nur die Javascript API in die eigene Webseite einbindet und darüber die Verbindung aufbaut.
Oder man lädt sich die open source Server-Implementation (nodejs) von peer.js runter und führt diese selbst auf einem entsprechenden Server aus.

Ein Live-Beispiel

Für folgendes Live-Beispiel wurde peer.js verwendet. Der Servercode wird auf einem NodeJS Server über Microsoft Azure gehostet.
Das Live-Beispiel ist ein selbst programmiertes online Schachspiel mit integriertem Video Chat. Zwei Spieler können dabei in Echtzeit miteinander spielen und sehen sich gleichzeitig. Beliebig viele weitere Personen können das Spiel (momentan noch nicht den Videochat) der beiden verfolgen.
Alles ist gänzlich mit modernen Webtechnologien umgesetzt – ohne Plugins oder spezielle Erfordernisse.

LINK ZUM SPIEL: https://dm161564.students.fhstp.ac.at/WebChess/war/

Das Schachspiel selbst läuft über eine Websocket Verbindung und einen NodeJS Server. Die ersten beiden Besucher die eine Spielsession joinen, sind die Spieler. Diese bekommen jeweils einen individuellen Key zugesandt, mit dem sie sich beim PeerJS Server registrieren.
Außerdem erhalten sie jeweils den Key des anderen.

Dadurch sind sie im schließlich in der Lage, eine P2P Verbindung zueinander aufzubauen und Audio/Video Daten auszutauschen.

Der ganze Code für den Videochat ist letztlich sehr simpel:

function videoChat(sessionID,flag)
{
     peer = new Peer(sessionID+flag, {host: '888peerjsserver.azurewebsites.net', port: 443, path: '/myapp', secure: true});
     if (flag=="white")
     {
          peer.on('call', function(call)
          {
                 passiveCall(call);
          });
     }
     else
     {
                   activeCall(peer,sessionID);
     }
}

 

Die Funktion wird aufgerufen, sobald 2 Spieler mit dem Schachserver verbunden sind und dieser den Beiden das entsprechende Signal (über Websockets) sendet.

Beide erhalten dabei eine Spiel-SessionID und ein individuelles Flag. Mittels „new Peer“ registrieren sich beide am PeerJS Server.

Der erste Spieler (weiß) registriert schließlich den Eventhandler „on call“ für die Aufgebaute peer Verbindung.
Der zweite Spieler (schwarz) führt später die Funktion „activeCall“ aus, die den weißen Spieler anruft, worauf besagter Event bei ersterem ausgelöst wird.

 

Die Funktion activeCall:

function activeCall (peer,sessionID) {
            navigator.getUserMedia({video: true, audio: true}, function(stream) {
                    document.getElementById("displayMe").src =
                      URL.createObjectURL(stream);

                    document.getElementById("displayMe").play();
                    var call = peer.call(sessionID + "white", stream);
                    call.on('stream', function(remoteStream) { 
                             document.getElementById("displayOther").src = 
                             URL.createObjectURL(remoteStream);
                             document.getElementById("displayOther").play();
                    });
               }, // errorCallback
                   function (err) {
                    //error action
               }
         );
}

Mittels „navigator.getUserMedia“ wird nun ein Audio- und Videostream geöffnet. Sobald dieser bereit ist, wird er in einem DOM video-node mit der ID „displayMe“ angezeigt – somit sieht der schwarze Spieler seine Videoübertragung zunächst auch selbst.
Gleichzeitig wird mittels „peer.call“ eine Verbindung zum weißen Spieler aufgebaut. Dieser Verbindung wird das erstellte Streamobjekt übergeben.
Wie weiter oben bereits beschrieben, hat der weiße Spieler zuvor mittels „peer.on(‘call‘, …….)“ einen Listener für den Fall eines calls erstellt, der beim Auftreten dieses Events die Funktion „passiveCall“ ausführt.


passiveCall:

function passiveCall (call)
{
    call.on('stream', function (remoteStream) {
            document.getElementById("displayOther").src =
              URL.createObjectURL(remoteStream);
            document.getElementById("displayOther").play();
    });
    navigator.getUserMedia({video: true, audio: true}, function (stream) {
              document.getElementById("displayMe").src =
                URL.createObjectURL(stream);

              document.getElementById("displayMe").play();
              call.answer(stream);
         }, // errorCallback
         function (err) {
             //error action           
         }
    );
}

In der Funktion „passiveCall“ wird beim weißen Spieler zusätzlich der Evenhandler „call on stream“ registriert. Sobald dem weißen Spieler also vom schwarzen Spieler ein Stream geschickt wird, wird dieser als source des DOM Elements „#displayOther“ gesetzt -> es handelt sich dabei wieder ein video-node. Dieses wird anschließend mittels „play“ abgespielt.
Der schwarze Spieler hat den selben Eventhandler in der Funktion „activeCall“ registriert (siehe oben).

Beim eingehenden Call des schwarzen Spielers erstellt der weiße Spieler nun ebenfalls ein Streamobjekt mittels „getUserMedia“.
Auch er zeigt diesen Stream in einem video-node mit der ID „displayMe“ an (sodass auch er sich selbst sieht) und sendet diesen stream wiederum schließlich an den schwarzen Spieler (mittels „call.answer(stream)“ ) -> ähnlich wie es der schwarze Spieler beim Aufbau des Calls bereits gemacht hat.

 

Damit ist dieser erste Artikel zu Ende. Hoffentlich konnte er das Interesse für die ein oder andere „upcoming“ oder „less known Webtechnologie vermitteln.
Im besten Fall sollte es jetzt zudem leicht fallen, mittels PeerJS, mit wenigen Schritten selbst einen P2P Videochat in die eigene WebApp oder Homepage zu integrieren – ausschließlich mit vorhandenen Browsertechnologien.

 

The comments are closed.