MavEtJu's Distorted View of the World - Asterisk

Distributed telephony done properly
Asterisk Dialplan - Best practice
Asterisk - seize a trunk
Asterisk - PRI settings for Australia

Back to index

Distributed telephony done properly

Posted on 2009-10-12 19:00:00
Tags: Asterisk, Voice over IP

Recently I have been involved in the design and installation of a global VoIP telephone system and learned a few valuable lessons.

The call-flow design and requirements were as follows:

So far nothing spectacular, but the issues came when mapping calls on the network.

Normally people differentiate between internal and external calls by dialing the 0 (or 9 if you are stuck with an American based PABX, or 91 if you want to make a long distance call in the USA) before dialing the local number. After the 0, you more or less have captured a channel on the PRI and are able to call anything via that, local or national or international as long as you play via the rules of that PSTN. For example in Sydney, Australia: You can dial an eight digit local number, a ten digit local number or a ten digit national number. And if you prefix your call with a 0011, you end up on an international call.

On a distributed telephone system connected to various PSTNs, this will be a nightmare for the people to remember (0, 0011, 86 plus a string of numbers for China) which has to be translated by the PABX to +86 plus a string of numbers which has to be send to the PABX in China so it knows how to translate it back to the a China local number etc etc etc. Both a nightmare for the users and for the PABX maintainers, plus a nightmare for the travelling salesman.

So, instead of having a single prefix for an external line for a local or national call and an international call, let's split it: Prefix local or national calls with a 0 and make the international access an *. Yes, that's a * because it looks most like the international prefix +. So the PABX maintainers now know when to handle local calls and national calls.

The only tricky part is left over with the international calls, but it is less tricky than what it was. Instead of having to write a different parser for for each country to figure out when an international call is placed, they just check for the * prefix: No check of 0,0011 in Australia, an 9,011 in the USA, 0,00 in Europe, just check for the *. Next is to map of the next one, two or three numbers on the remote destination telephone system, which we just send their national call telephone number and wait for it to be connected.

So, if you have enough local offices, you will be able to call a lot of international telephone numbers for the cost of a national telephone call!

So no more 9,0011 1 415 123 4567 to call, just *1 415 123 4567! It will save money (It will be a cheap local call for the telephone system. Or a free call if the destination is a free number), it will reduce the number of buttons to press (9,0011 -> *) and it will prevent from making silly counting mistakes (missing 1 in the string of numbers to be pressed).

The whole system was implemented on the open source PABX Asterisk and a central monitoring / configuration server which kept track of which international prefixes needed to be forwarded to which telephone system. The implementation showed that its fail-safe design worked as expected when the office in Germany lost its internet connectivity for a three days and nobody complained that their calls to Germany didn't work anymore.

The overal telephone bill got reduced to 20% of the original cost, having the whole system paying for itself it as little as eleven months! (Although we still have three months to go :-)

So: Stop thinking about local calls and national calls and international calls, only think about local / national calls and international calls. Don't think about local international call prefixes, handle that on the PABX. International calls should be routed to remote PABXs which handle it locally. And only if a remote call can't be completed due to no free PRI channels or the remote PABX not being reachable, then handle it locally.


No comments | Share on Facebook | Share on Twitter

Asterisk Dialplan - Best practice

Posted on 2005-03-28 23:14:38, modified on 2006-01-09 16:29:23
Tags: Voice over IP, Asterisk

ASTERISK EXTENSIONS.CONF - BEST PRACTICE

This document describes a best practice approach to a structured and controllable design of the Asterisk extensions configuration file.

THE DESIGN

The design is as follows: There are input sources, there are dial groups and there are macros.

Input sources are places where calls are being made from. For example incoming SIP connections (authenticated or unauthenticated), calls from the PSTN and calls from the internal phone numbers.

Dial groups are destinations to be called. For example other SIP phones, calls to the PSTN, calls to internal phone numbers and calls to Asterisk applications like voicemail and conferences.

And as third, macros to reduce the amount of repetitive code.

INPUT SOURCES - part 1

The context of input sources are defined in sip.conf, iax2.conf and zapata.conf.

