Dialplan Configuration & Call Routing
๐ Back to Main Documentation
Comprehensive guide to XML dialplan configuration, call routing logic, and dialplan variables.
Related Documentationโ
Core Documentationโ
- ๐ Main README - Overview and quick start
- ๐ง Configuration Guide - SIP trunk and gateway configuration
- ๐ง Operations Guide - Dialplan testing and templates viewer
Call Processing Flowโ
- ๐ข Number Translation - E.164 normalization (happens before dialplan)
- ๐ฅ Sh Interface - Subscriber data retrieved for dialplan variables
- ๐ก SS7 MAP - MSRN/HLR data in dialplan variables
- ๐ณ Online Charging - OCS authorization in call flow
Services Implementationโ
- โ๏ธ Supplementary Services - Implementing call forwarding, CLI blocking in dialplan
- ๐ Voicemail - Voicemail routing and deposit/retrieval in dialplan
- ๐ TTS Prompts - Using prompts in dialplan with playback
Monitoringโ
- ๐ Dialplan Metrics - Dialplan-specific metrics and monitoring
- ๐ Metrics Reference - General system metrics
Dialplan Config / Call Routingโ
The TAS uses XML dialplans with a schema compatible with standard telecom XML dialplan formats, with variables populated by the TAS. This means you can define your own dialplan as needed, with the business logic for the operator, but have all the required data such as Repository Data, SS7 routing info, IMPI / IMPU identities, dialplan normalization, etc, etc.
Dialplans are written into priv/templates and take the form:
mo_dialplan.xml- Mobile Originated Call Dialplanmo_emergency_dialplan.xml- Mobile Originated Emergency Call Dialplanmt_dialplan.xml- Mobile Terminated Call Dialplan
You can view the Dialplans from inside the Web UI.
Various variables are set by the TAS before the XML gets parsed, these variables are printed to the log at the start of the call with their current values and are very helpful when defining your own call logic.
FreeSWITCH XML Dialplan Fundamentalsโ
OmniTAS uses the same XML call routing system as the FreeSWITCH project, which allows for flexible call routing to meet your needs.
This section explains the core concepts and provides practical examples.
Basic Structureโ
A dialplan consists of extensions containing conditions and actions:
<extension name="description-of-what-this-does">
<condition field="${variable}" expression="regex-pattern">
<action application="app_name" data="parameters"/>
<anti-action application="app_name" data="parameters"/>
</condition>
</extension>
Extensions are evaluated in order from top to bottom. When a condition matches, its actions execute.
Conditions and Regex Matchingโ
Conditions test variables against regular expressions. If the regex matches, actions execute; if not, anti-actions execute.
Basic exact match:
<condition field="${tas_destination_number}" expression="2222">
<action application="log" data="INFO Calling voicemail access number"/>
</condition>
Multiple number match:
<condition field="${tas_destination_number}" expression="^(2222|3444|3445)$">
<action application="log" data="INFO Calling special service"/>
</condition>
Pattern matching with capture groups:
<condition field="${tas_destination_number}" expression="^1(8[0-9]{9})$">
<!-- Matches 1 followed by 8 and 9 more digits -->
<action application="log" data="INFO Matched toll-free: $1"/>
<action application="bridge" data="sofia/gateway/trunk/${tas_destination_number}"/>
</condition>
Prefix matching:
<condition field="${tas_destination_number}" expression="^00">
<!-- Matches any number starting with 00 (international) -->
<action application="log" data="INFO International call detected"/>
</condition>
Range matching:
<condition field="${msisdn}" expression="^5551241[0-9]{4}$">
<!-- Matches 55512410000 through 55512419999 -->
<action application="log" data="INFO Subscriber in range"/>
</condition>
Actions vs Anti-Actionsโ
Actions execute when a condition matches. Anti-actions execute when a condition does NOT match.
<condition field="${cli_withheld}" expression="true">
<!-- Executes if CLI is withheld -->
<action application="set" data="effective_caller_id_number=anonymous"/>
<action application="set" data="origination_privacy=hide_number"/>
<!-- Executes if CLI is NOT withheld -->
<anti-action application="log" data="DEBUG CLI is normal"/>
<anti-action application="set" data="effective_caller_id_number=${msisdn}"/>
</condition>
The continue="true" Attributeโ
By default, when an extension's condition matches, the dialplan stops processing further extensions. The continue="true" attribute allows processing to continue to the next extension.
Without continue (default behavior):
<extension name="First-Check">
<condition field="${tas_destination_number}" expression="^(.*)$">
<action application="log" data="INFO Processing call"/>
</condition>
</extension>
<extension name="Never-Reached">
<!-- This NEVER executes because the previous extension matched -->
<condition field="${tas_destination_number}" expression="^(.*)$">
<action application="log" data="INFO This won't print"/>
</condition>
</extension>
With continue="true":
<extension name="Print-Vars" continue="true">
<condition field="${tas_destination_number}" expression="^(.*)$">
<action application="info" data=""/>
</condition>
</extension>
<extension name="Check-Balance" continue="true">
<condition field="${hangup_case}" expression="OUTGOING_CALL_BARRED">
<action application="log" data="ERROR Insufficient balance"/>
<action application="hangup" data="${hangup_case}"/>
</condition>
</extension>
<extension name="Route-Call">
<!-- This extension still gets evaluated -->
<condition field="${tas_destination_number}" expression="^(.*)$">
<action application="bridge" data="sofia/gateway/trunk/${tas_destination_number}"/>
</condition>
</extension>
Use continue="true" for:
- Logging/debugging extensions
- Setting variables that apply to multiple scenarios
- Validation checks that don't route the call
Common Applicationsโ
call controlโ
answer - Answer the call (send 200 OK)
<action application="answer" data=""/>
hangup - Terminate the call with a specific cause
<action application="hangup" data="NORMAL_CLEARING"/>
<action application="hangup" data="USER_BUSY"/>
<action application="hangup" data="NO_ANSWER"/>
bridge - Connect the call to another destination
<!-- Bridge to external gateway -->
<action application="bridge" data="sofia/gateway/trunk/+12125551234"/>
<!-- Bridge to internal extension with codec preferences -->
<action application="bridge" data="{absolute_codec_string=AMR-WB,AMR,PCMA}sofia/internal/sip:user@domain.com"/>
<!-- Bridge with timeout -->
<action application="bridge" data="{originate_timeout=30}sofia/gateway/trunk/${tas_destination_number}"/>
Variables and Channel Dataโ
set - Set a channel variable
<action application="set" data="my_variable=my_value"/>
<action application="set" data="sip_h_X-Custom-Header=CustomValue"/>
<action application="set" data="effective_caller_id_number=anonymous"/>
unset - Remove a channel variable
<action application="unset" data="sip_h_P-Asserted-Identity"/>
export - Set variable and export to B-leg (bridged call)
<action application="export" data="sip_h_X-Account-Code=ABC123"/>
Media and Promptsโ
playback - Play an audio file
<action application="playback" data="/sounds/en/us/callie/misc/8000/out_of_credit.wav"/>
<action application="playback" data="$${base_dir}/sounds/custom_prompt.wav"/>
sleep - Pause for specified milliseconds
<action application="sleep" data="1000"/> <!-- Sleep for 1 second -->
echo - Echo audio back to caller (testing)
<action application="echo" data=""/>
conference - Place call into conference
<action application="conference" data="room-${destination_number}@wideband"/>
voicemailโ
voicemail - Access voicemail system
<!-- Leave voicemail for mailbox -->
<action application="voicemail" data="default default ${msisdn}"/>
<!-- Check voicemail with auth -->
<action application="voicemail" data="check auth default default ${msisdn}"/>
Logging and Debuggingโ
log - Write to log file
<action application="log" data="INFO Processing call from ${msisdn}"/>
<action application="log" data="DEBUG Destination: ${tas_destination_number}"/>
<action application="log" data="ERROR Call failed with cause: ${hangup_cause}"/>
info - Dump all channel variables to log
<action application="info" data=""/>
Misc Applicationsโ
say - Text-to-speech number reading
<action application="say" data="en number iterated ${tas_destination_number}"/>
send_dtmf - Send DTMF tones
<action application="send_dtmf" data="1234#"/>
Practical Examplesโ
Emergency Services Routing:
<extension name="Emergency-911">
<condition field="${tas_destination_number}" expression="^(911|112)$">
<action application="log" data="ALERT Emergency call from ${msisdn}"/>
<action application="answer" data=""/>
<action application="playback" data="/sounds/emergency_services_transfer.wav"/>
<action application="bridge" data="sofia/gateway/emergency_gw/${tas_destination_number}"/>
</condition>
</extension>
Conditional Routing Based on Balance:
<extension name="Check-Credit">
<condition field="${hangup_case}" expression="OUTGOING_CALL_BARRED">
<action application="answer" data=""/>
<action application="playback" data="/sounds/out_of_credit.wav"/>
<action application="hangup" data="CALL_REJECTED"/>
</condition>
</extension>
On-Net vs Off-Net Routing:
<extension name="Route-Decision">
<condition field="${on_net_status}" expression="true">
<!-- On-net: route back through TAS -->
<action application="log" data="INFO Routing to on-net subscriber"/>
<action application="bridge" data="sofia/internal/+${tas_destination_number}@10.179.3.60"/>
<anti-action application="log" data="INFO Routing off-net"/>
<anti-action application="bridge" data="sofia/gateway/trunk/+${tas_destination_number}"/>
</condition>
</extension>
Anonymous Caller ID Handling:
<extension name="CLI-Privacy" continue="true">
<condition field="${cli_withheld}" expression="true">
<action application="set" data="effective_caller_id_name=anonymous"/>
<action application="set" data="effective_caller_id_number=anonymous"/>
<action application="set" data="origination_privacy=hide_number"/>
</condition>
</extension>
Voicemail on No Answer:
<extension name="Try-Bridge-Then-VM">
<condition field="${tas_destination_number}" expression="^(555124115\d{2})$">
<action application="set" data="call_timeout=30"/>
<action application="bridge" data="sofia/internal/${tas_destination_number}@domain.com"/>
<!-- If bridge fails, go to voicemail -->
<action application="log" data="INFO Bridge failed, routing to voicemail"/>
<action application="answer" data=""/>
<action application="voicemail" data="default default ${tas_destination_number}"/>
</condition>
</extension>
Number Range Routing:
<extension name="Local-Numbers">
<condition field="${tas_destination_number}" expression="^([2-9]\d{2})$">
<!-- 3-digit local extensions 200-999 -->
<action application="log" data="INFO Local extension: $1"/>
<action application="bridge" data="sofia/internal/$1@pbx.local"/>
</condition>
</extension>
<extension name="National-Numbers">
<condition field="${tas_destination_number}" expression="^555\d{7}$">
<!-- National mobile numbers -->
<action application="log" data="INFO National mobile call"/>
<action application="bridge" data="sofia/gateway/national_trunk/${tas_destination_number}"/>
</condition>
</extension>
<extension name="International">
<condition field="${tas_destination_number}" expression="^00\d+$">
<!-- International calls starting with 00 -->
<action application="log" data="INFO International call"/>
<action application="bridge" data="sofia/gateway/intl_trunk/${tas_destination_number}"/>
</condition>
</extension>
Further Documentationโ
For complete details on each application:
- FreeSWITCH Dialplan Documentation: https://freeswitch.org/confluence/display/FREESWITCH/Dialplan
- FreeSWITCH mod_dptools: https://freeswitch.org/confluence/display/FREESWITCH/mod_dptools (complete application reference)
- Regular Expression Reference: https://freeswitch.org/confluence/display/FREESWITCH/Regular+Expression
- Channel Variables: https://freeswitch.org/confluence/display/FREESWITCH/Channel+Variables
The FreeSWITCH wiki contains detailed documentation for every dialplan application, including all parameters and use cases.
Dialplan Variablesโ
Variables set by the TAS in the XML dialplan logic:
Common Variables (All Call Types)โ
Initial Setup:
destination_number- translated destination numbertas_destination_number- translated destination numbereffective_caller_id_number- translated source number
Emergency Callsโ
hangup_case- "none"ims_private_identity- private user identityims_public_identity- public user identitymsisdn- subscriber number (stripped of +)imsi- IMSI from private identityims_domain- domain from private identity
MT Calls (Mobile Terminated)โ
ims_private_identity- private user identityims_public_identity- public user identitymsisdn- subscriber number (stripped of +)imsi- IMSI from private identityims_domain- domain from private identitycall_forward_all_destination- CFA destination or "none"call_forward_not_reachable_destination- CFNRc destinationscscf_address- S-CSCF address or "none"scscf_domain- S-CSCF domain or "none"no_reply_timer- timeout for no replyhangup_case- "none" or "UNALLOCATED_NUMBER"msrn- MSRN from PRN (if roaming) or forwarded number from SRI (if call forwarding active)tas_destination_number- Routing destination override (set to MSRN or forwarded number)
MO Calls (Mobile Originated)โ
hangup_case- "none", "OUTGOING_CALL_BARRED", or "UNALLOCATED_NUMBER"ims_private_identity- private user identityims_public_identity- public user identitymsisdn- subscriber number (stripped of +)imsi- IMSI from private identityims_domain- domain from private identityallocated_time- time allocated by OCS (if online charging enabled)cli_withheld- "true" or "false" stringon_net_status- "true" or "false" string (whether destination is on-net)msrn- MSRN for roaming subscribers (if applicable)tas_destination_number- MSRN override (if roaming)
Emergency Callingโ
Emergency calling is controlled through the emergency_call_codes configuration parameter and is automatically detected during call authorization.
Configurationโ
Configure the emergency call codes in your config/runtime.exs file:
config :tas,
emergency_call_codes: ["911", "912", "913", "sos"],
# ... other config
Configuration Details:
emergency_call_codes(required): List of strings representing emergency service numbers- These codes are checked in addition to SIP emergency URNs (e.g.,
<urn:service:sos>) - The system performs exact match comparison against the destination number
- Common codes include: "911" (US), "112" (EU), "000" (AU), "999" (UK), "sos"
How Emergency Detection Worksโ
The Tas.Dialplan.Authorization.is_emergency_call?/2 function checks two conditions:
- SIP URI Emergency Service URN: Detects
<urn:service:sos>or any URI containing "service:sos" - Destination Number Match: Compares
Caller-Destination-Numberagainst configuredemergency_call_codes
If either condition is true, the call is classified as emergency.
Code Reference: See lib/dialplan/authorization.ex
Processing Flowโ
Call Flow Details:
- Call arrives at TAS
- Authorization module checks destination against emergency patterns
- If emergency detected:
- Call type is set to
:emergency mo_emergency_dialplan.xmltemplate is used- OCS authorization is typically bypassed
- Call is routed to PSAP gateway
- Call type is set to
- Metrics are recorded with
call_type: emergencylabel
Dialplan Routingโ
Define the routing for emergency calls in priv/templates/mo_emergency_dialplan.xml. This template determines how calls are routed to your PSAP (Public Safety Answering Point) gateway or SIP URI based on your market requirements.
Example emergency dialplan:
<extension name="Emergency-SOS">
<condition field="${destination_number}" expression="^(911|912|913|sos)$">
<action application="log" data="ALERT Emergency call from ${msisdn}"/>
<action application="answer" data=""/>
<action application="bridge" data="sofia/gateway/psap_gw/${destination_number}"/>
</condition>
</extension>
Best Practicesโ
- Always include "sos" in your emergency codes list for SIP URN compatibility
- Include all local emergency numbers for your jurisdiction (e.g., 911, 112, 000, 999)
- Test emergency routing regularly using the Call Simulator
- Bypass OCS for emergency calls to ensure they always connect (configured via
skipped_regex) - Configure PSAP gateway with high availability and redundancy
- Monitor emergency call metrics to ensure system reliability
On-Net Mobile Originated call to an On-Net Mobile-Terminating Subscriberโ
You can route from your dialplan to your dialplan through something like this:
<action application="bridge" data="{absolute_codec_string=AMR-WB,AMR,PCMA,PCMU,originate_retries=1,originate_timeout=60,sip_invite_call_id=${sip_call_id}}sofia/internal/+${tas_destination_number}@10.179.3.60" />
Where 10.179.3.60 is the TAS IP (It's routing the call back to the TAS) - Just make sure the TAS IP it's in your allowed_sbc_source_ips list.