feat(telefon): Wartezeit vor answer() fuer parallel klingelnde Durchwahl (DW3)

Manche Provider (Fonial/Plusnet) klingeln bei einer Durchwahl parallel an
mehreren registrierten Zielen. Ohne Verzoegerung gewinnt AgentOne das Rennen
immer, weil answer() sofort laeuft - das eigentliche Endgeraet kommt nie zum
Klingeln. DW3_DDI in der .env schaltet 20s Wartezeit vor answer() frei,
erkannt ueber den SIP-Header X-ORIGINAL-DDI-URI (destination_number ist bei
diesem Trunk unbrauchbar). Nimmt jemand am Endgeraet ab, bricht der Provider
AgentOnes Versuch per CANCEL ab; sonst laeuft der Dialplan normal weiter zu
Ansage+Aufnahme.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ovr91y2VK8bYYKPimcX68
This commit is contained in:
Jeuner 2026-09-01 02:53:05 +02:00
parent b3d5e82958
commit 3da0cd7ec9
4 changed files with 78 additions and 0 deletions

View file

@ -65,6 +65,17 @@ SIP_DOMAIN=sip.plusnet.de
SIP_PASS=
SIP_PROXY=voice01.sip.plusnet.de
# --- Durchwahl 3: eigenes Endgeraet vor dem Anrufbeantworter klingeln lassen ---
# Leer lassen = keine Sonderbehandlung, jeder Anruf landet sofort beim
# Anrufbeantworter. Manche Provider (z.B. Fonial/Plusnet) klingeln bei einer
# Durchwahl PARALLEL an mehreren registrierten Zielen - ohne Wartezeit
# gewinnt AgentOne das Rennen immer, weil es sofort abnimmt (answer() ist die
# erste Aktion im Dialplan). Die DDI kommt bei Plusnet nicht im
# destination_number an (der ist bei diesem Trunk unbrauchbar), sondern im
# Header X-ORIGINAL-DDI-URI - siehe telefon/freeswitch/dw3_warten.xml.tpl.
# Nur Ziffern, kein "+".
DW3_DDI=
# --- Ansage ---
# piper = lokal, natuerlich, Modelle unter ~/piper-voices
# say = lokal, macOS-Bordmittel (Rueckfall wenn Piper fehlt)

View file

