Asterisk configuration

Peter Dordal, Loyola University CS Dept

Let's start with definitions for channels, SIP channels in particular. These are the actual paths that connections come in and go out over. Each analog phone line (FSX/FSO interface) represents a channel. A T1 line is a set of 24 voice (DS0) channels. Networks tend to allow better multiplexing.

In Asterisk, SIP channels are defined in the file sip.conf. Channels over the Internet are effectively synonymous with call endpoints. A connected phone call is the connection of two channels (ignoring, for the moment, conference calls, which actually work slightly differently).

First, here's a sample config file for the cisco phone
[cisphone001]
deny=0.0.0.0/0.0.0.0

permit=147.126.0.0/255.255.0.0 ;; what IP addresses we will accept
secret=MyP@ssW3rd ;; the SIP-authentication cleartext password
dtmfmode=rfc2833 ;; signaling method for touchtone buttons
canreinvite=yes ;; issue in SIP protocol
context=default ;; what context in extensions.conf we go to for incoming calls
host=dynamic ;; phone gets different IP addr depending on where it is plugged in
;; consequence: phone will contact Asterisk
type=friend ;; match incoming calls on both IP addr & SIP header info
nat=force_rport,comedia ;; can we be behind a firewall? (formerly "nat=yes")
port=5060 ;; default SIP port
callerid=device <312-915-7980>
The nat=force_rport,comedia setting is for phones behind a NAT router, and influences the way SIP handles connections. The "force_rport" causes the Asterisk server to use the "rport" mechanism of RFC 3581: the server will send replies back to the port from which they came, rather than attempting to use the port number embedded in the data. The comedia request enables "symmetric RTP".

