Twinkle, Twinkle little PVA …

„Boar, wie geil..“ war das Echo, als meine neueste Erweiterung für Carola im Familienkreis vorgestellt habe, also sollt auch Ihr daran teilhaben 🙂

Twinkle, Twinkle little PVA …

Bislang kam bei Carola, unserem Lieblings-Personal-Voice-Assistant, Jitsi beim Telefonieren zum Einsatz, weil es das brauchbarste SIP Programm war. Das hat sich radikal geändert, als Twinkle auf der Bildfläche erschien.

Die Oberfläche von Twinkle, daß mit zwei Leitungen auch mal eine Dreierkonferenz makeln kann, ist eher ernüchtern:

Main-UI von Twinkle.

Da Twinkle im Livebetrieb diese UI nicht offen haben muß, kann man das verschmerzen. Die UI von Jitsi ist klein, schön und kompakt, so wie man das von klassischen InstantMessangern erwartet. Bei Twinkle geht es aber hauptsächlich um SIP, über das man auch Nachrichten schicken kann, und cooles Aussehen nicht so wichtig 😉

Der schwierigste Teil von Twinkle ist seine Konfiguration, aber nur, wenn man den SIP-Providernamen falsch angibt. Merkt Euch mal: IMMER den Domainnamen angeben, also sipgate.de, fritz.box usw. NIE die IP!

Ok, jetzt haben wir ein funktionierendes SIP-Programm, was das mit Carola zu tun hat, dürfte Euch natürlich klar sein, man kann damit jemanden Anrufen. Das war natürlich der erste Test, also sagen wir Carola, wir wollen mit X sprechen, Carola sucht die Nummer raus, teilt das Twinkle mit und das ruft dann die Nummer an. Soweit hatten wir das schon mit Jitsi, wenn Ihr Euch erinnern mögt, steht auch so in der Default Config vom PVA drin.

Eigentlich nicht weiter spannend, dann können wir jetzt aufhören… Sekunde mal, das Telefon klingelt.

„Carola am Apparat“
„Wie war Ihr Name?“
„Müßten Sie das nicht wissen, Sie haben doch mich angerufen“
„ich will mit meiner Tochter sprechen“
„geht nicht, ist nicht da.“
„können sie ihr sagen, das ich angerufen habe“
„nein, kann ich sonstwie helfen?“

Wäre die Google Stimme noch etwas besser, wäre das Gespräch oben geeignet gewesen, einen Menschen zu täuschen. So aber ist es nur unsere neueste Errungenschaft: Carola nimmt aktiv das Telefonat an und spricht mit den Anrufenden \o/

Die für das Gespräch nötige Config sieht so aus:

reaction:“wie war ihr name“,““,“Mein Name ist %KEYWORD“
reaction:“wer ist da“,““,“Hier ist %KEYWORD. Was möchten Sie von mir?“
reaction:“wer ist da“,““,“Sollten Sie das nicht wissen, sie haben mich angerufen!“
reaction:“ich will mit [Haushaltsmitglied1] sprechen“,““,“der ist unterwegs mit seiner Tabletschlampe Anja“
reaction:“ich will mit [Haushaltsmitglied2] sprechen“,““,“tut mir leid, die ist nicht zu sprechen.“
reaction:“ich will mit|sprechen“,““,“Ist nicht da“
reaction:“ich will mit|sprechen“,““,“Die Person ist mir unbekannt“
reaction:“ich will mit|sprechen“,““,“Pech gehabt, nicht da“
reaction:“ich will mit|reden“,““,“kenn ich nicht“
reaction:“ich will mit|reden“,““,“Pech gehabt, nicht da“
reaction:“können sie eine nachricht“,““,“nein, die Funktion ist noch nicht eingebaut“
reaction:“können sie eine nachricht“,““,“das tonband ist defekt“
reaction:“können sie eine nachricht“,““,“rufen Sie einfach später nochmal an.“
reaction:“können|sie|sagen|das“,““,“rufen Sie einfach später nochmal an.“
reaction:“können|sie|sagen|das“,““,“nein, kann ich sonstwie helfen?“
reaction:“können|sie|sagen|das“,““,“nein, der mp3-rekorder ist defekt“

Das ist natürlich nur ein Teil. Vorher müssen wir noch ein paar coole Techniken benutzen, damit sich Carola und wer auch immer da anruft, unterhalten können.

Der Pulseaudio Part

War klar, oder? Ohne Pulseaudio geht so etwas nicht, weil man PA erzählen extern kann, wo welches Programm seinen Sound ausgeben soll. Jetzt muß ich etwas ausholen, denn ich habe zwei Audiogeräte im PC:

  1. Die Mainboard Lautsprecher
  2. Einen HDMI Monitor mit Köpfhörerausgang

Wie Ihr vielleicht wisst, gibt es zu jedem Ausgabegerät unter Pulseaudio auch die Möglichkeit einen Monitor davon als Eingabegerät zu verwenden. Ihr ahnt vermutlich jetzt, wo die Reise hingeht. Wir verdrahten die Ausgabe von Twinkle zur Aufnahme von Carola und umgekehrt.

Da Carola über gsay/say Ihre Sätze an den Lautsprecher schickt, ist es tatsächlich so, daß Twinkles Aufnahme auf den Monitor vom Mainboard geht und Carola kurzfristig das HDMI Gerät belauscht, auf dem Twinkle die Sachen ausgeben wird.

Der Scriptteil

Damit das klappt, braucht es zwei Bashscripte: pulse.out + pulse.in

pulse.out stellt die Ausgaben um, pulse.in die Aufnahmen. Die Scripte könnt Ihr hier finden:

https://github.com/Cyborgscode/Personal-Voice-Assistent/tree/main/plugins/twinkle

Zur Technik:

Schritt 1 – Die Sinkid finden, auf der ein Prozess seine Ausgaben macht

echo $( LANG=C pactl list sink-inputs | grep -e „Sink\ Input“ -e „node.name“)

Geht den Befehl wenn Musik läuft ein, da kommt das raus:

Sink Input #543 node.name = „qmmp“

LANG=C ist nötig, damit es eine definierte Sprache gibt, die parsebare Ergebnisse liefert. Sonst müßte man das Script auf alle Sprachen erweitern. Jetzt haben wir die SinkID von QMMP und müssen wir noch wissen wohin die Reise gehen soll:  pactl list sinks | grep „Name:“

kommt u.a. so ein Treffer: „alsa_output.pci-0000_0a_00.4.analog-stereo“ Das ist in meinem Fall, die normale Lautsprecherausgabe vom Mainboard. Jetzt noch in einer Anweisung zusammen bringen:

pactl move-sink-input 543 alsa_output.pci-0000_0a_00.4.analog-stereo

Damit ist QMMP auf die Lautsprecher gelegt. Jetzt als Befehl fürs Script: pulse.out qmmp default

Wenn Ihr die Scripte zu hause benutzen wollt, dann müßt Ihr die Aus/Eingabe-Gerätenamen anpassen.

Damit kann man jetzt schon neue Funktionen für Carola bauen:

command:“schalte auf kopfhörer“,“EXEC:pulse.outx:x{config:audioplayer:pname}x:xhdmi“
command:“schalte auf lautsprecher“,“EXEC:pulse.outx:x{config:audioplayer:pname}x:xdefault“
command:“schalte um auf kopfhörer“,“EXEC:pulse.outx:x{config:audioplayer:pname}x:xhdmi“
command:“schalte um auf lautsprecher“,“EXEC:pulse.outx:x{config:audioplayer:pname}x:xdefault“

replacements:“h d m i“,“hdmi“
replacements:“u s b“,“usb“

command:“schalte .* um auf kopfhörer“,“EXEC:pulse.outx:x%0x:xhdmi“
command:“schalte .* um auf lautsprecher“,“EXEC:pulse.outx:x%0x:xdefault“
command:“schalte .* auf .* um“,“EXEC:pulse.outx:x%0x:x%1″

Die ersten vier Zeilen schalten den Default-Audioplayer um. Das ist eine nette kurzversion des Befehls. Mit {config:audioplayer:pname} bekommen wir den konfigurierten Prozessnamen von, in dem Fall, qmmp. Damit ist klar, wen das Script umschalten soll.

Die letzten drei Befehle wiederum nehmen einen beliebigen Prozessnamen an und schalten diesen Prozess auf wiederum beliebige Geräte um. (Spart es Euch, das ist doppelt exploitsicher, egal wie oft Ihr da ein ; einfügen wollt, es wäre nur ein Argument, keine Bashanweisung UND versucht mal Semikolon über eine Spracheingabe als ; einbauen zu lassen 😀 ) Da kann man also auch firefox oder twinkle angeben.

Das alleine reicht aber noch nicht für den Trick, ist aber eine sehr wichtige Grundlage!

Die Twinkleanbindung

Jetzt stellt Euch mal die Frage: „Woher weiß der PVA, daß jemand anruft?“ Antwort: „Weiß er nicht.“

Folgerichtig muß Twinkle die Arbeit leisten und Carola andocken 🙂 Dazu brauchen wir das hier:

und dazu brauchen wir die zwei Script ( auch auf Github ) :

#!/bin/bash

echo „action=autoanswer“
echo „end“

sleep 2s
pulse.in „PipeWire ALSA [python3.10]“ hdmimonitor
pulse.in „PipeWire ALSA [twinkle]“ defaultmonitor
pulse.out „PipeWire ALSA [twinkle]“ hdmi
gsay „Hi, Carola am Apparat“

Die beiden ersten Anweisungen sind an Twinkle selbst, sofort abzuheben und nicht mehr auf das Script zu warten. An der Stelle kann man auch noch eine spezielle Behandlung für bestimmte Anrufer einbauen, in dem man auf die CallerID checkt, aber das brauchen wir nicht.

Wir warten jetzt 2 Sekunden, damit alle Sinks aktiv sind und unsere Pulse.in und Pulse.out Scripte Ihre Magie ausführen können.

Wenn das gespräch beendet wird, was Carola nicht beeinflussen kann, kommt das Gegenscript zum Einsatz:

#!/bin/bash

pulse.in „PipeWire ALSA [python3.10]“ usb
pulse.in „PipeWire ALSA [twinkle]“ usb
pulse.out „PipeWire ALSA [twinkle]“ default

echo „action=end“

Alles wird wieder auf normal umgestellt. Wenn wir da sind, können wir , in meinem Fall, über die Kopfhörer den Anrufer hören und über den Lautsprecher was Carola sagt. Das hat den Vorteil, daß wenn der Anrufer z.b. ein Programm mit Tonausgabe startet, er das auch hören kann, weil für alle anderen Programme außer Twinkle, hat sich nichts an der eingestellten Konfig geändert.

Jetzt seid Ihr dran

Ok, Freunde, an der Stelle überlasse ich Euch jetzt das Feld. Ich will ausgeklügelte Telefonreaktionsketten sehen, in denen ein Anrufer solange wie möglich am Telefon gehalten wird 🙂 Die besten kommen ins Github!

Jitsi + Linphone = kein Telefon

Einen ganzen Vormittag kann man damit verbrennen, wenn Jitsi und Linphone zusammen laufen und beide SIP VOIP Anschlüsse bedienen können sollen. „Sollen“, weil „können“ tun sie es nicht, bis man die wahre Ursache erkennt 🙂

Falls der geneigte Leser etwas Frust aus dem Text herausliest, „etwas“ ist stark untertrieben.

Was war passiert ?

Nun, ich hatte LinPhone4 installiert, um es auszuprobieren und es behalten, weil es, an dem Tag, besser mit Sipgate funktionierte, als Jitsi, welches mit Sipgate gar nicht mehr kann 🙁  Jetzt mußte ich feststellen, daß ich mit LinPhone ohne irgendwelche Fehlermeldungen auf UI Seite, weder angerufen werden, noch selbst anrufen konnte, egal auf welchem Konto!

Nachdem ich in den Einstellungen von LinPhone die Position des Logs gefunden hatte, fielen mir dort wiederholt diese Zeilen auf:

2017-10-05 11:25:17:394 ERROR No listening point matching for [udp://sipgate.de:5060]
2017-10-05 11:25:17:394 ERROR belle_sip_client_transaction_send_request(): no channel available

Natürlich neben jeder Menge „Technobabble“ des Clienten, versteht sich 🙂

Was sagt uns das ?

Antwort: Nichts 🙂

Lediglich 1 .. in Worten EINE ..  Webseite konnte Google finden, die schon mal was davon gehört hatte. Zum Glück, war es die richtige.

Übersetzt meint die Fehlermeldung, daß das Programm keinen Kommunikationskanal öffnen konnte. Nur wieso nicht, darüber schweigt es sich aus. Hellseher haben halt immer Konjunktur, weil der Rest blöd genug ist, Raum für deren „Notwendigkeit“ zu schaffen. Dank der einen Webseite, war es dann aber zum Glück recht einfach, der Ursache auf die Spur zu kommen.

Auflösung

Einen „Channel“ etabliert man, in dem man einen TCP Port bindet und dem Gegenüber sagt, das man darauf angerufen werden kann. Wieso man beim „Anrufen“ nicht direkt mit dem SIP Provider eine TCP-Connection aufmachen kann, will ich gar nicht wissen, wenn man SIP lernen will, wird man eh durch Unlogik erschlagen. IMHO, eins der schlechtesten Protokolle aller Zeiten. Stückwerk ^10.

Ok, was braucht man um einen Port zu binden ? Eine Portnummer und niemanden, der schneller als man selbst war! Mit anderen Worten, Jitsi hatte sich schon permanent auf Port 5060 gebunden, weswegen Linphone das nicht konnte. Soweit, so in den RFCs für TCP Ports vorgesehen. Warum Linphone das nicht schreiben kann, ist ein weiteres Rätsel, weil die Fehlermeldung des TCP/IP Stacks zu dem „Fehler“ ist eindeutig!

Jetzt bietet LinPhone in den Kontoeinstellungen an, daß man statt Port 5060 zufällige Ports benutzen kann. Wieso das nicht der Standard ist, wird man nie erfahren. Jedenfalls funktioniert das SIP Konto sofort, wenn man die feste Portzuweisung abgeschaltet hat:

Fazit: In Jitsi habe ich jetzt SIP deaktiviert, damit entfällt auch das Binden des Ports.

Da Jitsi eh derzeit nicht mit Sipgate kann, spielt das es keine Rolle mehr. Warum das alles am Tag, an dem ich Linphone ausprobiert habe, funktioniert hat, ist ein weiteres Mysterium.

Das VOIP stinkt, dürfte vielen leidgeplagten Telefonanschlußinhabern bekannt sein, wie sehr das grade stinkt, hier im Überblick:

Skype:

Old: Raustelefonieren geht, angerufen werden geht nicht.
New: Raustelefonieren geht, Gui ist Mist, angerufen werden, geht nicht, weil sobald man „abnimmt“ legt Skype auf! Fix in Sicht ? Nein. Problem bekannt ? Seit Monaten.

Jitsi:

Fritz!box: Raus geht, Rein geht.
Sipgate: Raus geht, Rein geht nicht.

Jitsi Android:

Fritz!box: geht gar nicht.
Sipgate: Raus geht, Rein geht.

LinPhone:

Fritz!box: geht beides
Sipgate: geht beides

Einzig gültiger Kommentar zu Sipgate+Jitsi: AAAAAAAAAAAAAAAAAAAARRGGS!

Jitsi kann keine SIP Anrufe mehr annehmen

Wer kennt das nicht, in der Firma läuft es ruhig. Kunden melden sich nur per Email, aber das Telefon schweigt seit Tagen. Das alljährliche Sommerloch, wegen dessen wir alle in den Urlaub fahren …, oder ?

Paranoide Menschen würden jetzt per Telefon sich selbst anrufen und entsetzt feststellen, daß die Telefone nicht klingeln, weil .. ja .. scheisse, wieso klingeln die nicht ????!!!!!!

Ab jetzt herrscht Panik in der IT-Abteilung:  Was ist passiert ?

Ist der SIP Provider pleite gegangen ?
Haben Mäuse die Glasfaserkabel geknackt ?
Oder liegt es etwa an uns ?
Gab es ein Update der Telefonsoftware ?
Gab es überhaupt irgend ein Update ?

Also prüfen wir zunächst mal, ob alle betroffen sind und stellen fest : Alle Jitsi SIP Softphones sind quasi tod, aber normale Telefone für SIP nicht. Jitsi kann zwar noch raustelefonieren, sonst wäre das ja auch eher aufgefallen, aber ankommende Anrufe gehen nicht mehr. Komischerweise geht Jitsi auf den Handies noch.

Das schliesst per se ein DSL Router und Netzwerkproblem aus, außer die lokale Firewall wäre im Spiel:

TEST:
systemctl stop firewalld
Anruf => kein Klingeln
systemctl start firewalld

Das wars nicht. Hatte Jitsi ein Update ? Seit Monaten nicht mehr.  Fällt somit als Ursache auch weg.  Hmm…

2 Tage und eine systematische Suche später ..

Das Problem, das  Jitsi keine SIP Calls mehr annehmen konnte, ist behoben worden.

Es lag NICHT an Jitsi, Sipgate, den Mäusen, dem DSL Router, den Kabeln, der Firewall sondern an :  JAVA.

Die Ursache

Fedora hat vor zwei Tagen ein neues openjdk 1.8.0.141_b16 eingespielt, das hat Jitsi und vermutlich andere Apps beeinträchtigt. Das Update war als Security Update markiert, es ist also potentiell gefährlich, die App weiter zu betreiben. Ist es in dem Fall nicht, da das Update pauschal als Security Update eingestuft wurde, weil 4 Security Tests beim Build nicht liefen. Dazu noch eine Menge normaler Updates, von denen vermutlich eins die Ursache ist.

Der Workaround

Der schnellste Workaround ist natürlich, Java zu downgraden auf die letzte funktionierende Version:

java-1.8.0-openjdk-1.8.0.131-5.b12.fc25.x86_64.rpm
java-1.8.0-openjdk-devel-1.8.0.131-5.b12.fc25.x86_64.rpm
java-1.8.0-openjdk-headless-1.8.0.131-5.b12.fc25.x86_64.rpm
java-1.8.0-openjdk-javadoc-1.8.0.131-5.b12.fc25.noarch.rpm

Wenn man das jetzt mit „dnf downgrade java-*“ macht, landet man bei einer uralten Version, was Securitymäßig keine gute Idee ist. Also lädt man die Pakete hier runter:

https://kojipkgs.fedoraproject.org//packages/java-1.8.0-openjdk/1.8.0.131/5.b12.fc25/noarch/java-1.8.0-openjdk-javadoc-1.8.0.131-5.b12.fc25.noarch.rpm
https://kojipkgs.fedoraproject.org//packages/java-1.8.0-openjdk/1.8.0.131/5.b12.fc25/x86_64/java-1.8.0-openjdk-headless-1.8.0.131-5.b12.fc25.x86_64.rpm
https://kojipkgs.fedoraproject.org//packages/java-1.8.0-openjdk/1.8.0.131/5.b12.fc25/x86_64/java-1.8.0-openjdk-devel-1.8.0.131-5.b12.fc25.x86_64.rpm
https://kojipkgs.fedoraproject.org//packages/java-1.8.0-openjdk/1.8.0.131/5.b12.fc25/x86_64/java-1.8.0-openjdk-1.8.0.131-5.b12.fc25.x86_64.rpm

Aber natürlich nur passenderweise für Fedora 25, andere Versionen bitte selbst bei koji suchen.

Nicht vergessen: /etc/dnf/dnf.conf editieren und java auf die Sperrliste setzen, sonst kommt das Update gleich wieder rein.

Warum ist jetzt der Downgrade auf b12 akzeptable und der auf die Fedora Downgrade Version nicht ?

Weil Jitsi nur Verbindungen zu bestimmten, vertrauenswürdigen Servern aufnimmt. Es ist daher kaum möglich etwaige SecBugs in Java über diesen Channel auszunutzen, zumal in der ML von OpenJAVA keine Hinweise zu Securitybugs enthalten waren. 4 Tests beim Build failten, das kann alles sein. in nächster Zeit wird es sicher Updates von Jitsi geben, damit es auch mit der aktuellen Java Version läuft, denn es steht zu befürchten, daß Openjdk, den „Bug“ nicht fixt.