summaryrefslogtreecommitdiff
path: root/projekt_doku.asciidoc
blob: 9c26a377cd5b3df25319ec12a33457b3ed210554 (plain)
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
Philips TV-Remote unter Linux
=============================
:author: Benjamin Franzke
:lang: de
:imagesdir: image
// a2x: --dblatex-opts="-p thesis.xsl -s thesis.sty -b xetex"

[abstract]
== Aufgabe
Ziel dieses Forschungsprojektes ist die Programmtechnische Umsetzung
der Nutzung der Philips TV-Firmware als Netzwerkbasierter-Infoscreen.
Als Plattform wird dabei GNU/Linux verwendet.
Es werden im weiteren Lösungsmöglichkeiten für die Probleme der aktuellen
Konfiguration mit dem Windows Client Pluggit evaluiert.

== Grundlagen

*DirectFB*

'DirectFB' ist eine Bibliothek, die als Hauptaufgabe Beschleunigung durch
Grafik-Hardware bereitstellt. 
Außerdem werden auch Eingabegeräte unterstützt, und es enthält ein
integriertes Fenster-System.
Auf Grund der genannten Eigenschaften kann DirectFB als
Hardwareabstraktionsschicht bezeichnet werden.

*DirectFB Voodoo*

'DirectFB Voodoo' ist ein Aufsatz bzw Proxy-Kanal für DirectFB.
Es besteht aus einer Client-Server Architektur.
Der Server ist dabei das Anzeige Gerät und bietet über den Voodoo Kanal
Zugriff auf den eigenen Framebuffer.

Die clientseitige Implementierung leitet 'DirectFB'-API-Aufrufe per 
'DirectFB-Voodoo' an den Server weiter, auf dem diese dann ausgeführt werden.

'DirectFB-Voodoo' ist demzufolge eine Remote-Rendering Infrastruktur
die das Zeichnen von Primitiven wie Rechtecken und Kreisen ermöglicht,
aber auch das übertragen von ganzen Bildinhalten.

*JointSpace* 
'JointSpace' ist ein Framework und API für Fernseher von Philips.
Es ermöglicht das Fernseher über das API gesteuert werden können,
und eine Bildübertragung per Netzwerkverbindung.
Das API zur Steuerung der Fernseher basiert auf einem REST-Full
HTTP-Protokoll.
Für die Bildübertragung wird 'DirectFB Voodoo' eingesetzt.

== Ist-Zustand

Verwendet werden Fernseher der 7000er Serie von Philips, auf die eine,
direkt vom Hersteller überarbeitete Firmware geladen wird. Diese beinhaltet die
'JointSpace' Erweiterung.

Als Datenquelle dient eine Windows-Installation in einer virtuellen Maschinen,
welche das ebenfalls vom 'JointSpace' bereitgestellte Programm 'Pluggit'
verwendet.

Die einzelnen Fernseher sind alle in eigenen Netzen, da zum Verbindungsaufbau
ein Netzwerk-Broadcast genutzt wird und sich so die Fernseher gegenseitig
stören würden, wenn sie Teil ein und der selben Netzwerk-Broadcast-Domain
wären.

Der Firefox-Browser wird mit Hilfe seines Vollbildmodus' für die Darstellung
eingesetzt, da er unter Windows einer der stabilsten und ausgetestetsten,
standardkonformen Browser ist.

Die Fernseher bieten eine native Auflösung von +1920x1080+ Pixeln,
die Remote-Anzeige funktioniert aber nur bis zur Auflösung von +1280x720+
Pixeln.

== Problemlösung & Implementation

Im ersten Schritt ist eine eins-zu-eins Umsetzung der Anzeige eines
Linux-Screens auf einen Fernseher zu implementieren.
Im zweiten sollen von einem Rechner mehrere Streams an verschiedene 
JointSpace-Fernseher gesandt werden.  In diesem Fall 3 Clients.

Das in Abbildung 1 aufgezeigte Schema verdeutlich die Server-Client
Architektur von 'DirectFB-Voodoo'. Dabei wird deutlich, dass 'Pluggit' die
Bildschirmdaten vom Xorg-Server ausliest und per Netzwerk an den Fernseher
überträgt. Der Fernseher besitzt

.Client-Server Interaktion
image::directfb-voodoo-js.eps[]

=== Pluggit

Als Basis für die Programmtechnische Umsetzung dient der Bestehende
Windows-Client Pluggit, sodass die bereits ausgetestete Remote-Rendering
Infrastruktur wiederverwendet werden kann.