For the flowroute account, there is a slightly different set of parameters:
[flowroute]                         ;; just a name
type=friend ;; same as above
secret=0th3rP@ssw3rd
username=12345678 ;; used by flowroute accounting
host=sip.flowroute.com ;; Asterisk can be told a FIXED IP addr for the other end
;; consequence: Asterisk will contact flowroute
dtmfmode=rfc2833 ;; same
context=inbound ;; same as above
canreinvite=no ;; issue in sip protocol
allow=ulaw ;; allowed encoding (in particular, we don't alow g729)
insecure=port,invite ;; rules for incoming calls from elsewhere
fromdomain=sip.flowroute.com ;; must put this value in SIP From: header field
We have just created two named channels, cisphone001 and flowroute. The flowroute channel may have multiple inbound and outbound calls; the cisphone001 channel represents a single physical device but we still might have several outbound lines in use, and several inbound call attempts. (Later we will see how to tell the flowroute channel what number we want to dial.)

When the actual cisphone001 registers itself, it will provide that name string, "cisphone001". This is how Asterisk learns that the channel [cisphone001] belongs to the IP address of that particular device.

For the sake of future examples, assume we've also defined cisphone002:

[cisphone002]
;; defined like cisphone001

Remember: Asterisk knows how to reach each of our three channels.

Finally, to reach these channels we have to prepend "SIP/" to the channel name defined above.

Now for the extensions.conf file, known as the dialplan file because it has all the rules for how to repond to dialing. First we'll define how to dial extension 3030, eg

[default]
exten => 3030,1,Dial(SIP/cisphone001, 15)       ;; 15 = timeout in seconds

This is all we need to answer calls dialed to number 3030:
  1. Asterisk will match the 3030 in extensions.conf, and find the reference to cisphone001
  2. This corresponds to a channel name defined in sip.conf
  3. That channel name in turn has been linked to a specific IP phone at the time when that phone registered itself and gave the name.
(The Dial() function also takes a third parameter, which allows for options such as keeping the connection if the other party hangs up (eg to dial another number), or to play music while you wait. See http://www.voip-info.org/wiki/view/Asterisk+cmd+Dial.)

Here's a diagram from Asterisk: The Definitive Guide that shows the flow. Phones here are given channel names corresponding to their Ethernet MAC addresses. The important thing to note here is how a call placed by the upper phone to the lower phone (extension 101) is routed between the respective channels.


In my current configuration, I use the manufacturer name, last three bytes of the MAC address, and the line number, eg cisco52ea4bline2. The "line1" is included because each phone has multiple lines that can be independently configured.

Dialplans

In Asterisk, a "dialplan" is the set of definitions of all the "extensions". An extension is, abstractly, a way of reaching a number or class of numbers. Specifically, an extension may represent
The simplest extension in the first category is something like the following:

exten => 3030,1,Dial(SIP/cisphone001, 15)       ;; 15 = timeout in seconds

If extension 3030 is dialed, Asterisk attempts to connect to the given channel cisphone001, using SIP. That channel presumably corresponds to a physical phone.

If we have a number (a "direct inward dial", or DID) 312-123-1234 from our VoIP provider, and we want to connect that to extension 3030 in context locals, we can use

exten => 13121231234,1,Goto(local,3030,1)

This means that if someone in the outside world dials 1-312-123-1234, then our provider routes the call to our Asterisk server, and our server, by dint of the line above, routes the call to extension 3030. We could have set up the connection from 1-312-123-1234 to the phone directly, without using the extension:

     exten => 13121231234,1,Dial(SIP/cisphone001,15)

This is inconvenient, though, as it makes later changes more difficult. It also makes it impossible for someone to dial "3030" internally to reach the phone.

At many sites, the extension is the last four (or five, as at Loyola) digits of the phone number. So the four-digit extension above would be, not 3030, but 1234.

It is best if incoming calls from the outside world start in a different context from local extension definitions.

A simple example in the second, pattern, category might be

exten => _1NXXXXXXXXX,1,Dial(SIP/${EXTEN}@flowroute)

The "_" sign indicates that this is a pattern, not literal bytes. N matches any digit 2-9; X matches any digit 0-9. The pattern here has an N and nine X's, to match a 10-digit phone number (I've added underlining to make it easier to count the X's).  The  literal 1 at the beginning (not a "pattern") represents the leading 1 used by NANP (North American Numbering Plan) dialing conventions.

Because we're matching a pattern, not a specific number, we need to tell the Dial command exactly what number we want. That's where the magic variable ${EXTEN} comes in; it contains the actual number dialed that matched the pattern here. The Dial() argument consists of the channel name (flowroute, from the sip.conf file), prepended by SIP and the actual number we want (${EXTEN}), with the required punctuation.

Dialing the extension here still results in a single channel, which is connected by Asterisk to the dialer's channel.

A simple example in the third category might be

exten => 2000,1,Playback(hello-world)

In Asterisk's default sounds directory is a file hello-world.gsm, which is played. If you have, say, hello-world.gsm and hello-world.wav, Asterisk picks whichever is "simpler" (ie requires less transcoding).

The above three examples were all single lines. However, most real examples of extension scripts are multiple lines. The "1" in the second field of the above extensions is a sequence number (line number). Usually for multi-line extension scripts we use "n" for subsequent lines.

Be aware that all Asterisk extension scripts belong to one specific context, and extensions in different contexts cannot reach one another unless you take steps to allow that (by an explicit context-shifting command, for example, or by including one context in another). A context can be thought of as a namespace, in that the scope of an extension name is its context and two different contexts can define the same extensions. Contexts can be used to implement different privilege levels for extensions; if your phone is in context [lusers] and the outside lines are in context [outbound], you cannot reach them unless things are explicitly configured to enable that. A new context starts with a name in square brackets:
    [localCallers]
Any subsequent extension scripts belong to that new context until the context changes again.

There are a few "special" extensions, built in to Asterisk (from http://www.voip-info.org/wiki/view/Asterisk+standard+extensions):


Here is a multi-line script for an extension that greets the user, tells them their caller-ID number, and then says goodbye. The CALLERID(num) function returns the number; including it in ${...} allows use of that value as a string by the caller. The Hangup at the end is for clarity; Asterisk would hang up by default if there were nothing left to do. This script would work without the Answer() as well.

exten => 3001,1,Answer()
exten => 3001,n,Playback(dir-welcome)                       ;; "welcome to the directory"
exten => 3001,n,SayDigits(${CALLERID(num)})       ;; num = numeric form of CallerID data
exten => 3001,n,Playback(vm-goodbye)
exten => 3001,n,Hangup

The second field of the first line is a 1, representing script entry number 1. The subsequent lines could have 2-5, but instead have "n" for next, which makes later insertion of additional lines easier. We could also have done the later lines as

  same => n,Playback(dir-welcome)

This avoids having to re-type the extension number.

The expression CALLERID(num) represents a string containing the caller-id value supplied by the caller; like all strings it must be enclosed in ${...} to be used in a script. There is also CALLERID(name), but that's less useful in scripts.

For any string STR, we can take the substring of length n starting at position m with ${STR:m:n}; the first character of STR is at position 0. Here is a simple example using variables and substrings:
exten => 2011,1,Answer()
 same => n,Set(NUM=123456789)
 same => n,Set(SNUM=${NUM:4:3})
 same => n,SayDigits(${SNUM})
This reads back the 3 digits starting at position 4 (counting from 0): "5 6 7". Note that to use a variable you need both the $ and the {} around the variable name.

If we leave off n, we get the substring from position m on to the end. If we write -m instead, then the position counting starts from the end of the string, towards the front, so that ${STR:-4} is the last four characters of STR. If STR is "123456789", then ${STR:-4:3} is "678". If we want the last four digits of the CALLERID(num) string, the simplest approach is to use ${CALLERID(num):-4}.

To evaluate an arithmetic expression or function call, enclose it in $[ ... ].



Here is a very simple way to allow calls to roll over into voicemail. If the Dial line completes and the call is connected, then it ends with Hangup and we don't continue to Voicemail. Otherwise we do. The Voicemail function takes a first parameter of the form "mailbox@context", where "mailbox" is usually the user's extension (eg 3001 here), and "context" is the section where the mailbox/extension is defined (for mailboxes, usually "default"). Voicemail settings would have to be made to create the appropriate mailbox here.

exten => 3041,1,Dial(SIP/cisco5534e4line1, 10)          ;; quit after 10 seconds
exten => 3041,n,Voicemail(3041@default)

Here is a multi-line script allowing someone to dial extension 3001 and go to voicemail as necessary (though, as noted, most of the lines are actually not continuations). This version supports separate "busy" and "unavailable" recorded greetings. We test the status of the Dial command and then use the ${DIALSTATUS} variable to continue to voicemail as appropriate. Lines 3-9 are actually different "virtual" extensions corresponding to different values of ${DIALSTATUS}, so they have 1's.

VoicemailMain is the application for receiving your voicemail.

exten => 3001,1,Dial(SIP/chanFor3001,15)                ;; dial for up to 15 seconds; sets DIALSTATUS variable
exten => 3001,n,Goto(${DIALSTATUS},1)                ;; here we use DIALSTATUS
exten => ANSWER,1,Hangup                                     ;; call was answered (and is now completed!)
exten => CANCEL,1,Hangup                                      ;; call was canceled by user
exten => NOANSWER,1,Voicemail(3001@default)   ;; no answer after 15 seconds
exten => BUSY,1,Voicemail(3001@default,b)                ;; b = use separate "busy" message, if one exists
exten => CONGESTION,1,Voicemail(3001@default,b)  ;; b = use separate "busy" message, if one exists
exten => CHANUNAVAIL,1,Voicemail(3001@default,u)  ;; u = use "unavailable" message, which is the default actually
exten => a,1,VoicemailMain(3001@default)                ;; The "a" means the user pressed "*" during the greeting

(One drawback with this version, which is in popular use, is that if we don't list some value of ${DIALSTATUS} then when that case arises we will not go to voicemail. A better solution might be to test for the "busy" cases (arguably only BUSY; CONGESTION means something quite different socially), and play the unavailable message as an "else" option.



Now let's try playing with extension scripts that interact with users. We'll put the script in its own context, so that we can define 1-digit extensions (corresponding to single keypresses) that do not interfere with anything else. The first parameter to Goto is the new context:

exten => 2003,1,Goto(menudemo,start,1)

Now here is context [menudemo]. The Background() function is like Playback() except that it can be interrupted by keypresses. The user is prompted to enter a 1 or a 2; if this is done, the system reads back the number and returns to the main prompt. Any other number except 6 exits the system; if the user presses 6, he or she is prompted to enter a multi-digit number ending with #.

[menudemo]

exten => start,1,Answer
 same => n,Playback(hello-world)            ;; Allison again
 same => n,Background(oneortwo)          ; oneortwo = "please press a one or a two"
 same => n,WaitExten(10)
 same => n,Playback(goodbye)

exten => 1,1,Playback(digits/1)                ;; user entered a 1
 same => n,Goto(start,3)

exten => 2,1,Playback(digits/2)                ;; user entered a 2
 same => n,Goto(start,3)

exten => 6,1,Playback(enternumber)          ;; user entered a 6; play "Enter a number, ending with pound"
 same => n,Read(theNum)                          ;; reads digits until #
 same => n,SayDigits(${theNum})
 same => n,Goto(start,3)

exten => _X,1,Playback(digits/${EXTEN})    ;; catchall extension matches any single digit
 same => n,Playback(wrong)



Here is the final example: a script that allows users to set a "magic" number in the database. Each "account" has its own "magic" number. There is no authentication here (how would you add that)?.

As before, we have a Goto to a special context from the [default] context:

exten => 2004,1,Goto(dbdemo,start,1)

Now here is the actual [dbdemo] context. Within this context, any single-digit extension applies only to this context. The dialplan functions include
[dbdemo]
;; this version says the numbers as strings of digits: "one four nine"

exten => start,1,Answer
same => n,Background(yourkeyis)
same => n,SayDigits(${theAccount})
same => n,Noop(The_account_is${theAccount})
same => n,Background(onetwothreemagic) ;; 1 = set account; 2 = get magic, 3 = set magic
same => n,WaitExten(10)
same => n,Playback(goodbye)

exten => 1,1,Playback(digits/1) ;; set account
same => n,Background(enterkey) ;; "enter your key, ending with #"
same => n,Read(theAccount)
same => n,Noop(The_account_is${theAccount})
same => n,Noop(The_value_is:${DB(MagicDB/${theAccount})}:)
same => n,Background(yourkeyis) ;; "your key is"
same => n,SayDigits(${theAccount})
same => n,GotoIf($[${LEN(${DB(MagicDB/${theAccount})})}=0]?end:speak) ;; empty string: LEN=0
same => n(speak),Background(yourmagicis) ;; "your magic number is"
same => n,SayDigits(${DB(MagicDB/${theAccount})})
same => n(end),Goto(start,4)

exten => 2,1,Playback(digits/2) ;; get magic
same => n,Background(yourmagicis) ;; "your magic number is"
same => n,SayDigits(${DB(MagicDB/${theAccount})})
; same => n,Read(theValue)
; same => n,Set(DB(MagicDB/${theAccount})=${theValue})
same => n,Goto(start,1)

exten => 3,1,Playback(digits/3) ;; set magic
same => n,Background(entermagic) ;; "enter a magic number, ending with #"
same => n,Read(theMagic)
same => n,Set(DB(MagicDB/${theAccount})=${theMagic})
same => n,Goto(start,1)

exten => _X,1,Playback(digits/${EXTEN}) ;; match any digit
same => n,Playback(wrong)
You can examine all the stored database keys with the Asterisk command

    database show

or, to look only at entries in the dbdemo subtree,

    database show dbdemo


Some possible improvements: