Skip to main content

Chapter 14: Dialplan Application Reference

This chapter is a reference for the dialplan applications you invoke with <action application="..." data="..."/> inside an extension condition. It covers every application registered by mod_dptools, which provides the core call-control, audio, DTMF, variable, and logging applications. A handful of these are advanced or internal helpers (for example park_state, acknowledge_call, recovery_refresh, reuse_caller_profile, set_media_stats, capture_text, vad_test, and the video_* overlay apps) that operators rarely call directly; they are included here for completeness and noted as such. Applications provided by companion modules (mod_conference, mod_voicemail, mod_fifo, mod_valet_parking, mod_hash, mod_db, mod_lua, mod_spy, mod_esf, mod_fsv) are covered in the Feature Applications section; those modules must be loaded before the applications become available.

Call Control

These applications establish, route, and tear down call legs. They operate directly on the signaling and media state of the channel.

ApplicationPurposeArguments
answerAnswer the channel, completing the SIP 200 OK handshake and allocating media.None
pre_answerSend a 183 Session Progress with SDP, enabling early media before a full answer.None
ring_readySend a 180 Ringing response to the caller without opening an early media path.None
hangupTerminate the channel with an optional Q.850 cause.[<cause>] -- e.g., NORMAL_CLEARING, USER_BUSY
bridgeBridge the current channel to one or more outbound channel URLs.<channel_url> -- full dial string, e.g., sofia/internal/1001@example.com
transferImmediately transfer the calling channel to a new extension in the dialplan.<exten> [<dialplan> <context>]
interceptPull a ringing or parked channel identified by UUID into the current call.[-bleg] <uuid>
holdSend a SIP re-INVITE or UPDATE placing the remote party on hold.[<display message>]
unholdRelease a previously placed hold.None
parkPark the channel, suspending bridging and allowing the call to wait.None
respondSend a raw SIP response code to the session.<code> [<text>] -- e.g., 407 Proxy Authentication Required
deflectSend a SIP REFER to redirect the call to another URI.<sip-uri>
redirectSend a SIP 3xx redirect response to the session.<redirect_data>
sleepPause channel execution for a specified duration, consuming audio during the pause.<milliseconds>
wait_for_silenceBlock until audio drops below a threshold, used to detect end-of-speech.<silence_thresh> <silence_hits> <listen_hits> <timeout_ms> [<file>]
execute_extensionJump to a named extension in a dialplan context and return when it completes.<extension> <dialplan> <context>
att_xferInitiate an attended transfer by calling a second party before handing off.<channel_url>
soft_holdPlace a bridged channel on hold without a full re-INVITE.<unhold_key> [<moh_a>] [<moh_b>]
pickupPick up a channel that is ringing on a named pickup group.<key>
check_aclEvaluate an IP address against a named ACL; terminate or continue based on the result.<ip> <acl_name>
set_nameAssign a human-readable name to the channel, visible in logs and event data.<name>
early_hangupEnable early hangup so the channel can be torn down before full media is established.None
media_resetReset all bypass and proxy media flags to their defaults.None
wait_for_answerBlock dialplan execution on the originating leg until the called party answers.None
wait_for_video_readyBlock until the video stream on the channel is ready.[<ms>] -- timeout in milliseconds (1 to 10000)
blind_transfer_ackAcknowledge or reject a blind transfer request on the channel.[true|false]
pagePage a list of channels simultaneously by dialing them and playing a file. The file path and optional variables are passed before the channel list.[<var1=val1,var2=val2>]<chan1>[:_:<chanN>]
park_stateTrigger the park state machine on the channel, used internally after the park application.None
acknowledge_callIndicate that the call has been acknowledged (used by endpoints that signal call acknowledgement separately from ringing or answer).None
breakSet the break flag on the channel, interrupting any in-progress playback or digit collection. If a broadcast is active it is stopped instead. Pass all to also flush queued private events.[all]
recovery_refreshSend a recovery-refresh indication to the channel, used during call recovery to re-sync endpoint state.None
reuse_caller_profileSet the channel flag that causes the existing caller profile to be reused rather than rebuilt, typically before a transfer or execute_extension.None
set_media_statsSnapshot the current RTP media statistics into channel variables (rtp_audio_*, etc.) for the current state of the media.None

Scheduling Applications

These schedule deferred actions on the channel.

ApplicationPurposeArguments
sched_hangupSchedule a hangup after a delay.[+]<time_sec> [<cause>]
sched_transferSchedule a transfer after a delay.[+]<time_sec> <exten> [<dialplan> <context>]
sched_broadcastSchedule a file broadcast after a delay.[+]<time_sec> <path> [<leg>]
sched_cancelCancel a previously scheduled action by group name.[group]
sched_heartbeatEnable a scheduled heartbeat event on the channel.[<seconds>]

Audio and Prompts

These applications play, record, and generate audio on the channel. They require an answered (or at minimum early-media) channel unless stated otherwise.

ApplicationPurposeArguments
playbackPlay an audio file or stream to the channel. Stops on DTMF by default unless playback_terminators is cleared.<path> -- filesystem path, tone_stream://..., silence_stream://..., etc.
endless_playbackPlay a file in an infinite loop until the channel is terminated externally.<path>
broadcastPlay a file to a specific leg of a bridged call without interrupting the other leg.<path> <leg> -- leg is aleg, bleg, or both
gentonesGenerate TGML tones to the channel.<tgml_script>[|<loops>] -- e.g., %(1000,0,350,440)
play_and_get_digitsPlay a prompt, collect DTMF digits, validate against a regex, and store in a variable.<min> <max> <tries> <timeout_ms> <terminators> <file> <invalid_file> <var_name> <regexp> [<digit_timeout>] ['<failure_ext> [failure_dp [failure_context]]']
readPlay a file and collect a fixed range of digits into a channel variable.<min> <max> <file> <var_name> <timeout_ms> <terminators> [<digit_timeout>]
sayUse the language module to speak values such as numbers, dates, and currency in the channel's language.<module_name>[:<lang>] <say_type> <say_method> [<say_gender>] <text>
speakSynthesize text to speech via a TTS engine.<engine>|<voice>|<text>
phraseExecute a named phrase macro defined in the phrases XML configuration.<macro_name>,<data>
recordRecord audio from the channel input into a file. Stops on silence or a DTMF terminator.<path> [<time_limit_secs>] [<silence_thresh>] [<silence_hits>]
record_sessionStart a background recording of the full bridged session (both legs) to a file.<path> [+<timeout_sec>]
stop_record_sessionStop a background session recording started by record_session.<path>
record_session_maskReplace audio in an active recording with silence to mask a sensitive region.<path>
record_session_unmaskResume normal audio capture in a recording after masking.<path>
record_session_pauseTemporarily pause writing audio to a session recording file.<path>
record_session_resumeResume a paused session recording.<path>
displace_sessionReplace the channel's audio input with audio from a file or stream.<path> [<flags>] [+<time_limit_ms>]
stop_displace_sessionStop a displace session started by displace_session.<path>
detect_speechStart ASR speech detection on the channel using a grammar and ASR engine, or send a control keyword to an already-running detector.<mod_name> <gram_name> <gram_path> [<addr>] to start, or one of the control keywords: grammar <name> [<path>], nogrammar <name>, grammaron <name>, grammaroff <name>, grammarsalloff, pause, resume, start-input-timers, init <name> <path>, stop, param <name> <value>
play_and_detect_speechPlay a prompt while simultaneously running ASR speech detection.<file> detect:<engine> {<params>}<grammar>
echoEcho audio back to the caller; used for latency testing.None
delay_echoEcho audio back to the caller with a configurable delay in milliseconds.<delay_ms>
tone_detectDetect a named tone on the channel and execute an action when found.<key> <freqs> [<flags> [<timeout>] [<app>] [<data>] [<hits>]]
fax_detectDetect an inbound fax CED tone and execute an action.None (uses channel variables for action)
stop_tone_detectStop active tone detection on the channel.None
loop_playbackPlay a file a fixed number of times. A + prefix on the loop count is accepted.[+<loops>] <path>
detect_audioBlock until audio energy exceeds a threshold, used to detect the start of speech or a tone.<threshold> <audio_hits> <timeout_ms> [<file>]
detect_silenceBlock until audio energy drops below a threshold for a number of consecutive frames.<threshold> <silence_hits> <timeout_ms> [<file>]
preprocessApply a DSP pre-processing filter to the channel's read audio.<filter_string>
sound_testRun an audio analysis pass on the channel and log the results.None
clear_speech_cacheClear the cached TTS/ASR speech handles on the channel, forcing the next speak or detect_speech to re-initialize its engine.None
capture_textCapture inbound text (T.140/MSRP real-time text) on the channel into the channel's text buffer. Pass a truthy value to enable capture.[true|false]
vad_testRun the Voice Activity Detector against the channel's read audio and log talk/silence transitions, for tuning VAD parameters. The mode selects sensitivity. The vad_debug, vad_silence_ms, and related channel variables tune behavior.[<mode>] -- -1 (default), 0, 1, 2, or 3

DTMF and Signaling

These applications control how DTMF is detected, generated, and transmitted. Inband detection (start_dtmf) is required when the endpoint does not send RFC 2833 telephone-event packets.

ApplicationPurposeArguments
start_dtmfEnable inband DTMF detection on the session using DSP.None
stop_dtmfStop inband DTMF detection previously started with start_dtmf.None
start_dtmf_generateGenerate inband DTMF audio for outbound DTMF events on the session.None
stop_dtmf_generateStop inband DTMF generation.None
send_dtmfSend DTMF digits on the channel immediately.<dtmf_digits>[@<duration_ms>] -- e.g., 1234 or 1234@500
queue_dtmfQueue DTMF digits to be sent after the current audio completes.<dtmf_digits>[@<duration_ms>]
flush_dtmfDiscard any DTMF digits buffered in the channel's input queue.None
send_infoSend a SIP INFO message on the session.<info_data>
send_displaySend an updated caller-ID name and number to the remote party via SIP INFO or re-INVITE.<name>|<number>
block_dtmfBlock DTMF digits from being passed through the channel.None
unblock_dtmfRe-enable DTMF passthrough after block_dtmf.None
deduplicate_dtmfSuppress duplicate DTMF events when both inband and RFC 2833 are received.[only_rtp]
privacySet caller privacy flags on the outbound leg.off|on|name|full|number
presenceSend a SIP presence update for the channel.<rpid> <status> [<id>]
bind_digit_actionBind a digit sequence or regex to a dialplan action string within a named realm. Unlike bind_meta_app, this does not require a * prefix and works outside of a bridge.<realm>,<digits|~regex>,<string>[,<value>][,<dtmf_target_leg>][,<event_target_leg>]
clear_digit_actionClear all digit action bindings in a realm, or all realms.<realm>|all[,target]
digit_action_set_realmChange the active digit action realm on the channel.<realm>[,<target>]

Feature Applications

These applications are registered by companion modules. Each module must be loaded in modules.conf.xml for the application to be available.

Conferencing (mod_conference)

The conference application and its configuration are covered in detail in the Conferencing chapter.

ApplicationPurposeArguments
conferencePlace the channel into a named conference room. The room is created if it does not exist; it is destroyed when the last participant leaves.<room_name>[@<profile>][+flags{<flag1>|<flag2>}]
conference_set_auto_outcallRegister an outbound call URL to be dialed automatically when the conference starts.<channel_url>

Voicemail (mod_voicemail)

The voicemail application and its configuration are covered in detail in the Voicemail chapter.

ApplicationPurposeArguments
voicemailDeliver a call to a voicemail box, or enter the mailbox check menu.[check] [auth] <profile_name> <domain_name> [<id>] [uuid]

FIFO Queuing (mod_fifo)

The fifo application and its configuration are covered in detail in the Queues: FIFO and Call Center chapter.

ApplicationPurposeArguments
fifoPlace an inbound call into a named FIFO queue (in) or connect an agent to the next waiting caller (out).<fifo_name>[!<importance>] [in [<announce>|undef] [<music>|undef] [early|noans] | out [wait|nowait] [<announce>|undef] [<music>|undef]]

Valet Parking (mod_valet_parking)

The valet_park application and its configuration are covered in detail in the Utility Applications chapter.

ApplicationPurposeArguments
valet_parkPark a call in a named lot at a specific slot, or retrieve a parked call. Supports interactive slot selection with ask and automatic slot assignment with auto.<lot_name> <extension>|[ask [<min>] [<max>] [<timeout>] [<prompt>]|auto [in|out] [min] [max]]

In-Memory Hash Table (mod_hash)

ApplicationPurposeArguments
hashInsert, conditionally insert, delete, or conditionally delete a key-value pair in the shared in-memory hash table. Values survive across calls until the module is reloaded.[insert|insert_ifempty|delete|delete_ifmatch]/<realm>/<key>/<val>

SQLite Key-Value Store (mod_db)