Pluggit wurde so verändert, dass das X11-Protokoll anstatt der WinAPI verwendet
wird, um den Inhalt eines Fensters oder auch des ganzen Framebuffers anzuzeigen.

Dazu ist eine 'SourceX11' Klasse notwendig, die das in Pluggit enthaltene
Interface 'Source' implementiert, und somit als Datenlieferer agiert. 

// TODO: Graph?

==== Verbindungsaufbau

Die DirectFB-Voodoo Plattform nutzt als Standardmethode zum Verbindungsaufbau
einen Broadcast Request, um verfügbare Anzeigegeräte zu finden.
Dies ist für den Einsatz im Heimnetzwerk gedacht, bei dem der
Verbindungsaufwand möglichst gering gehalten werden soll.
Sind mehrere der Fernseher in einer Broadcast-Domain, so ist nicht eindeutig
definiert, welcher zuerst auf den Broadcast antwortet, und dadurch für die
Verbindung ausgewählt werden wird. 
Aus diesem Grund ist eine ausschließliche Unicast-Verbindung nötig.

Die Bibliothek bietet kein direktes API, um die Ziel-Adresse zu verarbeiten.
Die Initialisierungsmethode +DirectFB::Init()+ erwartet aber einen
Argumentenzähler und -vektor.
Dieser Vektor bezieht sich auf die Kommandozeilen Argumente, im folgenden
C-Code ist dies Beispielhaft dargestellt:

[source,c]
----
#include <directfb.h>

int
main(int argc, char *argv[])
{
	DirectFB::Init(&argc, &argv);
	return 0;
}
----

+DirectFB::Init()+ würde nun Kommandozeilen parameter beginnend mit +--dfb:+
auswerten. In diesem Fall würde +--dfb:remote=ip.address+ übergeben werden,
und somit implizit, das Voodoo-Discovery (Broadcast) ausgelassen,
und anstatt dessen direkt zur IP verbunden.

==== Verbindungsabbruch
Bricht die Verbindung ab -- z.B. durch Ausschalten des Fernsehers oder durch
Auswählen einer anderen Quelle -- wird dies durch die DirectFB Bibliothek
nicht an die Anwendung signalisiert.

Im produktiven Einsatz ist es bei Remote-Steuerung deshalb nicht zu erkennen,
ob die Verbindung noch besteht. Außerdem ist auch keine automatisierte
Neuverbindung möglich.

//die Anwendung signalisiert.
//Intern wird der Rückgabewert von +send(2)+ nicht auf einen Verbindungsabbruch
//geprüft.

*Lösung:*

Die Bibliothek DirectFB wurde erweitert, das SIGPIPE Signal vom Kernel zu
empfangen. Pluggit installiert für DirectFB eine Signal Behandlungsroutine
und bricht die Programmausführung ab.
Ein Shell-Script das 'Pluggit' überwacht, erkennt dies am Rückgabe-Status des
Pluggit-Prozesses und startet diesen neu.

//TODO: Add shell script here


=== Framebuffer Größenlimit
Bei der Verwendung von 'Pluggit' unter Windows besteht das Problem, dass eine
maximale Auflösung von +1280x720+ Pixeln genutzt werden kann.
Dieses Limit ist kein Fehler im Programm oder eine Einschränkung des
Betriebssystems, sondern das API erlaubt keine größere Auflösung.
Bei Verwendung von z.B. einer +1920x1080+ Auflösung -- bei einem Fernseher,
der diese Auflösung per HDMI unterstützt -- signalisiert das API
einen Fehler, dass ein invalides Argument übergeben wurde.

Diese Limitierung ist also nicht zu beheben und muss als gegeben hingenommen
werden.

=== Framebuffer Auslesen
Das X11-Protokoll bietet die Möglichkeit den angezeigten Framebuffer
über die Funktion +XGetSubImage(3)+ auszulesen.

Darüber hinaus gibt es eine Anbindung an +shmget(2)+, sodass Unix
Shared-Memory verwendet werden kann.
Dies bietet den Vorteil, dass die Framebuffer-Daten nicht über den
X11-Protokoll-Socket übertragen werden müssen -- wie bei +XGetSubImage+,
sondern direkt gelesen werden können.
Es wird ein X11-Pixmap erzeugt, welchem ein XImage auf Shared-Memory Basis
zugrunde liegt.
Zum Auslesen wird nun +XCopyArea(3)+ mit dem X11-Pixmap als Argument
ausgeführt. Der X-Server schreibt in der Folge den angefragten Bildinhalt
in den Shared-Memory, 