Sip.conf has three different contexts: The default context, to which everybody who isn't authenticated is assigned:

    [general]
    context=incoming-from-internet

People who are authenticated so they are trusted.

    [my-friend]
    context=incoming-from-friends

Iax2.conf has the same idea, but instead of putting it in the general section it's put in the guest section:

    [guest]
    context=incoming-from-internet

    [my-friend]
    context=incoming-from-friends

Zapata.conf has the definitions of ISDN channels to logical groups in it. For every group of ISDN channels you could have a different group and a different context:

    group = 1
    context = CUST1-PABX
    signalling = pri_net
    channel => 1-15,17-31

    group = 2
    context = CUST2-PABX
    signalling = pri_net
    channel => 32-46,48-62

    group = 3
    context = ME-TELCO
    signalling = pri_net
    channel => 63-77,79-93

DIAL GROUPS

Dial groups are the collections of different extension to dial. To start with, all PSTN numbers which are routed by your telco to your Asterisk server. Also all internal numbers for voicemail and conferences. And as last, a default entry for everything which is not local.

Our PSTN numbers for customers are +61 2 9210 0500 to +61 2 9210 0599 for customer 1 and +61 2 9210 0600 to +61 2 9210 0799 for customer 2. First we map the trunk to the customer onto the Zap interface, then we map the number ranges for the customers onto the customer trunks. In the dial plan we use the last mapping, so that any changes in hardware links only have to be modified in the general section. In the extensions definitions we use three versions of the number: The local number without the are code, the full national number with the area code and the international number with the country code.

    [general]
    TRUNK_CUST1= Zap/g1
    TRUNK_CUST2= Zap/g2

    TRUNK_612921005xx=${TRUNK_CUST1}
    TRUNK_612921006xx=${TRUNK_CUST2}
    TRUNK_612921007xx=${TRUNK_CUST2}

    [outgoing-customer1]
    exten => _612921005XX,1,Macro(call-int,${TRUNK_612921005xx},0${EXTEN:2})
    exten => _02921005XX,1,Macro(call-int,${TRUNK_612921005xx},${EXTEN})
    exten => _921005XX,1,Macro(call-int,${TRUNK_612921005xx},02${EXTEN})

    [outgoing-customer2]
    exten => _612921006XX,1,Macro(call-int,${TRUNK_612921006xx},0${EXTEN:2})
    exten => _02921006XX,1,Macro(call-int,${TRUNK_612921006xx},${EXTEN})
    exten => _921006XX,1,Macro(call-int,${TRUNK_612921006xx},02${EXTEN})
    exten => _612921007XX,1,Macro(call-int,${TRUNK_612921007xx},0${EXTEN:2})
    exten => _02921007XX,1,Macro(call-int,${TRUNK_612921007xx},${EXTEN})
    exten => _921007XX,1,Macro(call-int,${TRUNK_612921007xx},02${EXTEN})

The PSTN number ranges for VoIP users are +61 2 9210 081x for authenticated SIP users and +61 2 9210 080x towards a remote SIP server.

    [general]
    OTHERSIPSERVER= sip.foo.bar

    [outgoing-voip]
    exten => _6129210080X,1,Macro(call-sip-remote,${EXTEN:9}@${OTHERSIPSERVER}))
    exten => _029210080X,1,Macro(call-sip-remote,${EXTEN:8}@${OTHERSIPSERVER}))
    exten => _9210080X,1,Macro(call-sip-remote,${EXTEN:6}@${OTHERSIPSERVER}))

    exten => 61292100810,1,Macro(call-sip-local,foo,0${EXTEN:2})
    exten => 0292100810,1,Macro(call-sip-local,foo,${EXTEN})
    exten => 92100810,1,Macro(call-sip-local,foo,02${EXTEN})
    exten => 61292100811,1,Macro(call-sip-local,bar,0${EXTEN:2})
    exten => 0292100811,1,Macro(call-sip-local,bar,${EXTEN})
    exten => 92100811,1,Macro(call-sip-local,bar,02${EXTEN})

