!!! Installation

!! Alles auf einem Server

Anleitung: [https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md]

!! Cluster

Anleitung: [https://github.com/jitsi/jitsi-meet/blob/master/doc/scalable-installation.md]

Nach Videobridge-Installation auf jeden Fall Passwort in {{{/etc/jitsi/videobridge/config}}} und {{{/etc/jitsi/jicofo/sip-communicator.properties}}} mit prosody-server abgleichen.Falls Login fehlschlägt, mit {{{prosodyctl}}} zurücksetzen.

Bei Fehler "Could not build trust path": {{{auth.meet.example.org.crt}}} in jeder videobridge in ca-certificates aufnehmen

Weitere Doku: [https://www.slideshare.net/AnnikaWickert/freifunk-munich-how-to-scale-jitsi-231999167]

! Skalierungsinfos

vom Freifunk München: 20 Server für 10000 User, We can run 280 people without issue with ressources compareable with AWS c5.2xlarge. ([https://twitter.com/i/status/1253353265158332416])

vom den Matrix-Machern: Roughly speaking we're seeing Jitsi serve around 1000 concurrent streams (i.e. 25x 50-user conferences) on a typical 4 core box with 8GB of RAM. However, it's worth noting that Jitsi is pretty low resource - all it's doing is forwarding streams of data around the place. All the heavy lifting is done by the clients when displaying all the concurrent videos, so it's the clients which tend to be the bottleneck. ([https://news.ycombinator.com/item?id=22804401])

Eigene Tests:

* 4 User: 25% CPU-Auslastung für CCX21
* 4 User: 10% CPU-Auslastung für L-16 HDD
* 12 User: 26% CPU-Auslasting für L-16 HDD, 30 MBit/s eingehend, 25 MBit/s ausgehend

!!! Anpassung

Jitsi per User/Passwort schützen, wenn nicht jeder eine Konferenz starten soll: [https://github.com/jitsi/jicofo#secure-domain]

Um ein Impressum, Datenschutz etc auf Startseite einzufügen:

Dateien von {{{/usr/share/jitsi-meet}}} nicht editieren, sondern nach {{{/etc/jitsi/meet}}} kopieren, dort anpassen und via Webserver-Regeln ausliefern.

Als Beispiel:

/etc/jitsi/meet/static/welcomePageAdditionalContent.html
{{{
<template id = "welcome-page-additional-content-template">
	<div class="welcome-page-content">
        	<div class="welcome-footer">
            		<div class="welcome-footer-content">
                		<div class="welcome-footer-about">
					<div>
						<a href="https://jitsi.org/jitsi-meet/" rel="noopener" target="_blank">Powered by Jitsi Meet</a> | <a href="https://example.org/imprint" rel="noopener" target="_blank">Impressum</a> | <a href="https://example.org/privacy" rel="noopener" target="_blank">Datenschutz</a>
					</div>
				</div>
	    		</div>
		</div>
	</div>
</template>
}}}

/etc/jitsi/meet/plugin.head.html:
{{{
<style>
    .welcome-page-content {
        display: flex;
        flex-direction: column;
        flex-grow: 1;
        justify-content: space-between;
        position: relative;
        z-index: 1;
        margin-top: 35px;
        width: 100%
    }
    .welcome-page-content .welcome-footer {
        color: #FFF;
        display: flex;
        padding-bottom: 20px;
        padding-top: 20px;
        width: 100%;
        z-index: 1
    }
    .welcome-page-content .welcome-footer-content a {
        color: #fff !important;
        text-decoration: underline
    }

    .welcome-page-content .welcome-footer-content {
        display: flex;
        justify-content: center;
        width: 100%;
        z-index: 2
    }

    .welcome-page-content .welcome-footer-about {
        display: flex;
        flex-direction: column;
        flex: 1;
        font-size: 14px;
        line-height: 20px;
        text-align: center;
        justify-content: center
    }

    .welcome-page-content .welcome-footer-about:last-child {
        margin-left: 4px
    }
</style>
}}}

Ausschnitt aus apache-vhost-config:
{{{  
  Alias "/static/welcomePageAdditionalContent.html" "/etc/jitsi/meet/static/welcomePageAdditionalContent.html"
  <Location /static/welcomePageAdditionalContent.html>
    Require all granted
  </Location>

  Alias "/plugin.head.html" "/etc/jitsi/meet/plugin.head.html"
  <Location /plugin.head.html>
    Require all granted
  </Location>
}}}

Wenn die Datei {{{/usr/share/jitsi-meet/interface_config.js}}} angepasst werden soll, ebenfalls mit Kopie unter {{{/etc/jitsi/meet}}} arbeiten.

Außerdem sind folgende Anpassungen in der {{{/etc/jitsi/meet/meet.example.org-config.js}}} empfohlen:

{{{
/// Nur letzte 6 Sprecher als Video anzeigen, schont CPU auf Clients und Bandbreite
channelLastN: 6,

/// Sprecherdetektion aus Clientseite deaktivieren, schont CPU auf Clients
disableAudioLevels: true,

defaultLanguage: 'de',
    
/// Schaltet Gravatar und STUN ab
disableThirdPartyRequests: true,

/// Auf eigene Hilfe-/Impressumsseite und Desktop-Apps während Call im Menü hinweisen
deploymentUrls: {
//    // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for
//    // user documentation.
    userDocumentationURL: 'https://example.org/jitsi',
//    // If specified a 'Download our apps' button will be displayed in the overflow menu with a link
//    // to the specified URL for an app download page.
    downloadAppsUrl: 'https://github.com/jitsi/jitsi-meet-electron'
},
}}}

!!! Telefoneinwahl

Setup: Sipgate Basic, Asterisk, Jigasi, ConferenceMapper

Schematischer Ablauf: Eine Jitsi-Konferenz wird per Browser aufgemacht. Dabei ruft der Webclient den ConferenceMapper auf und dieser liefert eine 6-stellige Nummer zum Raumnamen. Diese wird dann auch im Jitsi-Info-Dialog nach der Einwahlnummer angezeigt. Ein weiterer Teilnehmer ruft die Sipgate-Basic-Numme an. Der Anruf kommt bei Asterisk an. Asterisk nimmt den Anruf entgegen und fragt per DTMF die "Konferenz-PIN" ab, schlägt den Raumnamen im ConferenceMapper nach, fügt dann den SIP-Header Jitsi-Conference-Room: mit dem Raumnamen hinzu und ruft bei der Jigasi-Gegenstelle an. Wenn Jigasi den Anruf entgegennimmt, stellt Asterisk die VoIP-RTP-Sprachverbindung direkt zwischen Sipgate und Jigasi her. Jigasi selbst nimmt erfährt dann via XMPP die Videobridge-Details und stellt seinerseits eine Verbindung zur Videobridge her, über die dann die Audiokommunikation läuft.

Zusammengefasst: Asterisk und der ConferenceMapper übernehmen nur Signaling-Funktionen und sind an der eigentlichen Sprachverbindung nicht beteiligt, Jigasi ist als "RTP <-> WebRTC-Proxy" Teil der Audiokette.

Die Anleitung basiert auf [https://doku.jgz-energie.net/jitsi-meet/#telefoneinwahl] und dem "Hello World"-Kapitel des deutschen Askterisk-Buchs [http://das-asterisk-buch.de/1.6/installation-einleitung.html]

!! Setup Asterisk

Ubuntu Server 20.04, Asterisk installieren, default-Konfiguration löschen

{{{
apt install asterisk
rm /etc/asterisk/sip.conf
rm /etc/asterisk/extensions*
}}}

/etc/asterisk/sip.conf, aaaa ist Sipgate User, bbbb Sipgate Passwort, cccc ist Jigasi-SIP-Passwort, d.d.d.d ist die öffentliche IP-Adresse des Jigasi-Servers.
{{{
[general] 
port=5060 
bindaddr=0.0.0.0
language=de
deny=0.0.0.0/0.0.0.0
permit=d.d.d.d/255.255.255.255
allowguest=no

register => aaaa:bbbb@sipgate.de/aaaa

[ext-sip-account]
type=friend
context=von-voip-provider
username=aaaa
fromuser=aaaa
secret=bbbb
host=sipgate.de
fromdomain=sipgate.de
qualify=yes
insecure=port,invite
nat=yes
disallow=all
allow=alaw

[2000]
type=friend
context=meine-telefone
secret=cccc
host=dynamic
disallow=all
allow=alaw
}}}

extensions.conf, aaaa ist Sipgate User, https://e.e.e/conferenceMapper ist die Adresse des ConferenceMappers (siehe unten)
{{{
[default]

[von-voip-provider]
exten => aaaa,1,Answer()
same => n,Read(confid,conf-getpin&astcc-followed-by-pound)
same => n,Set(CURL_RESULT=${SHELL(curl --silent https://e.e.e/conferenceMapper?id=${confid} | sed -e 's/.*"conference":"\(.*\)@.*/\1/')})
same => n,Verbose(0, ${CURL_RESULT});
same => n,SIPAddHeader(Jitsi-Conference-Room:${CURL_RESULT})
same => n,Set(CDR(userfield)=Jitsi:${CURL_RESULT})
same => n,Dial(SIP/2000,3)
same => n,Verbose(0, Contacting Jigasi... Status is ${DIALSTATUS} );
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?conf-busy)
same => n,GotoIf($["${DIALSTATUS}" = "CANCEL"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "DONTCALL"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "TORTURE"]?unknown)
same => n,GotoIf($["${DIALSTATUS}" = "INVALIDARGS"]?unknown)
same => n,Hangup()
same => n(conf-busy),Playback(confbridge-begin-leader)
same => n,Dial(SIP/2000,120)
}}}

!! Setup Jigasi

Jigasi installieren

{{{
apt install jigasi
}}}

Bei der Installation wird nach Jigasi-SIP-User und Passwort gefragt. 

Jigasi-SIP-User ist 2000@<IP-Asterisk>
Jigasi-Passwort cccc aus Asterisk-Konfiguration oben

In der Jigasi-Konfiguration {{{/etc/jitsi/jigasi/sip-communicator.properties}}} auf jeden Fall das Packet-Logging deaktivieren:

{{{
net.java.sip.communicator.packetlogging.PACKET_LOGGING_ENABLED=false
}}}

Die Standard-Konfiguration von Jigasi geht davon aus, dass der Jitsi-Prosody auf dem selben Host installiert ist. Wenn das Im Cluster-Setup nicht so ist, dann:
in {{{/etc/jitsi/jigasi/config}}} JIGASI_HOSTNAME und JIGASI_HOST auf den Prosody-Host setzen. In {{{/etc/jitsi/jigasi/sip-communicator.properties}}} die org.jitsi.jigasi.xmpp.acc.SERVER_ADDRESS auf den Prosody-Host setzen.

!! Setup ConferenceMapper

ConferenceMapper von https://github.com/luki-ev/conferencemapper installieren und konfigurieren.

Die resultierende URL dann noch in der Asterisk-Konfiguration /etc/asterisk/extentions.conf hinterlegen.

Eine statische Datei mit den Einwahlnummern unter https://meet.example.com/numbers.json via nginx verfügbar machen:

{{{
location = /numbers.json {
        alias /etc/jitsi/meet/numbers.json;
}
}}}

Inhalt von /etc/jitsi/meet/numbers.json, FFFF/FFFF durch Sipgate Basic-Festnetznummer ersetzen:
{{{
{"message":"Einwahlnummbern","numbers":{"DE":["FFFF/FFFF"]},"numbersEnabled":true}
}}}

!! Setup Jitsi-Meet

Audio-Konfiguration in Jitsi-Meet config.js aktivieren:

{{{
    dialInNumbersUrl: 'https://meet.example.org/numbers.json',
    dialInConfCodeUrl: 'https://meet.example.org/conferenceMapper',
}}}