=== Multiple Streams

Teil der Anforderung ist, mehrere Fernseher gleichzeitig mit unterschiedlichen
Bildern zu beliefern.
Dazu ist es notwendig Bilddaten aus mehreren Browser-Fenstern auszulesen.

Theoretisch sind mehrere Methoden denkbar:
Es könnten mehrere X-Server gestartet und pro X-Server immer ein
Browser im Vollbild-Modus angezeigt werden.
Weiterhin könnten auf einem X-Server die Browser auf Virtuelle Desktops
verteilt werden.
Diese Methoden scheitern am Damage-Handling, das bewirkt, dass nicht sichtbare
Teile eines Fensters nicht (neu)gezeichnet werden.

Eine weitere Möglichkeit wäre OffScreen-Rendering.
Dies muss aber direkt von Browsern unterstützt werden, wofur keine
Unterstützung festgestellt werden konnte.

Deshalb wird um mehrere Fenster darzustellen, ein großer Anzeigebereich
benötigt, auf dem alle Fenster gleichzeitig Platz finden.
Mit dem X11 'XRandR'-Protokoll ist die möglich und wird durch folgenden Aufruf
erreicht:

[source,sh]
----
xrandr --fb $((1280*3+10))x768 # <1>
----
<1> Es werden 10 hinzuaddiert, damit Platz für Fensterrahmen bleibt.

In Abbildung 2 ist eine Beispiel-Konfiguration für 3 Multiple Streams aufgeführt.

.Multiple Browser-Fenster 
image::framebuffer.svg[]

=== Browser

Die Anzeige des Infoscreens erfolgt über eine HTML-Website, die auch
Multimediainhalte enthält.
Aus diesem Grund ist es nötig, dass das HTML von einem Web-Browser gerendert
wird.

In Betracht kommt auf Grund der Bekanntheit und Stabilität der
Firefox-Browser.
Dieser kann allerdings nur im Vollbild-Modus so konfiguriert werden, dass nur
der Inhalt im X11-Fenster -- welches ausgelesen werden soll -- angezeigt wird,
Menus und Scrollbars sind im normalen Floating-Modus immer vorhanden.
Ein weiteres Problem stellt die eindeutige Adressierung der WindowID, bei
Verwendung mehrerer Firefox-Fenster.
Es gibt keine direkte Möglichkeit die WindowID zu erhalten, nur über Matching
des Titels des Firefox-Fensters.
Die Verwendung für mehrere Infoscreens würde es aber nötig machen den Titel
des angezeigten Inhalts zu wissen, und in der Programmlogik zu
berücksichtigen.  Eine Veränderung des Inhalts würde damit auch eine Anpassung
des Programms erfordern. Dies ist nicht wünschenswert.

