# Projekt: Med. Uni Graz: Livestreaming im Portal
> Dieses Dokument stellt die Grundlöage der Livestreaming-Erweiterungen von Opencast und des „Vital“-Videoportals dar. Anforderungen und die Art der Umsetzung können bei Bedarf agil angepasst werden.
## Livestreams
Für Raumintegration und der Transcodingserver sollen Livestreams zur Verfügung stellen. Diese sollen dann im Portal auf vital.medunigraz.at angezeigt werden.

### Darstellung
- Neue Kategorie „Live“ im Hauptmenü
- Listet alle Räume
- Streams können zusätzliche Metadaten haben:
- Veranstaltungsname
- Lehrender
- öffentlich/intern
- …
- In der Kategorie werden Räume gelistet:
- Räume haben einen Status (online, offline)
- Räume haben einen Namen
- Räume haben eine eindeutige ID
- Räume verlinken Raumseiten, wenn „online“
- Es können zusätzliche Metadaten eines aktiven Streams angezeigt werden
- Auf einer Raumseite wird dargestellt:
- Player mit Streams
- wenn online und Nutzer autorisiert
- „Sie müssen sich einloggen […]“
- wenn online aber Nutzer nicht autorisiert
- „Momentan kein Stream verfügbar“
- wenn kein Stream aktiv
- oder gar nicht betretbar
### Funktionsweise
- Opencast stellt einen Endpunkt `/vital-livestream` bereit
- Zum Starten/Beenden von Streams
- Akzeptiert Daten als JSON (siehe unten)
- Jeder Nutzer enthält eine eigene Stream-URL
- Für Statistik
- URL wird durch Opencast abgefragt
Neuer Stream:
- Externer Dienst meldet neuen Stream in Raum „A“
- Beinhaltet Veranstaltungsnamen
- Beinhaltet URL wo personalisierte Streams abgerufen werden können
Ablauf, wenn ein Nutzer die Seite aufruft:
- Nutzer betritt Sektion „Live“
- Portal fragt Opencast an
- Opencast liefert Liste aller Räume die der Nutzer sehen darf
- Opencast liefert deren Status
- Nutzer klickt auf Raum „A“ mit Status „online“
- Portal fragt Opencast nach Details zum Stream
- Opencast fragt externen Dienst nach personalisierten Stream URLs
- Opencast liefert URLs
- Portal rendered Player
### Konfigurationsmöglichkeit
- Es muss eine Liste von Räumen festgelegt werden
- Konfiguration in Opencast
- Daten
- Identifier
- Name
- Eventuell kann die Konfiguration von einem externem Dienst abgefragt werden
- URL für die Abfrage in Opencast konfigurieren
- Beispiel für hinterlegte Daten:
```json
[{
"name": "Reithalle",
"identifier": "69/E09"
}, {
"name": "Auditorium",
"identifier": "42/105"
}]
```
### Schnittstelle
- `GET /vital-livestream/` liefert Raumliste
- `GET /vital-livestream/<room-id>` liefert Raumdetails
- Fragt jeweils nach personalisierten Stream URLs wenn online
- `PUT /vital-livestream/<room-id>` aktualisiert den Raum
- Um neue Streams zu starten
- Beispieldaten:
```json
{
"metadata": {
"name": "<string>",
"presenter": "<string> (optional)"
},
"preview": [{
"type": "<type of preview image: search or player>",
"url": "<url of preview image>"
}],
"stream": [{
"url": "<url to retrieve stream url from>",
"type": "<string e.g. presentation>"
}],
"room": {
"id": "<room-id>",
"status": "(online|offline)"
}
}
```
### Schnittstelle by MedGraz
#### Starten eines Events
`PUT /<path/to/opencast/ HTTP/1.1`
Host: vital.medunigraz.at
Content-Type: application/json
```json
{
"viewer": "https://api.medunigraz.at/video/live/<eventid>/",
"channel": {
"id": "<channelid>",
"name": "Hörsaal 1 MC"
},
"event": {
"id": "<eventid>",
"title": "lorem ipsum",
"description": "Lorem <strong>ipsum dolor</strong> sit amet, <a href=\"https://www.medunigraz.at/\">consetetur</a> sadipscing elitr, ...",
"public": true
},
"previews": {
"presenter": [
"https://1.asd.medunigraz.at/livestream/<eventid>/<stream1id>.jpg",
"https://2.asd.medunigraz.at/livestream/<eventid>/<stream1id>.jpg"
],
"slides": [
"https://1.asd.medunigraz.at/livestream/<eventid>/<stream1id>.jpg",
"https://2.asd.medunigraz.at/livestream/<eventid>/<stream1id>.jpg"
]
}
}
```
#### Legende
| | |
|---|----|
|.viewer: | Die URL bei der ihr mit einem PUT einen neuen Viewer erzeugen könnt, siehe weiter unten.
|.channel.id: | Die ID des Channels in dem der Event angezeigt werden soll. Die Channels (früher Räume) bekommt ihr dann noch an einem eigneen RESTful-Endpoint
|.channel.name: | Der Name des Channels, sollte aber schon bekannt sein von der Liste der Channels
|.event.id: | Die ID des gerade gestarteten Events, dient für euch als Referenz.
|.event.title: | Titel des Events
|.event.description: | Teaser/Zusatztext zum Event, kann HTML enthalten
|.event.public: | Boolean, der anzeigt, ob public oder private
|.previews: | Ein Dictionary aus verschiedenen Streams (meist wohl "presenter" und "slides")
|.previews.<stream>: | Eine Liste von URLs zu den Vorschaubildern für den Stream. Davon sollte eine URL zufällig ausgewählt werden. Beide URLS sollten das selbe Bild liefern. Das Bild wird derzeit alle 10 Sekunden neu erzeugt und der Cache-Control-Header refkeltiert das auch.
#### Stoppen eines Streams
`DELETE /<path/to/opencast/ HTTP/1.1`
Host: vital.medunigraz.at
Content-Type: application/json
```json
{
"event": {
"id": "<eventid>"
}
}
```
#### Legende
| | |
|---|----|
|.event.id: | Die ID des Events der gestoppt werden soll.
#### Erzeugen eines Viewers
Ein Viewer ist ein Zuseher, der einen Event mit seinen Streams ansehen will. Dazu bekommt jeder Viewer eine UUID, die in die URL der Streams eingebettet ist.
`PUT /video/live/viewer/<eventid>/`
Host: api.medunigraz.at
Darauf bekommt ihr als Response (404 wenn der Event nicht aktiv ist):
HTTP/1.1 200 OK
Content-Type: application/json
```json
{
"viewer": "<viewerid>",
"streams": {
"presenter": "https://2.asd.medunigraz.at/livestreams/<eventid>/<stream1id>/<viewerid>.m3u8",
"slides": "https://2.asd.medunigraz.at/livestreams/<eventid>/<stream2id>/<viewerid>.m3u8"
}
}
```
#### Legende
| | |
|---|----|
|.viewer: | Die ID, die dem Viewer zugeweisen wurde, ist auch in den Stream-URLs eingebettet.
|.streams: | Ein Dictionary aus verschiedenen Streams (meist wohl "presenter" und "slides")
|.streams.<stream>: | Die URL zur Master-Playlist für den HLS-Stream.
### TODO
- Opencast Service (~24h)
- Datenspeicherung
- Schnittstellen
- Streams abfragen
- Vital-Frontend (~40h)
- Neue Sektion
- Plugin
- Kommunikation mit Opencast
- Player (~8h)
- Player mit Streams füttern
## Chat
Bei Livestreams auf vital.medunigraz.at soll es die Möglichkeit geben per Chat live zu kommunizieren. In der ersten Iteration soll dies möglichst simpel gehalten werden. Spätere Erweiterungen sind möglich.