ApplicationPurposeArguments
dbInsert or delete a key-value pair in the persistent SQLite-backed key-value store. Values survive restarts.[insert|delete]/<realm>/<key>/<val>

IVR Menu (mod_dptools)

ApplicationPurposeArguments
ivrRun a named IVR menu defined in ivr_menus.conf.xml.<menu_name>

Lua Scripting (mod_lua)

ApplicationPurposeArguments
luaExecute a Lua script in the context of the current call channel.<script_path> [<args>]

Call Limiting (mod_dptools)

ApplicationPurposeArguments
limitEnforce a maximum concurrent call count for a realm/id pair using a pluggable backend (db or hash). Optionally transfer to a failure extension when the limit is exceeded.<backend> <realm> <id> [<max>[/<interval_sec>]] [<number> [<dialplan> [<context>]]]
limit_hashSame as limit but uses the hash backend directly, omitting the backend argument.<realm> <id> [<max>[/<interval_sec>]] [<number> [<dialplan> [<context>]]]
limit_executeExecute a dialplan application only when under the resource limit; does not transfer on failure. Uses a pluggable backend.<backend> <realm> <id> <max>[/<interval>] <application> [<app_args>]
limit_hash_executeDeprecated alias for limit_execute hash. Uses the hash backend.<realm> <id> <max>[/<interval>] <application> [<app_args>]

Eavesdrop (mod_dptools)

ApplicationPurposeArguments
eavesdropMonitor an active channel by UUID. The operator hears both legs; DTMF 1/2/3 cycles which leg is heard, 0 listens to both simultaneously, * skips to next channel. Pass all to cycle through all active channels.[all|<uuid>]
native_eavesdropEavesdrop on a channel at the native (transport) layer, targeting a specific read or write stream. Lower overhead than eavesdrop when only one direction is needed.<uuid> [read|write]
interceptRedirect a ringing or held channel identified by UUID to the current call, completing the answer.[-bleg] <uuid>

User Spy (mod_spy)

ApplicationPurposeArguments
userspyContinuously eavesdrop on all calls to a specific directory user. Cycles automatically as the user starts new calls. mod_spy must be loaded.<user@domain> [uuid]

Multicast Paging (mod_esf)

ApplicationPurposeArguments
esf_page_groupSend an RTP multicast page to all devices subscribed to the multicast group configured in mod_esf. mod_esf must be loaded.None (uses channel variables for group config)

FSV Video Recording (mod_fsv)

ApplicationPurposeArguments
record_fsvRecord both audio and video to an FSV container file. mod_fsv must be loaded.<path>
play_fsvPlay an FSV container file (audio and video) to the channel. mod_fsv must be loaded.<path>

Variables, Logging, and Meta-binding

These applications read and write channel variables, write to the log, and bind DTMF keys to mid-call actions.

Channel Variables

ApplicationPurposeArguments
setSet a channel variable. The variable is scoped to the current channel.<varname>=<value>
multisetSet multiple channel variables in a single call. Uses space as the default delimiter; use ^^<char> to specify an alternate delimiter.[^^<delim>]<var1>=<val1> <var2>=<val2> ...
unsetDelete a channel variable.<varname>
multiunsetDelete multiple channel variables in a single call.[^^<delim>]<var1> <var2> ...
set_globalSet a global variable visible to all channels and persisted for the life of the process.<varname>=<value>
set_profile_varSet a field on the caller profile (e.g., caller_id_name, caller_id_number).<field>=<value>
exportSet a channel variable and propagate it to the B-leg when a bridge is established.<varname>=<value>
bridge_exportSame as export, but only copies the variable to bridged legs without setting it on the current channel.<varname>=<value>
pushAppend a value to a channel variable that holds a colon-separated list.<varname>=<value>
unshiftPrepend a value to a channel variable that holds a colon-separated list.<varname>=<value>
transfer_varsCopy a matching variable or prefix group from the current channel to its bridged partner. Prefix the name with ~ to match all variables starting with that string.<~variable_prefix|variable>

Logging and Diagnostics

ApplicationPurposeArguments
logWrite a string to the FreeSWITCH log at the specified level.<log_level> <log_string> -- levels: DEBUG, INFO, NOTICE, WARNING, ERR, CRIT, ALERT
infoDump all channel variables and call metadata to the log at INFO level.None
eventFire a custom FreeSWITCH event on the event socket.<key>=<value> [<key>=<value> ...]
verbose_eventsMake all subsequent events on this channel verbose (include all variables).None
session_loglevelOverride the per-session log verbosity.<log_level>

