This family of templates is a pathway by which you can configure your
Asterisk server to direct outbound calls. The beauty of templates is that you can create easily-repeatable blocks of dialplan code that can be stacked and/or interchanged to create different outbound pathways based on the context in which a device is placed. For those of you who don't want the explanation, skip to
Putting it all together.
It is a method of Least Cost Routing which includes in order:
- ENUM lookup
- DUNDi lookup with local PSTN integration
- Failover to VoIP Provider(s)
The first step in the configuration is to create the outbound templates. I create a template for each possible outbound route, making it easy to mix and match for devices which should not have "full" outbound access.
The ENUM Template
[enum](!)
exten => _X.,1,Set(ARRAY(i,max)=1,${ENUMLOOKUP(+${EXTEN},ALL,c,,e164.org)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Set(uri=${ENUMLOOKUP(+${EXTEN},ALL,,${i},e164.org)})
exten => _X.,n,Exec(${IF($["${uri:0:3}" = "sip"]?Dial(SIP/${uri:4},40,KTW):NoOp(ENUM URI is not of type SIP))})
exten => _X.,n,Exec(${IF($["${uri:0:4}" = "iax2"]?Dial(IAX2/${uri:5},40,KTW):NoOp(ENUM URI is not of type IAX2))})
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
The Local PSTN & DUNDi Template
[pstn-dundi](!)
exten => _X.,n,Gosub(outbound-dundi-e164,${EXTEN},1)
Since the
DUNDi lookup is called with a Gosub to a separate context, I need to create the proper [outbound-dundi-e164] context.
[outbound-dundi-e164]
include => dundi-e164-lookup
exten => _X.,2,Return()
exten => i,1,Return()
The SIP & IAX2 Templates
These templates are identical except for the dialstrings, but I want to have separate templates so it is easy to enable/disable one or the other.
[sip](!)
exten => _X.,n,Set(ARRAY(CDR(amaflags),i,max)=BILLING,1,${FIELDQTY(SIPTRUNKS,&)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Dial(SIP/${EXTEN}@${CUT(SIPTRUNKS,&,${i})},40,KL(7200000:120000)TW)
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
[iax2](!)
exten => _X.,n,Set(ARRAY(CDR(amaflags),i,max)=BILLING,1,${FIELDQTY(IAX2TRUNKS,&)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Dial(IAX2/${CUT(IAX2TRUNKS,&,${i})}/${EXTEN},40,KL(7200000:120000)TW)
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
In [globals], I have defined the global variables "SIPTRUNKS" and IAX2TRUNKS" each listing my respective SIP or IAX2 peers in ascending order of cost per minute as follows:
SIPTRUNKS=callwithus&diamondcard&voicemeup
IAX2TRUNKS=callwithus&diamondcard
The VoIP Template
I can now very easily create another template that combines my SIP and IAX templates into one for ease of use.
[voip](sip,iax2)
Outbound Contexts
Now that the templates are configured, I can create my outbound contexts quickly and easily. The first block is defined for my devices that have full outbound access; they can dial out using ENUM, Local PSTN,
DUNDi and all of my VoIP providers. It is important to note that the templates listed after the [outbound] context marker will be copied to this context in order and before anything else defined in this context.
[outbound](enum,pstn-dundi,voip)
exten => _X.,n,Goto(exit-extensions,noroute,1)
The only exten line I place in each outbound context is one that sends the call to Allison saying "No route exists to the dialed destination" after the dialplan has exhausted all options.
[exit-extensions]
; No route to destination
exten => noroute,1,Playback(no-route-exists-to-dest&vm-goodbye)
exten => noroute,n,Hangup()
This next block is for my "guest" devices. I give these devices access to anything that doesn't cost me money!
[outbound-guest](enum,pstn-dundi)
exten => _X.,n,Goto(exit-extensions,noroute,1)
I configure calls to exit via a certain pathway by adding the following to the [context] in which my devices are registered in extensions.conf. I use the following [context] so that I can properly format the numbers prior to sending them to my [outbound] context(s).
[context]
; Define the country code and local area code before "${EXTEN}", i.e. "1773"
exten => _NXXXXXX,1,Goto(outbound,1773${EXTEN},1)
exten => _1NXXNXXXXXX,1,Goto(outbound,${EXTEN},1)
exten => _011.,1,Goto(outbound,${EXTEN:3},1)
Putting it all together
[globals]
SIPTRUNKS=callwithus&diamondcard&voicemeup
IAX2TRUNKS=callwithus&diamondcard
[context]
; FULL access devices
; Define the country code and local area code before "${EXTEN}", i.e. "1773"
exten => _NXXXXXX,1,Goto(outbound,1773${EXTEN},1)
exten => _1NXXNXXXXXX,1,Goto(outbound,${EXTEN},1)
exten => _011.,1,Goto(outbound,${EXTEN:3},1)
[context-guest]
; GUEST access devices
; Define the country code and local area code before "${EXTEN}", i.e. "1773"
exten => _NXXXXXX,1,Goto(outbound-guest,1773${EXTEN},1)
exten => _1NXXNXXXXXX,1,Goto(outbound-guest,${EXTEN},1)
exten => _011.,1,Goto(outbound-guest,${EXTEN:3},1)
[enum](!)
exten => _X.,1,GosubIf($["${directory}" != "1"]?outbound-clid,s,1)
exten => _X.,n,Set(ARRAY(i,max)=1,${ENUMLOOKUP(+${EXTEN},ALL,c,,e164.org)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Set(uri=${ENUMLOOKUP(+${EXTEN},ALL,,${i},e164.org)})
exten => _X.,n,Exec(${IF($["${uri:0:3}" = "sip"]?Dial(SIP/${uri:4},40,KTW):NoOp(ENUM URI is not of type SIP))})
exten => _X.,n,Exec(${IF($["${uri:0:4}" = "iax2"]?Dial(IAX2/${uri:5},40,KTW):NoOp(ENUM URI is not of type IAX2))})
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
[pstn-dundi](!)
exten => _X.,n,Gosub(outbound-dundi-e164,${EXTEN},1)
[sip](!)
exten => _X.,n,Set(ARRAY(CDR(amaflags),i,max)=BILLING,1,${FIELDQTY(SIPTRUNKS,&)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Dial(SIP/${EXTEN}@${CUT(SIPTRUNKS,&,${i})},40,KL(7200000:120000)TW)
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
[iax2](!)
exten => _X.,n,Set(ARRAY(CDR(amaflags),i,max)=BILLING,1,${FIELDQTY(IAX2TRUNKS,&)})
exten => _X.,n,While($["${i}" <= "${max}"])
exten => _X.,n,Dial(IAX2/${CUT(IAX2TRUNKS,&,${i})}/${EXTEN},40,KL(7200000:120000)TW)
exten => _X.,n,Set(i=${MATH(${i}+1)})
exten => _X.,n,EndWhile()
[voip](sip,iax2)
[outbound-dundi-e164]
include => dundi-e164-lookup
exten => _X.,2,Return()
exten => i,1,Return()
[exit-extensions]
; No route to destination
exten => noroute,1,Playback(no-route-exists-to-dest&vm-goodbye)
exten => noroute,n,Hangup()
[outbound](enum,pstn-dundi,voip)
exten => _X.,n,Goto(exit-extensions,noroute,1)
[outbound-guest](enum,pstn-dundi)
exten => _X.,n,Goto(exit-extensions,noroute,1)