@ -236,6 +236,35 @@ Der SIP-Zugang steht in der `.env` (`SIP_USER`, `SIP_DOMAIN`, `SIP_PASS`). Das
Einrichtungsskript trägt das Passwort in die FreeSWITCH-Konfiguration ein und
setzt deren Rechte auf 600 — im Git liegen nur Vorlagen mit Platzhaltern.
### Durchwahl parallel zu einem Endgerät klingeln lassen
Manche Provider (z. B. Fonial/Plusnet) klingeln bei einer Durchwahl **parallel**
an allen dafür registrierten Zielen — bei uns also gleichzeitig an AgentOne und
an einem echten Telefon/Softphone. Ohne Gegenmaßnahme gewinnt AgentOne das
Rennen aber immer: `answer()` ist im Dialplan die erste Aktion, es gibt keine
Verzögerung davor. Das Telefon klingelt dann faktisch nie, weil der Anruf schon
beim Assistenten gelandet ist, bevor am Gerät überhaupt ein Klingelzeichen
ankommt.
`DW3_DDI` in der `.env` schaltet eine Wartezeit vor `answer()` frei
(`telefon/freeswitch/dw3_warten.xml.tpl`, deployed als `00_dw3_warten.xml`
lädt alphabetisch vor `00_praxis_ab.xml`): erkennt der Dialplan die passende
Durchwahl, wartet er 20 Sekunden, bevor überhaupt abgenommen wird. Nimmt in der
Zeit jemand am registrierten Endgerät ab, bricht der Provider den Versuch bei
AgentOne per SIP-`CANCEL` ab — der Dialplan kommt gar nicht mehr bis zum
`answer()`. Nimmt niemand ab, läuft er nach den 20 Sekunden normal weiter zu
Ansage und Aufnahme, identisch zum Standard-Anrufbeantworter.
Wichtig: die Durchwahl selbst kommt bei diesem Trunk nicht im
`destination_number` an (der zeigt bei Plusnet nur eine interne Trunk-Kennung,
unabhängig von der gewählten Nummer), sondern im SIP-Header
`X-ORIGINAL-DDI-URI` der eingehenden Einladung — nur der ist brauchbar, um DW3
von anderen Anrufen zu unterscheiden. `DW3_DDI` erwartet die volle Rufnummer
inklusive Durchwahl-Ziffer(n), nur Ziffern, kein `+`.
Leer lassen = keine Sonderbehandlung, jeder Anruf landet sofort beim
Anrufbeantworter wie bisher.
Text ändern: `profile/$PROFIL/ansage.txt` bearbeiten (siehe
[Branchen-Profil](#kategorien--branchen-profil)), `ansage_bauen.sh` erneut
ausführen. Für den Praxisbetrieb muss die Ansage den Notruf 112 nennen und auf

View file

@ -0,0 +1,30 @@
<include>
<!-- Durchwahl 3: Fonial klingelt bei dieser DDI offenbar PARALLEL an
AgentOne und an MainMacPhone (dem Endgeraet mit Durchwahl 3). Ohne
diese Regel beantwortet AgentOne jeden Anruf sofort (answer() ist die
erste Aktion in 00_praxis_ab.xml, keine Verzoegerung davor) - AgentOne
gewinnt das Rennen daher immer, bevor am anderen Mac ueberhaupt
geklingelt hat. deflect() (siptrace-verifiziert: nie tatsaechlich ein
302 verschickt) hat rein zufaellig als Wartezeit gewirkt und damit
MainMacPhone eine Chance gegeben.
Diese Regel macht das Warten explizit: bei erkannter DW3
(X-ORIGINAL-DDI-URI, da destination_number bei diesem Trunk
unbrauchbar ist) erstmal nur schlafen. Nimmt jemand an MainMacPhone
ab, schickt Plusnet ein CANCEL - der Kanal wird beendet, bevor der
sleep() zu Ende ist, alles Weitere unten laeuft nie. Nimmt niemand ab,
laeuft der Dialplan nach dem sleep() normal weiter zur Ansage+Aufnahme,
identisch zu AgentOnes Anrufbeantworter (00_praxis_ab.xml). -->
<extension name="dw3_warten">
<condition field="${sip_h_X-ORIGINAL-DDI-URI}" expression="@@DW3_DDI@@">
<action application="sleep" data="20000"/>
<action application="set" data="record_stereo=false"/>
<action application="set" data="RECORD_ANSWER_REQ=true"/>
<action application="answer"/>
<action application="sleep" data="700"/>
<action application="playback" data="@@PROJEKT@@/telefon/ansage.wav"/>
<action application="record"
data="@@PROJEKT@@/telefon/eingang/${strftime(%Y%m%d-%H%M%S)}_${caller_id_number}.wav 120 200 4"/>
<action application="hangup"/>
</condition>
</extension>
</include>

View file

@ -44,6 +44,7 @@ fuelle() { # <vorlage> <ziel>
-e "s|@@SIP_PASS@@|$SIP_PASS|g" \
-e "s|@@SIP_DOMAIN@@|$SIP_DOMAIN|g" \
-e "s|@@SIP_PROXY@@|${SIP_PROXY:-$SIP_DOMAIN}|g" \
-e "s|@@DW3_DDI@@|${DW3_DDI:-}|g" \
-e "s|@@PROJEKT@@|$PROJEKT|g" "$1" > "$2"
}
@ -55,3 +56,10 @@ echo "Trunk -> $FS_ETC/sip_profiles/external/plusnet.xml (Rechte 600)"
echo "Dialplan -> $FS_ETC/dialplan/public/00_praxis_ab.xml"
echo "Ansage -> $PROJEKT/telefon/ansage.wav"
echo "Eingang -> $PROJEKT/telefon/eingang"
if [ -n "${DW3_DDI:-}" ]; then
fuelle "$PROJEKT/telefon/freeswitch/dw3_warten.xml.tpl" "$FS_ETC/dialplan/public/00_dw3_warten.xml"
echo "DW3 -> $FS_ETC/dialplan/public/00_dw3_warten.xml (DDI: $DW3_DDI, 20s Wartezeit)"
else
echo "DW3 -> uebersprungen (DW3_DDI leer in .env)"
fi