We don't want to specify all outgoing PSTN numbers, so we just use a catch-all for them:

    [general]
    TRUNK_TELCO= Zap/g3

    [outgoing-theworld]
    exten => _.,1,Macro(call-ext,${TRUNK_TELCO},${EXTEN})

And a number of tools for internal and external users on +61 2 9210 082x:

    [outgoing-tools]
    exten => 61292100820,1,MeetMe(1234|M)
    exten => 0292100820,1,MeetMe(1234|M)
    exten => 92100820,1,MeetMe(1234|M)

    exten => 61292100821,1,VoicemailMain
    exten => 61292100821,n,Hangup
    exten => 0292100821,1,VoicemailMain
    exten => 0292100821,n,Hangup
    exten => 92100821,1,VoicemailMain
    exten => 92100821,n,Hangup

    exten => *600,1,Playback(demo-echotest)
    exten => *600,n,Echo
    exten => *600,n,Playback(demo-echodone)
    exten => *600,n,Hangup

MACROS

Now we're in the section which actually does do the dialing. The following four macros are all we need: call-int, call-ext and call-sip-local and call-sip-remote.

The call-int macro calls on an internal trunk. Further call handling is done by these phone systems:

    [macro-call-int]
    exten => s,1,NoOp(Trunk:${ARG1})
    exten => s,n,NoOp(Number:${ARG2})
    exten => s,n,ChanIsAvail(${ARG1})
    exten => s,n,Cut(C=AVAILCHAN,,1)
    exten => s,n,Dial(${C}/${ARG2})
    exten => s,n,Hangup()

The call-ext macro calls on a trunk to the outside world. We need to check for dial responses like BUSY, CHANUNAVAIL and others.

    [macro-call-ext]
    exten => s,1,NoOp(Trunk:${ARG1})
    exten => s,n,NoOp(Number:${ARG2})
    exten => s,n,ChanIsAvail(${ARG1})
    exten => s,n,Cut(C=AVAILCHAN,,1)
    exten => s,n,Dial(${C}/${ARG1}) 
    exten => s,n,Goto(s-${DIALSTATUS},1)
    exten => s,n,Hangup()

    exten => s-BUSY,1,Busy()
    exten => s-BUSY,n,Hangup()
     
    exten => s-CHANUNAVAIL,1,PlayTones(congestion)
    exten => s-CHANUNAVAIL,n,Wait(5)
    exten => s-CHANUNAVAIL,n,StopPlayTones()
    exten => s-CHANUNAVAIL,n,Hangup
     
    exten => s-CONGESTION,1,PlayTones(congestion)
    exten => s-CONGESTION,n,Wait(5)
    exten => s-CONGESTION,n,StopPlayTones()
    exten => s-CONGESTION,n,Hangup
     
    exten => s-NOANSWER,1,Hangup

    exten => s-ANSWER,1,Hangup
    exten => s-CANCEL,1,Hangup

Call-sip-remote is just like call-int, but then for an SIP session:

    [macro-call-sip-remote]
    exten => s,1,Playback(pls-wait-connect-call)
    exten => s,n,Dial(SIP/${ARG1},45,r)
    exten => s,n,Hangup

And call-sip-local is like call-ext, but with better handling of failed dial attempts since we need to use voicemail there:

    [macro-call-sip-local]
    exten => s,1,NoOp(To user: ${ARG1})
    exten => s,n,NoOp(Voicemail: ${ARG2})
    exten => s,n,Dial(SIP/${ARG1},45,r)
    exten => s,n,NoOp(${DIALSTATUS})
    exten => s,n,Goto(s-${DIALSTATUS},1)
    exten => s,n,Hangup
     
    exten => s-BUSY,1,Playback(user)
    exten => s-BUSY,n,Playback(is-curntly-busy)
    exten => s-BUSY,n,Goto(s-VM,1)
     
    exten => s-NOANSWER,1,Playback(user)
    exten => s-NOANSWER,n,Playback(is-curntly-unavail)
    exten => s-NOANSWER,n,Goto(s-VM,1)
     
    exten => s-ANSWER,1,Playback(thank-you-for-calling)
    exten => s-ANSWER,n,Hangup
     
    exten => s-CHANUNAVAIL,1,Playback(is-curntly-unavail)
    exten => s-CHANUNAVAIL,n,Goto(s-VM,1)
     
    exten => s-CONGESTION,1,PlayTones(congestion)
    exten => s-CONGESTION,n,Wait(5)
    exten => s-CONGESTION,n,StopPlayTones()
    exten => s-CONGESTION,n,Goto(s-VM,1)

    exten => s-CANCEL,1,Hangup
     
    exten => s-VM,1,VoiceMail(${ARG2})
    exten => s-VM,n,Hangup