Deshalb wird ein Web-Browser benötigt, der es ermöglicht nur den Inhalt der
Website im X11-Fenster darzustellen.
Der Browser 'surf' footnote:[http://surf.suckless.org] von 'suckless.org' ist
mit dem Prinzip erstellt worden, in andere Programme über das X11-XEmbed
Protokoll eingebettet zu werden, z.B. um mehrere Instanzen in einem
Tab-Manager zu einzubetten.

Dies ermöglicht per Design zwei Vorteile:

 - Die WindowID von 'surf' wird auf +stdout+ ausgegeben. +
   (Kann demzufolge einfach als Parameter an Pluggit übergeben werden.)
 - Keine Bedienelemente vorhanden, denn der Browser wird über X11-Properties
   gesteuert -- das erlaubt Scripting.

Im weiteren setzt 'surf' auf WebKit/GTK footnote:[http://webkitgtk.org/], und
besitzt somit, genauso wie Firefox, auch ein standardkonformes und
ausgetestetes Framework.

== Test

Getestet wurde jeweils mit der Infoscreen-Website
footnote:[http://et.hs-wismar.de/~infosc/index.php?file=config16n]
des Fachbereichs EuI:

Da während der Entwicklung nicht dauerhaft Philips-Fernseher zur Verfügung
standen, wurde der durch das 'JointSpace'-Projekt als VMWare-Virtuelle
Maschine bereitgestellte Simulator mit QEMU verwendet:

[source,sh]
----
qemu-system-x86_64 -enable-kvm -m 256 -hda jointspace.vmdk \
	-net nic -net tap,ifname=tap0,script=no,downscript=no
----

Das Anzeigen des Browser-Inhaltes und die korrekte Wiedergabe des Videos
entscheiden über das Bestehen des Tests.

== HowTo

Ein auf GNU/Linux basierendes Betriebssystem ist Vorraussetzung für die
Einrichtung des Clients. Ein minimales System wie Gentoo Linux oder Arch Linux
eignet sich auf Grund der Konfigurierbarkeit bezüglich erwünschter Packete
sehr gut.

=== System Vorraussetzungen

Das System muss einen Xorg-Server mit Xrandr 1.3 Unterstützung besitzen und
die dazugehörige 'libX11'.
Das Utility wmctrl wird zur Positionierung und Größenfestlegung der Browser
genutzt. Der Browser selbst ist 'surf'.

Die daraus resultierende Installationsroutine, beispielhaft für Gentoo Linux:

[source,sh]
----
emerge -va xorg-server libX11 xrandr wmctrl surf
----

=== DirectFB

Für diese Arbeit wurde die, zum Zeitpunkt der Bearbeitung, neueste Version von
'DirectFB' verwendet:
DirectFB141_source_1.3.1beta5.7z
footnote:[http://sourceforge.net/projects/jointspace/files/remote_applications_SDK/]

[source,sh]
----
7z x DirectFB141_source_1.3.1beta5.7z
----

Diese sollte aber nur zum Vergleich herbei gezogen werden, denn die Sourcen,
inklusive benötigter Patches (mit GIT-History), sind bereits im
beiliegenden Dokumentationsverzeichnis enthalten.

Bei späteren Updates auf neue DirectFB Versionen sollten die Patches aus dem
GIT-Repository neu eingespielt werden.

=== Pluggit

Dieser Abschnitt beschreibt die eigentliche Kompilierung der Toolchain.
Das Dokumentationsverzeichnis enthält ein Makefile, welches ein pluggit target
bereitstellt.
Dies leitet die Kompilierung von 'DirectFB' ein und führt danach die
Übersetzunbg von 'pluggit' selbst aus.


[source,make]
-------------------------------------------------------------------------
.PHONY: pluggit
pluggit:
	rm -f pluggit/pluggit # <1>
	$(MAKE) -C directfb-voodoo/ -f makefile.voodoo DEBUG=$(DEBUG) package # <2>
	$(MAKE) -C pluggit/ -f makefile.voodoo DIRECTFB_VOODOO=../directfb-voodoo/DirectFB_Voodoo all
-------------------------------------------------------------------------

<1> In der Entwicklungsphase ist es notwendig, dass pluggit neu gelinkt wird,
wenn DirectFB verändert wird.
<2> Das DirectFB-Packet baut die Bibliothek und kopiert Header an die
benötigten Stellen.

Für die Übersetzung von DirectFB und Pluggit muss also außschließlich
folgender Befehl im Quellverzeichnis des Projekts ausgeführt werden:

[source,sh]
------------
make pluggit
------------

== Bewertung & Ausblick

Die Performanz ist durch das ständige Übertragen kompletter Bilder
beschränkt auf die Übertragungsbandbreite des Kanals.
Zur Optimierung könnte ein direktes Remote-Rendering des WebBrowsers, bzw
dessen Backends, verwendet werden.
Ein weiterführender Ansatz wäre es deshalb, das, sich in Entwicklung befindende
-- und deshalb zum Zeitpunkt dieser Arbeit noch nicht verwendbare --
WebKit-DirectFB footnote:[http://git.directfb.org/?p=libs/WebKitDFB.git;a=summary]
backend zu diesem Zweck zu nutzen.

Eine weitere Alternative wäre die Implementation eines Wayland-Compositors
footnote:[http://wayland.freedesktop.org/],
der direkt und ausschließlich die Framebuffer Daten per DirectFB-Voodoo
überträgt.
Auf diese Weise wäre ein Offscreen-Rendering möglich, und die Workarounds
bezüglich nebeneinander Positionierung mehrerer Browser-Fenster und eine
vergrößerte Arbeitsfläche wären nicht notwendig.

Das Übertragen der Framebuffer-Daten, aber auch der Rendering-Direktiven wird
stets eine Höhere Datenrate aufweisen, als die HTML Daten (+embedded Video) zu
übertragen. Diese werden zwar nicht direkt von Fernsehern der Philips 7000er Generation
angezeigt. Ein alternativer Ansatz wäre aber das Verwenden von Mini-Computern,
z.B. Thin-Clients, die einen Web-Browser besitzen und die Anzeige mittels VGA
oder HDMI an den Fernseher übertragen.

// vim: set syntax=asciidoc tw=78 filetype=asciidoc:
// spell spelllang=de,en: