iToverDose/Software· 20 MAI 2026 · 16:06

Ein Open-Source-Telefonie-System selbst gebaut: Architektur und die Fehler der Nacht

Ein Entwickler hat einen Open-Source-Dialer als Alternative zu ViciDial erstellt – mit Kamailio, FreeSWITCH und Go. Doch die größten Herausforderungen lagen nicht im Code, sondern in unerwarteten Fehlern bei DTMF, Audio und Pacing. Hier sind die Lektionen aus schlaflosen Nächten.

DEV Community5 min0 Kommentare

Ein selbstgebautes Open-Source-Telefonie-System ist mehr als nur ein technisches Projekt – es ist eine Reise durch unerwartete Fallstricke, nächtelange Debugging-Sessions und die Suche nach der perfekten Architektur. Genau das hat ein Entwickler mit seinem neuen System vollzogen, das nun als Alternative zu kommerziellen Lösungen wie ViciDial auf GitHub veröffentlicht wurde. Doch hinter der fertigen Software stecken unzählige Stunden, in denen sich alles um scheinbar einfache Funktionen drehte, die plötzlich nicht mehr funktionierten.

Der Technologie-Stack: Warum diese Kombination?

Die Architektur des neuen Systems setzt auf eine modulare Trennung von Aufgaben, um Skalierbarkeit und Wartbarkeit zu gewährleisten. Im Zentrum steht die Kombination aus Kamailio und FreeSWITCH – eine Entscheidung, die auf den ersten Blick übertrieben wirken mag, sich aber bei genauerer Betrachtung als strategisch erweist.

  • Kamailio übernimmt die Rolle des SIP-Edge-Servers. Es ist optimiert für hohe Anrufraten pro Sekunde (CPS) und unterstützt STIR/SHAKEN durch das Modul secsipid, das die Authentizität von Anrufen sicherstellt. Diese Trennung ist entscheidend, da Kamailio zwar für die Routing-Logik prädestiniert ist, aber nicht für die Verarbeitung von Medienströmen.
  • FreeSWITCH übernimmt die Medienverarbeitung. Durch den Einsatz von bgapi originate lassen sich Anrufe dynamisch starten, während Module wie mod_avmd die Erkennung von Anrufbeantwortern ermöglichen. Die Kommunikation zwischen FreeSWITCH und dem Steuerungssystem erfolgt über das ESL-Protokoll (Event Socket Layer), das in einer Lua-Skriptumgebung pro Anruf genutzt wird, um den Zustand zu verwalten.
  • Go fungiert als zentrale Steuerungseinheit. Es koordiniert die Anrufplanung, die Lead-Verwaltung und die Zustandsmaschine, die auf ESL-Ereignisse reagiert. Besonders hervorzuheben ist der Einsatz von `SELECT FOR UPDATE SKIP LOCKED`, um Lead-Ansprüche zwischen mehreren Kampagnen sicher zu verteilen – eine Methode, die Deadlocks vermeidet und die Effizienz steigert.
  • PostgreSQL mit Row-Level Security (RLS) bildet die Datenbankbasis. Jeder Datensatz ist mit einer tenant_id versehen, und die Zugriffsrechte werden direkt in der Datenbank durch RLS-Policies durchgesetzt. Diese Herangehensweise eliminiert das Risiko von Abfragen, die versehentlich Daten anderer Mandanten lesen, da die Datenbank die Isolation aktiv erzwingt.
  • Die React-basierte Webkonsole dient als grafische Oberfläche für die Verwaltung von Kampagnen, Leads, Skripten und Berichten. Sie ermöglicht eine intuitive Steuerung des Systems, ohne tiefgehende technische Kenntnisse vorauszusetzen.

Die Trennung von Kamailio und FreeSWITCH mag auf den ersten Blick redundant erscheinen, doch sie bietet einen entscheidenden Vorteil: Skalierbarkeit. Während FreeSWITCH problemlos um zusätzliche Medien-Server erweitert werden kann, bleibt die SIP-Routing-Logik in Kamailio zentralisiert – eine Architektur, die sich in der Praxis als robust erwiesen hat.

Multi-Tenancy: Sicherheit durch die Datenbank erzwungen

Eine der größten Herausforderungen in der Entwicklung von Telekommunikationssystemen ist die sichere Trennung von Mandanten. Viele Lösungen verlassen sich auf manuelle Prüfungen in SQL-Abfragen, etwa durch WHERE tenant_id = .... Doch diese Herangehensweise ist fehleranfällig und kann zu Datenlecks führen.

In diesem Projekt wurde diese Problematik radikal gelöst: PostgreSQL übernimmt die Mandantentrennung aktiv. Jeder API-Request setzt eine Session-Variable, die den aktuellen Mandanten identifiziert. Die RLS-Policies der Datenbank sorgen dann dafür, dass Abfragen automatisch nur die Daten des berechtigten Mandanten zurückgeben – selbst wenn eine Abfrage versehentlich ohne tenant_id-Filter ausgeführt wird. Diese Methode eliminiert nicht nur menschliche Fehler, sondern gibt dem Entwickler auch die Gewissheit, dass die Datenintegrität auf Datenbankebene sichergestellt ist.

Die Bugs, die keine Ruhe lassen wollten

Nicht alle Probleme lagen in der Architektur oder den Tools – viele entstanden durch subtile Fehler, die erst unter Last oder in Echtzeit sichtbar wurden. Diese Bugs haben nicht nur Stunden, sondern Nächte gekostet.

1. „Press-1“ funktioniert nicht – obwohl die Kampagne läuft

Eine der Kernfunktionen eines Dialers ist die Interaktive Sprachantwort (IVR), bei der Anrufer durch Tastendruck Aktionen auslösen können. Doch in diesem System blieb die „Press-1“-Abfrage stumm. Der Grund: Die Kampagnenlogik ging davon aus, dass nur interne Agenten als verfügbar galten – doch diese wurden längst durch externe Brücken ersetzt. Die Folge: Die Kampagne startete, doch es gab keine „Agenten“, die auf den Tastendruck warteten. Die Lösung bestand darin, die „Press-1“-Pacing-Logik an die Broadcast-Funktionalität anzupassen und die maximale Kapazität direkt in der Kampagnenkonfiguration zu definieren.

2. MP3-Dateien werden als Stille abgespielt

Ein weiterer Albtraum war die Audio-Wiedergabe. Die in FreeSWITCH integrierten Module konnten MP3-Dateien nicht direkt abspielen, da das mod_shout-Modul fehlte. Nach dessen Installation klang die Audio jedoch nicht nur verzerrt, sondern wurde bei jedem Anruf neu von 44,1 kHz Stereo auf 8 kHz Mono umgewandelt. Die Lösung lag nicht im Code, sondern im vorherigen Transkodieren der Audio-Dateien. Mit ffmpeg wurden alle hochgeladenen MP3-Dateien in 8 kHz Mono PCM WAV-Dateien umgewandelt, sodass FreeSWITCH sie ohne weitere Verarbeitung abspielen konnte.

3. DTMF-Töne verschwinden im Nichts

Ein besonders tückischer Fehler betraf die DTMF-Erkennung. In der Lua-Skriptumgebung wurde die Funktion session:execute("playback", file) verwendet, um eine Ansage abzuspielen. Doch dieses Modul hat einen fatalen Nebeneffekt: Es frisst alle DTMF-Töne, die während der Wiedergabe eingegeben werden. Das Ergebnis: Anrufer drücken die „1“, doch das System registriert nichts – der Anruf wird als „keine Eingabe“ interpretiert und beendet. Die Lösung war der Einsatz von session:playAndGetDigits(), einer Funktion, die Ansage und Tastendruck in einem Schritt verarbeitet, ohne die Eingabe zu verlieren.

4. Anrufbeantworter-Erkennung ohne zusätzliche Kosten

Kommerzielle Dialer-Lösungen bieten oft integrierte Anrufbeantworter-Erkennung (AMD) an – doch diese Module sind entweder veraltet oder mit Lizenzgebühren verbunden. In diesem Projekt wurde stattdessen auf `mod_avmd` gesetzt, ein Modul zur Erkennung von Besetztzeichen und Stille. Die Implementierung erfolgte durch eine kreative Lösung: Das Broadcast-Lua-Skript startet die AvMD-Erkennung, spielt die Nachricht ab und wiederholt sie nach einem erkannten Besetzton. Dadurch landet eine saubere Version der Nachricht auf dem Anrufbeantworter – ganz ohne zusätzliche Kosten.

Der aktuelle Stand: Fast bereit, aber nicht ganz

Das System ist noch nicht für den Produktiveinsatz bereit, aber die wichtigsten Funktionen sind bereits implementiert und getestet. Broadcast-Kampagnen, Press-1-Funktionen, Anrufbeantworter-Erkennung und Aufzeichnung arbeiten end-to-end zusammen. Doch es gibt noch offene Punkte:

  • Es fehlt eine direkte Anbindung an einen Carrier für den produktiven Betrieb. Bisher wurde mit einem Linphone-Gateway getestet, das jedoch seine eigenen Herausforderungen bei der DTMF-Übertragung mit sich bringt.
  • Die STIR/SHAKEN-Signierung ist in Kamailio konfiguriert, wurde aber noch nicht unter realen Bedingungen mit einem Carrier getestet. Die Authentizität von Anrufen ist jedoch ein kritischer Faktor für die Akzeptanz bei Endnutzern.
  • Eine Agenten-Softphone-Lösung fehlt noch, um die Bridge-Funktionalität vollständig zu nutzen.

Das Projekt wird unter der AGPL-3.0-Lizenz auf GitHub gehostet und ist selbsthostbar. Der Entwickler betont, dass es keine kommerzielle Absicht gibt – es handelt sich um ein reines Community-Projekt, das eine Lücke füllen soll. Für Entwickler, die bereits Erfahrung mit Outbound-Telefonie haben, gibt es eine Einladung zum Austausch: Was wurde übersehen? Welche Fehler könnten noch schlummern? Denn bevor das System mit echtem Traffic belastet wird, sollen mögliche Schwachstellen identifiziert und behoben werden.

KI-Zusammenfassung

Açık kaynaklı bir ViciDial alternatifi inşa eden geliştirici, kullandığı yığını ve geceyarılarını uyutmayan kritik hataları paylaşıyor. PostgreSQL RLS, FreeSWITCH ve Go tabanlı mimariyi keşfedin.

Kommentare

00
KOMMENTAR SCHREIBEN
ID #E94DH5

0 / 1200 ZEICHEN

Menschen-Check

4 + 7 = ?

Erscheint nach redaktioneller Prüfung

Moderation · Spam-Schutz aktiv

Noch keine Kommentare. Sei der erste.