Pfioew! That's all the low level work.

INPUT SOURCES - part 2

Now it's time to glue the input source and the dial groups together. Every input source has its own definitions on which dial groups it is allowed to call.

The first group is the unauthenticated people on the internet which get routed to my Asterisk server. They are allowed to call my public PSTN numbers, but not to retrieve voicemail and do conferencing.

    [incoming-from-internet]
    include => outgoing-voip
    include => outgoing-customer1
    include => outgoing-customer2

The second group is the authenticated people on the internet which actually register at my Asterisk server. They are allowed as above, but also to retrieve voicemail and do conferencing.

    [incoming-from-friends]
    include => outgoing-tools
    include => outgoing-voip
    include => outgoing-customer1
    include => outgoing-customer2

All incoming called from the PSTN are allowed to call my public PSTN numbers and to retrieve voicemail and do conferencing.

    [ME-TELCO]
    include => outgoing-tools
    include => outgoing-voip
    include => outgoing-customer1
    include => outgoing-customer2

And the customers are allowed to call everything: public PSTN numbers, retrieve voicemail and do conferencing and make PSTN calls.

    [CUST1-PABX]
    include => outgoing-tools
    include => outgoing-voip
    include => outgoing-customer1
    include => outgoing-customer2
    include => outgoing-theworld

    [CUST2-PABX]
    include => outgoing-tools
    include => outgoing-voip
    include => outgoing-customer1
    include => outgoing-customer2
    include => outgoing-theworld

CONCLUSION

By properly defining what the input sources are, what the destination groups are and what the allowed destinations for an input source are, it is possible to have a structured, scalable and safe dial plan.


No comments | Share on Facebook | Share on Twitter

Asterisk - seize a trunk

Posted on 2004-11-28 22:37:36, modified on 2006-01-09 16:29:22
Tags: Voice over IP, Asterisk, PRI

Problem: Before switching to asterisk, it was possible for people to seize the trunk and dial out any number, and thus bypassing the numbering plan. The error you currently get is:

-- Extension '' in context 'SJH05-A4400' from '282122348' does not exist. Rejecting call on channel 3/21, span 3

Solution: In zapata.conf, add overlapdial=yes to the group definition. This will cause an additional delay of three seconds before the number is forwarded:

-- Starting simple switch on 'Zap/206-1'
-- Accepting overlap call from '293312303' to '<unspecified>' on channel 7/20, span 7
-- Executing Dial("Zap/206-1", "Zap/g8/95212347||") in new stack

No comments | Share on Facebook | Share on Twitter

Asterisk - PRI settings for Australia

Posted on 2004-11-10 23:28:07, modified on 2006-01-09 16:29:22
Tags: Voice over IP, Asterisk, PRI

To connect an TE410P / TE405P card to the australian PSTN, use the following settings:

In /etc/zaptel.conf:

span=1,1,0,ccs,hdb3,crc4
bchan=1-15,17-21
dchan=16
unused=22-31

The 1 in span means that you use the clock from their network.

Please note that this is for an OnRamp20, which has 20 B-channels. With an OnRamp10 you need only channels 1-10 and modify unused too.

In /etc/asterisk/zapata.conf, use:

[trunkgroups]
trunkgroup => 1,16
spanmap => 1,1,1

[channels]
group = 1
context=PRI-Telstra
switchtype=national
pridialplan=unknown
prilocaldialplan=unknown
signalling = pri_cpe
channel => 1-15,17-21

No comments | Share on Facebook | Share on Twitter