Category Archives: News

Kommunizieren statt Kommandieren

Computer durchdringen immer mehr Lebensbereiche. Dabei bleibt oft die eigentliche Frage des Nutzens auf der Strecke. Doch wie findet man einen solchen Nutzen? Wie kann eine gemeinsame Diskussionsgrundlage für das Finden und Umsetzung von neuen digitalen Ideen geschaffen werden? Der Austausch von Informationen, also das Kommunizieren, ist aber noch in einer zweiten Hinsicht essentiell für die Entwicklung neuer Anwendungen. Denn auf der einen Seite verlieren klassische Ein- und Ausgabemittel wie Tastatur und Monitor an Bedeutung und auf der anderen Seite nehmen die Vernetzung sowie die sensorische Möglichkeiten der Geräte zu. Damit drängt sich die Frage auf, wie wir als Menschen mit all diesen Maschinen kommunizieren sollen. Wie kann eine natürliche Interaktion für Anwendungen im Internet der Dinge aussehen?

Austausch von Informationen, also das Kommunizieren, ist in zweierlei Hinsicht essentiell für die Entwicklung neuer Anwendungen. Zum einen muss eine gemeinsame Diskussionsgrundlage für das Finden und Umsetzung von neuen digitalen Ideen geschaffen werden und zum anderen erwartet der Nutzer möglichst natürliche Interaktionsformen für den Informationsaustausch innerhalb einer Anwendung.

image

Gemeinsam mit Partnern erarbeiten, erleben und evaluieren wir In Workshops neue Ideen. Als Kommunikationsgrundlage dienen vorgefertigte und einfach zu nutzende APIs (Programmierschnittstellen) z. B. zur Sprachverarbeitung oder Positionsbestimmung kombiniert mit Alltagsgegenständen und interaktiven Spielzeugen von Lego Mindstorms bis zu Microsoft Kinect.

In erster Linie werden mobile Nutzungsszenarien diskutiert, bei denen der Anwender mit einem einzelnen Endgerät interagiert. Doch Computer durchdringen zunehmend mehr Lebensbereiche und sind dabei immer weniger offensichtlich als solche erkennbar (Ubiquitous und Pervasive Computing). Häufig existieren nicht einmal die gewohnten Ein- und Ausgabekanäle wie Bildschirm und Tastatur. Dafür sind diese Geräte meist vernetzt wenn nicht sogar gleich über das Internet verbunden (Internet of Things).

Die Herausforderung liegt nun darin, neue Interaktionsformen zu finden, die nicht mehr nur einer 1:1-Beziehung zwischen Mensch und Maschine gerecht werden, sondern sich auch für 1:n-Szenarien eignen, bei denen der Nutzer sich inmitten einer Vielzahl an Geräten bewegt. Diese miteinander vernetzten Geräte bilden eine komplexe Benutzungsschnittstelle aus unterschiedlichsten Sensoren (Ambient Intelligence) und Aktuatoren (z. B. Motoren).

Der Anwender erwartet natürliche Interaktionsformen, die beispielsweise auf angeborene Fähigkeiten wie Gesten und Sprache basieren. Mangels der gelernten und auf Metaphern basierenden grafischen Benutzungsschnittstellen ist hier sowieso ein Umdenken erforderlich. Die Erkennung von Gesten und Sprache (Speech Recognition) funktioniert bereits sehr gut. Technisch ist es dabei mittlerweile sogar möglich nonverbale Signale wie die Gemütslage zu ermitteln und in die Kommunikation zwischen Mensch und Maschine einzubeziehen.

image

Die Erkennung bei Spracheingaben kann durch Grammatiken anstelle einer allgemeinen Transkription verbessert werden. Doch fehlende „Höflichkeitsfloskeln“ machen diese Form der Interaktion schnell zu einem unnatürlichen Kommandieren.

Das eigentliche Verstehen (Natural Language Understanding) ist jedoch noch ganz am Anfang. Noch können wir mit den Geräten nicht natürlich Kommunizieren, denn Maschinen verfügen nur über einen eingeschränkten Kontext und Weltwissen und Intuition fehlen. In vielen Fällen sind nicht einmal Höflichkeitsfloskeln erlaubt, so dass sich die Kommunikation auf das Erkennen von Schlüsselwörtern beschränkt und somit eher einfachen Kommandos entspricht. 1966 entwickelte Joseph Weizenbaum das Computerprogramm ELIZA, bei dem es sich um eine oberflächliche Simulation eines Psychotherapeuten handelt. ELIZA zeigt eindrucksvoll, dass Maschinen natürliche Kommunikation auf einzelne Domänen beschränkt vorgaukeln können, solange auf Weltwissen verzichten werden kann. Auch ein großer Teil der interaktiven Erwachsenenunterhaltung und der ein oder andere Facebook Chatbot (textbasiertes Dialogsystem) machen sich die Eindeutigen Interessen der Anwender zunutze und erkennen so scheinbar natürlich deren Absichten.

Bombe: „Ich denke, also bin ich.“ […] Doolittle: „Aber woher weißt Du, dass außer Dir etwas existiert?“ Bombe: „Meine sensorische Apparatur vermittelt es mir.“ (Quelle: Dark Star, 1974)

Von der philosophisch anmutenden Diskussion mit der „Bombe 20“ aus dem Science-Fiction Klassiker Dark Star von 1974 sind wir jedoch trotz Siri und Co. noch ein ganzes Stück entfernt. Doch genau diese Bombe zeigt, was wir schon heute realisieren können: Interaktionen müssen mit allen zur Verfügung stehenden Informationen (Sensoren) aus dem Kontext kombiniert werden. Eine Spracheingabe in der Form „Licht an“ bei mehreren Leuchten alleine reicht bei weitem nicht aus. Kombiniert mit einer auf die Leuchte deutenden Geste kommt das dem natürlichen Verhalten jedoch schon sehr nah. Aber auch Positionsdaten (wo bin ich) und Blutdruck (wie geht es mir) können helfen, Absichten besser zu „verstehen“.

Und damit schließt sich der Kreis und wir sind wieder bei der ganz am Anfang erwähnten Bedeutung von Kommunikation: Die Vielfalt solcher Interaktionsformen ist so groß und vor allem die Erfahrungswerte sind so gering, dass die Umsetzung nicht einfach Delegiert werden kann, sondern beginnend mit der Ideenfindung Kommunikation essentiell ist.

Learnings from Embedded World

It´s been my second visit at Embedded World this year. I strongly recommend this fair to everybody involved in the Internet of Things idea (and I always prefer meeting people carrying Leathermans to people wearing a suit, which you´ll find at that time at the MWC). At Embedded World you meet all the experts who build the foundation of our future: Sensors, processors, embedded devices and alike are everywhere. Best of all, the chip makers finally understand, that´s the developer who counts! Therefore, you – as a developer – are welcome everywhere: Chance have been great to make a good bargain and to grab a nice developer kit.

DSC_0210

We did some hacking and sessions on the internet of things at the Deutsche Telekom booth together with our friends of the M2M unit.

The industry finally understands that we need more innovation. Last year we have been one of the few companies using inspiring showcases instead of dry industrial solutions. This year it seemed every second booth showcases something made of Lego, slot car tracks, RC cars etc. – I appreciate this, because it´s not about the technology alone. The true challenge is inspiration, innovation and generating future needs, we are not yet aware…

Echtzeitkommunikation mit WebRTC enträtselt und ohne Schnickschnack

WebRTC-Logo

WebRTC-Logo von http://www.webrtc.org/ 

Es scheint so, dass WebRTC sich zukünftig zu einem Standard für die Echtzeitkommunikation im Browser mausern könnte. Denn auch wenn WebRTC noch weit von einem Browser-übergreifenden Standard entfernt ist, reicht der aktuelle Stand durchaus schon aus, erste Gehversuche wenn nicht sogar bereits erste Anwendungen zu wagen. Für die effiziente Arbeit gibt es einen ganzen Haufen an JavaScript-Bibliotheken, welche die Komplexität und eventuelle Unzulänglichkeiten kompensieren. Nur leider ist es dann auch schwierig, die eigentliche Arbeitsweise zu verstehen und möglichen Problemen auf den Grund zu gehen. Darum dieser Artikel rund um WebRTC mal ganz ohne Schnickschnack.

Audio und Video

Viele Entwickler verstehen unter WebRTC in erster Linie das Einbinden der Webcam. Dieses gestaltet sich mit WebRTC in der Tat auch sehr einfach und gelingt im Google-Chrome z. B. mit JavaScript über navigator.webkitGetUserMedia (im Firefox heißt es aktuell navigator.mozGetUserMedia):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Stream
var senderStream;
var constraints = {audio: true, video: true};
var startButton = document.getElementById("startButton");
startButton.onclick =  start;
 
function start() {
    // Request sender stream
    console.log("request local stream");
    // Exact method varies based on browser
    navigator.webkitGetUserMedia(constraints, gotStreamSuccessCallback, errorCallback);
}
 
function gotStreamSuccessCallback(stream) {
    var senderVideo = document.getElementById("senderVideo");
    senderVideo.src = window.URL.createObjectURL(stream);
    senderStream = stream;
}
 
function errorCallback(error) {
    console.log("navigator.getUserMedia error: ", error);
}

Echtzeitkommunikation

simple-web-rtc-call-flow

Das Sequenzdiagramm aus der Spezifikation unter http://dev.w3.org/2011/webrtc/editor/webrtc.html  ist auf den ersten Blick wenig erhellend. Dabei ist der Ablauf garnicht so kompliziert…

Die Verarbeitung von Medien-Streams in Form von Audio und Video ist nur ein Aspekt von WebRTC. Denn die eigentliche Stärke ist die Echtzeitkommunikation über Browser hinweg per RTCPeerConnection. Die Arbeitsweise ist eigentlich ganz einfach:

  1. Der Sender generiert (nicht sendet, sondern generiert nur) ein Angebot (createOffer). In so einem Angebot (Session Description Protocol, kurz SDP) stehen die verfügbaren Codecs und Streams und jedes Mal, wenn sich ein Angebot ändert, muss das auch entsprechend bekannt gemacht und aktualisiert werden.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    // RTCPeerConnection WITHOUT the use of a server
    var servers = null;
    var senderPeerConnection;
    var senderIceCandidates = [];
    var callButton = document.getElementById("callButton");
    callButton.onclick = call;
     
    function call() {
     
        // create sender peer connection
        console.log("create sender peer connection");
        senderPeerConnection = new webkitRTCPeerConnection(servers);
        senderPeerConnection.onicecandidate = gotSenderIceCandidate;
     
        // add stream
        senderPeerConnection.addStream(senderStream);
     
        // create offer
        senderPeerConnection.createOffer(gotSenderDescription);
     
    }
     
    function gotSenderDescription(description){
        // console.log("offer from senderPeerConnection: \n" + description.sdp);
        senderPeerConnection.setLocalDescription(description);
        var senderDescriptionText = document.getElementById("senderDescriptionText");
        senderDescriptionText.value = description.sdp;
    }
  2. Neben diesem Angebot werden noch die eigentlichen Verbindungsmöglichkeiten für die Empfänger erzeugt. Die Verbindungsmöglichkeiten (Interactive Connectivity Establishment, kurz ICE) umfassen die möglichen IP-Adressen, Ports usw. – letzteres kann wie in diesem Beispiel sowohl lokal erzeugt oder von einem sogenannten TURN- oder STUN-Server generiert werden.
    1
    2
    3
    4
    5
    6
    7
    
    function gotSenderIceCandidate(event) {
        if (event.candidate) {
            var senderIceText = document.getElementById("senderIceText");
            senderIceCandidates.push(event.candidate);
            senderIceText.value = JSON.stringify(senderIceCandidates);
        }
    }
  3. Der Empfänger erhält das Angebot auf einem beliebigen Weg. Normalerweise über einen Server oder eine Socket-Verbindung. Aber es geht auch wie hier im Beispiel einfach per „Copy and Paste“ vom einen Browser zum anderen (oder sogar per Email). An dieser Stelle sollte die Verbindung auch auf den Empfang von Medienstreams vorbereitet werden (onaddstream).
  4. Anschließend erzeugt der Empfänger eine Antwort (createAnswer). In dieser Antwort stehen genauso wie in dem Angebot die verfügbaren Streams und Codecs (SDP).
  5. Nun werden die Verbindungsmöglichkeiten (ICE) des Senders verarbeitet. Auch diese können auf einem beliebigen Weg übertragen werden.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    var servers = null;
    var remotePeerConnection;
    var remoteIceCandidates = [];
    var answerButton = document.getElementById("answerButton");
    answerButton.onclick = answer;
     
    function answer() {
        // create remote peer connection
        console.log("create remote peer connection");
        remotePeerConnection = new webkitRTCPeerConnection(servers);
        remotePeerConnection.onicecandidate = gotRemoteIceCandidate;
        remotePeerConnection.onaddstream = gotRemoteStream;
     
        var senderDescriptionText = document.getElementById("senderDescriptionText");
        var senderDescription = new RTCSessionDescription({sdp:senderDescriptionText.value, type: "offer" });
        remotePeerConnection.setRemoteDescription(senderDescription);
        remotePeerConnection.createAnswer(gotRemoteDescription);
    }
     
    function gotRemoteStream(event) {
        console.log("gotRemoteStream stream: " + event.stream);
        var remoteVideo = document.getElementById("remoteVideo");
        remoteVideo.src = webkitURL.createObjectURL(event.stream);
    }
     
    function gotRemoteDescription(description) {
        // console.log("offer from remotePeerConnection: \n" + description.sdp);
        remotePeerConnection.setLocalDescription(description);
        var remoteDescriptionText = document.getElementById("remoteDescriptionText");
        remoteDescriptionText.value = description.sdp;
     
        // list of candidates
        var senderIceText = document.getElementById("senderIceText");
        var senderIceCandidates = JSON.parse(senderIceText.value);
        for (var i in senderIceCandidates) {
            var senderIceCandidate = new RTCIceCandidate(senderIceCandidates[i]);
            remotePeerConnection.addIceCandidate(senderIceCandidate);
        }
    }
  6. Da es sich um eine Peer-to-Peer-Verbindung (P2P) handelt, benötigt auch der Sender Verbindungsdaten (ICE), die der Empfänger nun generiert.
    1
    2
    3
    4
    5
    6
    7
    8
    
    function gotRemoteIceCandidate(event){
        if (event.candidate) {
            // console.log("gotRemoteIceCandidate candidate: " + event.candidate.candidate);
            var remoteIceText = document.getElementById("remoteIceText");
            remoteIceCandidates.push(event.candidate);
            remoteIceText.value = JSON.stringify(remoteIceCandidates);
        }
    }
  7. Jetzt müssen sowohl die Antwort und die Verbindungsdaten noch zurück zum Sender geschickt und dort dann verarbeitet werden, um eine Verbindung auszuhandeln. Um die Details kümmert sich WebRTC nun glücklicherweise selbständig.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    var handleAnswerButton = document.getElementById("handleAnswerButton");
    handleAnswerButton.onclick = handleAnswer;
     
    function handleAnswer() {
     
        var remoteDescriptionText = document.getElementById("remoteDescriptionText");
        var remoteDescription = new RTCSessionDescription({sdp: remoteDescriptionText.value, type: "answer"});
        senderPeerConnection.setRemoteDescription(remoteDescription);
     
        // list of candidates
        var remoteIceText = document.getElementById("remoteIceText");
        var remoteIceCandidates = JSON.parse(remoteIceText.value);
        for (var i in remoteIceCandidates) {
            var remoteICECandidate = new RTCIceCandidate(remoteIceCandidates[i]);
            senderPeerConnection.addIceCandidate(remoteICECandidate);
        }
     
    }

Und nun?

Klar, das hier ist nur eine Richtung und würde sich rein auf das Beobachten beschränken. Auch fehlen eine adäquate Software-Architektur sowie eine Fehlerbehandlung. Und der Austausch der Verbindungsdaten per „Copy and Paste“ ist vermutlich auch nur in wenigen Szenarien sinnvoll. Dennoch ist das ein guter Startpunkt, um Schritt-für-Schritt genau diese fehlenden Aspekte hinzuzufügen oder ggf. auf eine der zahlreichen Bibliotheken dafür zurückzugreifen – die beiden HTML-Dokumente für den Sender und den Empfänger finden sich dafür hier als möglichst einfach gehaltener Quellcode.