DTMF Meta-binding

bind_meta_app lets the operator bind a DTMF digit (preceded by *) pressed during a bridged call to a dialplan application, without interrupting the media stream.

ApplicationPurposeArguments
bind_meta_appBind a digit key to an application. The key is triggered when *<key> is pressed during a bridge.<key> [a|b|ab] [a|b|o|s|i|1] <app>[::args]
unbind_meta_appRemove a meta-app binding by key.[<key>]

The second argument selects which leg detects the keypress (a, b, or ab). The third argument selects the execution scope: a = a-leg, b = b-leg, o = opposite leg, s = self, i = inline, 1 = once.

Miscellaneous Utilities

ApplicationPurposeArguments
evalEvaluate an expression and discard the result. Used as a no-op placeholder or to force variable expansion.Any string
stopAlias for eval. Acts as a no-op that can be used to terminate an action list.None
strftimeFormat a time value using strftime(3) and store or log the result.[<epoch>|]<format_string>
mkdirCreate a directory on the filesystem.<path>
renameRename a file on the filesystem.<old_path> <new_path>
mutexBlock execution of this call flow until no other channel holds the same mutex key. Optionally pass on or off to explicitly acquire or release.<keyname> [on|off]
captureCapture data matched by a regex into a named channel variable.<varname>=<regex>
set_userApply directory user settings (variables, parameters) to the channel from the directory.<user>@<domain> [prefix]
filter_codecsRemove codecs from the current SDP that do not match a filter pattern.See source for full syntax.
jitterbufferEnable or configure the RTP jitter buffer on the session.<msec>[:max_msec[:max_drift]] or off
novideoRefuse or strip inbound video from the session.None
video_refreshRequest a video keyframe refresh from the remote party, or switch the refresh mode. With no argument it sends an immediate refresh request; manual suppresses automatic refreshes, auto restores them.[manual|auto]
video_decodeEnable or disable full decoding of the inbound video stream (needed for media bugs such as overlays). on enables decoding, wait enables decoding and blocks until input video parameters are known, off disables it.[[on|wait]|off]
video_write_overlayOverlay a static image (e.g., a PNG with alpha) onto the channel's outbound video stream. Requires the video stream to be decoded.<path> [<pos>] [<alpha>] -- <pos> is an image position keyword (e.g., left-bot); <alpha> is 1-255
stop_video_write_overlayRemove a video overlay previously applied with video_write_overlay.<path>
set_audio_levelAdjust the read or write audio level on the channel.[read|write] <level>
set_muteMute or unmute the read or write leg of the channel.[read|write] [true|false|toggle]
remove_bugsRemove all or a named set of media bugs from the channel.[<function>]
three_wayBridge a third party into a call by UUID, creating a three-way audio mix.<uuid>
cng_plcEnable Packet Loss Concealment on Comfort Noise Generation frames received from the remote party.None
enable_heartbeatEnable a periodic media heartbeat event on the channel, optionally setting the interval. Set to 0 to disable.[0|<seconds>]
enable_keepaliveEnable RTP keepalive packets on the channel to maintain NAT bindings. Set to 0 to disable.[0|<seconds>]
set_zombie_execAllow the channel to continue executing dialplan applications after the call has been answered and the originating state machine has exited.None
debug_mediaEnable or disable media debugging output on the channel for a specific stream direction.<read|write|both|vread|vwrite|vboth|all> <on|off>
systemExecute a system shell command synchronously. Only available when disable_system_app_commands is not set to true.<command>
bgsystemExecute a system shell command asynchronously. Only available when disable_system_app_commands is not set to true.<command>

Examples

The following examples are drawn from the vanilla FreeSWITCH dialplan (default.xml and features.xml).

Answer, bridge, and fall back to voicemail

<extension name="Local_Extension">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="export" data="dialed_extension=$1"/>
<action application="set" data="call_timeout=30"/>
<action application="set" data="hangup_after_bridge=true"/>
<action application="set" data="continue_on_fail=true"/>
<action application="bridge" data="user/${dialed_extension}@${domain_name}"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
</condition>
</extension>

Bind meta-app keys to mid-call features

<action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<action application="bind_meta_app" data="2 b s record_session::${recordings_dir}/${caller_id_number}.wav"/>
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>

Intercept a ringing channel by UUID