### Darstellung
- Nur angemeldete Nutzer sehen den Chat
- In jedem Live-Raum des Portals soll es einen Chat geben
- Der Chat ist nur für angemeldete Nutzer
- Chat-Nachrichten werden mit dem Login versehen
- Chat-Nachrichten sind Plaintext
- Der Chat-Inhalt kann als Textdokument heruntergeladen werden
## Funktionsweise
- Opencast-Modul mit:
- REST API
- Datenbank-Backend oder In-Memory?
- UI
- Das Livestream-Modul kontrolliert die Gültigkeit von Chats
- Chat wird angelegt, wenn Raum online geht
- Chat-Link wird gespeichert
- Chat wird gelöscht, wenn Raum offline geht
- Nachrichten werden bei Opencast verworfen
- Es können keine neuen Nachrichten gesendet werden
- Nachrichten verbleiben in der UI bis der Nutzer die Seite verlässt
### API
- `POST /` legt einen neuen Chatraum an
- `GET /` listet vorhandene Chats
- `DELETE /<id>` löscht einen Chatraum
- `GET /<id>` liefert JSON mit allen Nachrichten
- `POST /<id>` nimmt eine neue Nachricht an
### TODO
- Chat-Service (~28h)
- Datenspeicherung
- REST API
- Java API
- Anpassung Live-Service (~8h)
- Chats starten/stoppen
- Chat speichern
- Daten an Vital weitergeben
- Chat-UI (~20h)
- Mit API sprechen
- Daten renderen
- Downloadfunktion
- Anpassung an Vital (~4h)
- Einbindung der Chat-UI