Dialplan basics

We have everything in place to start processing calls and doing cool stuff with Asterisk. This section will briefly go over some major components to building dialplans in Asterisk.

We'll go over our rudimentary dialplan in more detail now and add more functionality to it a little at a time. Recall, all dialplans are defined in extensions.conf.

Here are some key terms to know:

  • Extension - An extension is an arbitrary set of digits (or even letters) which trigger something to happen to a call inside Asterisk. Extensions break up step-by-step functionality of how to process calls that are routed to them. Extensions take calls and push them into Asterisk "applications" that do specific things, like playback audio over a call, or wait for button presses from the caller. 
  • Context - A context is a collection of extensions, being routed to by SIP endpoints. Recall our endpoints we defined in sip.conf, PhoneHandset and PhoneLine. In sip.conf, we set the default context for PhoneLine to one also named "PhoneLine" and did the same for "PhoneHandset."
  • Applications - When a call hits an extension, we chain together various applications in Asterisk to create a call flow for logic we wish to apply to a call.
  • Priority - the order in which each step of the extension is executed. In the past, Asterisk had to be hard coded with numeric priorities for each step of the dialplan. Now we have generic place holders and names that allow us to jump to different parts of the extension without having to renumber our extensions every time we want to make a change.

The basic syntax of an Asterisk dialplan looks like this:

exten => extension,priority,application

Keeping that in mind, let's look at our basic dialplan now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[general]
exten => _X.,1,Answer()
    same => n,NoOp("generic catch-all extension")
    same => n,NoOp(${EXTEN})
    same => n,HangUp()

[PhoneLine]
exten => _X.,1,Answer()
    same => n,NoOp("in PhoneLine extension")
    same => n,NoOp(${EXTEN})
    same => n,HangUp()

[PhoneHandset]
exten => _X.,1,Answer()
    same => n,NoOp("in PhoneHandset extension")
    same => n,NoOp(${EXTEN})
    same => n,HangUp()

Looking at line 7, we have named a context called "PhoneLine."

On line 8, we have our first (and only) extension defined within our PhoneLine context, called "_X." The "1" after it tells Asterisk it's the first step in the extension, and the is followed by the Answer() application.

This extension name is actually a special extension that defines a "catch all" for phone number pattern matching. It is guaranteed to match the incoming caller ID from the PhoneLine context and pushes it to the Answer() application. The Answer() app does exactly what it sounds like: answer the call coming in. It's good practice to answer all calls before doing any work on them in Asterisk.

We then move on to the next line of the extension, denoted by the same keyword. The n in front is that generic priority ordering we talked about earlier. The application we use next is called NoOp(), short for "No Operation." This is used for showing messages to the debug console, like displaying values of dialplan variables, just like ....

Line 1o shows the value of a built-in dialplan variable called "EXTEN." This contains the value of the dialed extension detected on the phoneline. To display this value with the NoOp() app, we have to encase the variable name like so: ${EXTEN}. This tells Asterisk to evaluate whatever is in that variable and sit it back on the debug console.

Lastly, we hang up on the call with HangUp().

This dialplan is good for demonstrating concepts, but we're also just getting calls and hanging up on them.

Let's adjust this to be a little more functional by adding another application to our dialplan: Dial().

The Dial() application tells Asterisk to dial out calls from the server and connects them to the current call in the extension.

The basic syntax for using Dial looks something like this

exten => callout,1,Dial(SIP/5555555555@PhoneLine)

This line is telling Asterisk to Dial the SIP endpoint defined as PhoneLine with the number (555) 555-5555.

Let's make our dialplan actually usable by having Asterisk pass the calls it receives to the appropriate endpoints. We'll also add in another NoOp() to view the built-in Asterisk variable for pulling caller ID info from the incoming call.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[general]
exten => _X.,1,Answer()
    same => n,NoOp("generic catch-all extension")
    same => n,NoOp(${EXTEN})
    same => n,HangUp()

[PhoneLine]
exten => _X.,1,Answer()
    same => n,NoOp("in PhoneLine extension")
    same => n,NoOp("incoming caller id: ${CALLERID(number)}")
    same => n,Dial(SIP/${EXTEN}@PhoneHandset)

[PhoneHandset]
exten => _X.,1,Answer()
    same => n,NoOp("in PhoneHandset extension")
    same => n,NoOp("dialed number: ${EXTEN}")
    same => n,Dial(SIP/${EXTEN}@PhoneLine)

Now we can see calls coming into the server with their caller ID. They then get passed to the appropriate endpoint and the call completes.

Let's take a look at the debug console to see what's happening step by step in the call.

So Asterisk is clearly pulling the caller ID (I blurred mine out b/c it's the Internet and my grandma's phone) and passing the call to the appropriate extension.

You can see how stacking Asterisk applications in an extension can quickly build up complex functionality for a call. I won't do anymore examples of dialplan logic, but if you wanna know more about building dialplans, the Definitve Guide to Asterisk is an excellent free online publication written by the dudes who make Asterisk. It's an excellent start if you wanna get into the VoIP world.

So that pretty much does it for dialplan basics. In the next section, we will be putting a bunch of Python scripts into our dialplan and finishing out the build of Banana Phone.

-> Next section: Integrate Banana Phone scripts