<extension name="global-intercept">
<condition field="destination_number" expression="^886$">
<action application="answer"/>
<action application="intercept" data="${hash(select/${domain_name}-last_dial_ext/global)}"/>
<action application="sleep" data="2000"/>
</condition>
</extension>

Place a call into a conference room

<extension name="nb_conferences">
<condition field="destination_number" expression="^(30\d{2})$">
<action application="answer"/>
<action application="conference" data="$1-${domain_name}@default"/>
</condition>
</extension>

Park a call in a FIFO queue and retrieve it

<!-- Park -->
<extension name="park">
<condition field="destination_number" expression="^5900$">
<action application="set" data="fifo_music=${hold_music}"/>
<action application="fifo" data="5900@${domain_name} in"/>
</condition>
</extension>

<!-- Retrieve -->
<extension name="unpark">
<condition field="destination_number" expression="^5901$">
<action application="answer"/>
<action application="fifo" data="5900@${domain_name} out nowait"/>
</condition>
</extension>

Read digits and transfer

<extension name="dx">
<condition field="destination_number" expression="^dx$">
<action application="answer"/>
<action application="read" data="11 11 'tone_stream://%(10000,0,350,440)' digits 5000 #"/>
<action application="execute_extension" data="is_transfer XML features"/>
</condition>
</extension>

Valet parking

<!-- Park a call interactively -->
<extension name="valet_park">
<condition field="destination_number" expression="^(6000)$">
<action application="answer"/>
<action application="valet_park" data="valet_parking_lot ask 1 11 10000 ivr/ivr-enter_ext_pound.wav"/>
</condition>
</extension>

<!-- Park or retrieve by slot number (6001-6099) -->
<extension name="valet_park">
<condition field="destination_number" expression="^((?!6000)60\d{2})$">
<action application="answer"/>
<action application="valet_park" data="valet_parking_lot $1"/>
</condition>
</extension>

Log a warning and send a custom SIP response

<action application="log" data="WARNING Call from ${caller_id_number} exceeded limit"/>
<action application="respond" data="503 Service Unavailable"/>

Eavesdrop on all active channels

<extension name="eavesdrop">
<condition field="destination_number" expression="^779$">
<action application="answer"/>
<action application="set" data="eavesdrop_indicate_failed=tone_stream://%(500,0,320)"/>
<action application="set" data="eavesdrop_indicate_new=tone_stream://%(500,0,620)"/>
<action application="set" data="eavesdrop_indicate_idle=tone_stream://%(250,0,920)"/>
<action application="eavesdrop" data="all"/>
</condition>
</extension>

Dial Strings and Call Origination

A dial string is the argument passed to bridge, originate, and gateway destination fields. It describes one or more outbound legs to create, using endpoint prefixes, optional per-leg or global channel variables, and multi-leg separators. The parsing logic resides in switch_ivr_originate.c.

Endpoint Prefixes

Every leg in a dial string begins with an endpoint prefix that selects the channel driver. The prefix is separated from the address by a forward slash.

PrefixMeaningExample
user/<u>@<d>Look up user <u> in domain <d> in the directory and dial the dial-string param from that user's profile. Domain is optional; defaults to the configured default domain.user/1001@example.com
sofia/<profile>/<uri>Dial a SIP URI directly via the named sofia profile.sofia/internal/1001@192.168.1.10
sofia/gateway/<gw>/<number>Dial <number> through the named gateway. The gateway must be registered under any loaded sofia profile.sofia/gateway/mycarrier/15551234567
loopback/<exten>[/<context>[/<dialplan>]]Re-enter the dialplan at <exten> in <context> (default default) using <dialplan> (default xml). Also accepts loopback/app=<app>[:<arg>] to execute a specific application.loopback/1001/default
group/<name>@<domain>Dial all members of a directory group simultaneously, using each member's dial-string.group/support@example.com
error/<cause>Immediately return the named Q.850 hangup cause without placing any call. Useful as a fallback leg.error/USER_BUSY
pickup/<key>Register the originating call into a named pickup group and wait. Any party that runs the pickup app with the same key will intercept the call.pickup/sales

Multi-leg Separators

A single dial string argument may describe multiple legs. Two separators control how those legs are dialed.

SeparatorBehaviorWhere parsed
, (comma)Simultaneous (parallel) originate. All legs separated by commas within one group are dialed at the same time; the first to answer wins.switch_separate_string with ',' inside each pipe-separated group
| (pipe character)Sequential (failover) originate. Groups separated by the pipe character are tried in order; the next group is attempted only if every leg in the current group fails or times out.switch_separate_string with '|' at the top level
:_:Enterprise parallel originate (SWITCH_ENT_ORIGINATE_DELIM). Each leg separated by :_: is dispatched in its own thread concurrently, with independent ringback and timeout tracking. Use when the legs may have very different media behavior.Detected by strstr before any other parsing; routes to switch_ivr_enterprise_originate

Precedence. The string is first tested for :_:. If found, the enterprise originate path handles it. Otherwise the string is split by the pipe character into sequential groups, and each group is split by commas into simultaneous legs.

Channel Variable Syntax

Variables can be injected into a dial string at two scopes.

Global variables {key=val,key2=val2} -- prefixed before the first leg address, inside curly braces. These variables are applied to every leg in the entire dial string. Multiple sets of curly braces are allowed and merged in order. Parsed by switch_event_create_brackets with { and } as delimiters.

{ignore_early_media=true,origination_caller_id_number=5550000}sofia/internal/1001@pbx.example.com

Per-leg variables [key=val,key2=val2] -- prefixed immediately before the address of a single leg, inside square brackets. These variables apply only to the leg they precede and override any global variable with the same name for that leg only. Parsed by switch_event_create_brackets with [ and ] as delimiters.

[leg_timeout=10]sofia/internal/1001@pbx.example.com,[leg_timeout=20]sofia/internal/1002@pbx.example.com

Multiple [...] blocks may precede a single leg address; they are merged left to right.

Combined example. Global variable sets call timeout for all legs; per-leg variables override the timeout for individual legs.

{call_timeout=30}[leg_timeout=10]sofia/internal/1001@pbx,[leg_timeout=20]sofia/internal/1002@pbx

Worked bridge Examples

Failover: gateway first, then voicemail

Try the PSTN gateway for 30 seconds. If it fails, loop back into the dialplan and drop the caller into voicemail. continue_on_fail=true is required for the dialplan to continue after a failed bridge.

<extension name="outbound_with_voicemail_fallback">
<condition field="destination_number" expression="^(15551234567)$">
<action application="set" data="continue_on_fail=true"/>
<action application="set" data="call_timeout=30"/>
<action application="bridge" data="sofia/gateway/mycarrier/$1"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="bridge" data="loopback/app=voicemail:default ${domain_name} 1000"/>
</condition>
</extension>

Simultaneous ring of two users

Ring user/1001 and user/1002 at the same time. The first to answer is bridged; the other leg is hung up automatically.

<action application="bridge" data="user/1001@${domain_name},user/1002@${domain_name}"/>

Sequential failover with simultaneous ring

Ring 1001 and 1002 simultaneously. If both fail, try the gateway. The pipe character separates the two groups.

<action application="bridge"
data="user/1001@${domain_name},user/1002@${domain_name}|sofia/gateway/mycarrier/15559990000"/>

Call Transfers and Feature Codes

Blind Transfer: the transfer Application

transfer immediately redirects the current channel to a new dialplan extension without consulting the destination first. The caller is transferred and the current dialplan execution ends.

<action application="transfer" data="<exten> [<dialplan> <context>]"/>

Optional flags modify which leg is transferred:

  • -bleg <exten> [<dialplan> <context>] -- transfer the B-leg (called party) instead of the A-leg.
  • -both <exten> [<dialplan> <context>] -- transfer both legs independently to the same extension.

These flags are verified in transfer_function in mod_dptools.c.

Attended Transfer: att_xfer

att_xfer initiates an attended transfer. It puts the current B-leg on soft hold, dials the transfer target, bridges the operator to the target for consultation, and then completes the transfer when the operator hangs up.

<action application="att_xfer" data="<channel_url>"/>

The <channel_url> argument accepts any valid dial string (e.g., user/1002@${domain_name}).

DTMF keys during consultation. Three channel variables control what DTMF digits the operator presses while bridged to the transfer target:

VariableDefaultEffect
attxfer_cancel_key#Abort the transfer; return to the original B-leg.
attxfer_hangup_key*Hang up the transfer target and complete the transfer by bridging the original A-leg and B-leg directly.
attxfer_conf_key0Convert to a three-way call by conferencing all three parties.

Set these on the channel before calling att_xfer, or set them on the transfer target leg using per-leg variable syntax.

Result variable. After att_xfer completes, the channel variable att_xfer_result is set to success or failure (SWITCH_ATT_XFER_RESULT_VARIABLE in switch_types.h).

Vanilla dialplan binding. In features.xml, the att_xfer extension collects a digit sequence with read, sets origination_cancel_key on the originate call (note: this is the variable checked by originate, not by att_xfer itself; the att_xfer cancel key is attxfer_cancel_key), then calls att_xfer:

<extension name="att_xfer">
<condition field="destination_number" expression="^att_xfer$">
<action application="read" data="3 4 'tone_stream://%(10000,0,350,440)' digits 30000 #"/>
<action application="set" data="origination_cancel_key=#"/>
<action application="att_xfer" data="user/${digits}@$${domain}"/>
</condition>
</extension>

Three-way Calling: three_way

three_way bridges a third party UUID into the current call, creating a three-way audio mix using the existing bridged legs plus the channel identified by UUID. All three parties hear each other.

<action application="three_way" data="<uuid>"/>

The UUID must be an active session. The application is registered in mod_dptools.c.

Call Pickup

Pickup groups allow a ringing call to be answered by any party in a group. The mechanism uses two sides:

Registering a call into a group. Include pickup/<key> as one of the legs in a bridge dial string. When the bridge is established, the call is registered in the named pickup group using an in-memory hash. The pickup leg waits silently until claimed.

<action application="bridge"
data="user/${dialed_extension}@${domain_name},pickup/${called_party_callgroup}@${domain_name}"/>

Claiming a ringing call. The pickup application retrieves the first available call registered under the named key and bridges it to the current channel.

<action application="pickup" data="<key>"/>

Intercepting by UUID. The intercept application pulls any ringing or held channel into the current call by its UUID.

<action application="intercept" data="[-bleg] <uuid>"/>

The -bleg flag intercepts the B-leg of the identified session rather than the A-leg. The intercept: prefix is also used internally by mod_sofia when handling SIP REFER with Replaces headers, routing calls as answer,intercept:<uuid>.

In-call Feature Codes via bind_meta_app

bind_meta_app binds a single DTMF digit (pressed as *<digit> during a bridge) to a dialplan application without interrupting the media stream. Bindings are set before the bridge call and remain active for the duration of the bridge.

Syntax recap (from Section 5):

bind_meta_app <key> [a|b|ab] [a|b|o|s|i|1] <app>[::args]
  • Argument 2: which leg detects the keypress. a = A-leg only, b = B-leg only, ab = both.
  • Argument 3: which leg executes the app. a = A-leg, b = B-leg, o = opposite leg, s = same leg, i = inline (current thread), 1 = once (remove binding after first trigger).

Vanilla bindings from default.xml. The Local_Extension extension sets these four bindings before every bridge:

KeypressBindingEffect
*1execute_extension::dx XML featuresPrompt the B-leg caller to enter a number for a blind transfer.
*2record_session::<path>.wavStart recording the session to a timestamped file.
*3execute_extension::cf XML featuresTransfer both legs to a conference room.
*4execute_extension::att_xfer XML featuresInitiate an attended transfer from the B-leg.

All four use b s (B-leg detects, same-leg executes).

Worked Example: Bridged Call with Feature Codes

The following extension replicates the vanilla Local_Extension pattern. It binds four in-call feature codes, then bridges to the dialed user. On failure it falls through to voicemail.

<extension name="Local_Extension">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="export" data="dialed_extension=$1"/>

<!-- Feature code bindings active during the bridge -->
<action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<action application="bind_meta_app" data="2 b s record_session::${recordings_dir}/${caller_id_number}.wav"/>
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<action application="bind_meta_app" data="4 b s execute_extension::att_xfer XML features"/>

<action application="set" data="call_timeout=30"/>
<action application="set" data="hangup_after_bridge=true"/>
<action application="set" data="continue_on_fail=true"/>

<!-- Primary bridge; includes a pickup group leg for call-pickup by colleagues -->
<action application="bridge" data="user/${dialed_extension}@${domain_name}"/>

<!-- Fallback: voicemail -->
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
</condition>
</extension>

When a bridged B-leg party presses *4, execute_extension::att_xfer XML features runs in the features context. That extension collects a destination number with read, then calls att_xfer to consult the transfer target. The operator presses # (default attxfer_cancel_key) to abort, * (default attxfer_hangup_key) to complete the transfer, or 0 (default attxfer_conf_key) to merge all three parties.