|
Home | Switchboard | Unix Administration | Red Hat | TCP/IP Networks | Neoliberalism | Toxic Managers |
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and bastardization of classic Unix |
|
|
We define all of the steps we want Asterisk to perform in our extensions.conf file, in the customary location of /etc/asterisk.
What is a context? Simply said, a context is a group of extensions. Each extension must exist within a context. There is more to contexts than grouping extensions though.
In our extensions.conf file (or any included files), a context is denoted by square brackets "[]", like so:
[mycontext]
. . .
So, if a context is a group of extensions, why do we need more than one? Let's think for a minute. Not all employees should be able to dial every phone. Would you trust your 16-year old intern with the ability to dial international calls? I wouldn't. Also, do you want your president to be bothered by customers in the waiting room who use a courtesy phone and misdial? We could find that hazardous to our continued employment!
So, contexts allow us to hide or make inaccessible certain extensions from other extensions. This gives us some level of security. It also allows us to host multiple phone systems on a single server.
Imagine you have two businesses on the same phone system, each with only two handsets. It'd be a pain to have each dial four digits to reach the other handset. We can use contexts to treat each company as if it were on a separate server.
Something very important about contexts is that we can include other contexts through the use of the include directive. This means that all extensions in an included context are available. The value of this may not be immediately apparent, but soon we will see the full power of this tool.
Suppose we have some context named bob. If we wanted bob to include default, then we would have the following in our extensions.conf:
[bob] include => defaultThis single line placed in any context gives that context the ability to dial any extension in the default context, as well as all contexts included in the default context. This means that if the default context included the foo context, then anybody in the bob context could dial extensions in the foo context.
Suppose we had the following in our extensions.conf file:
[foo] exten => 1,1,Playback(tt-monkeys) include => bar [bar] exten => 1,1,Playback(tt-weasels)
Now I know that we haven't yet discussed the definition of extensions yet. That's OK. All we need to know is that extension 1 in foo will play back a file that sounds like monkeys, and extension 1 in bar will play back a file that says that weasels have taken over our phone system.
If we are in context foo and press 1, which file will we hear play? This shows us the danger of includes. We should be careful to not include multiple matches for the same extension. If we do include multiple contexts, the first included context with a match will win. Consider the following file:
[foobar1] include => foo include => bar [foobar2] include => bar include => foo
If we are in context foobar1 and press 1, we will hear monkeys, while if we are in context foobar2 and press 1, we will hear weasels. While this can trip the unwary, we will use it to our advantage later on.
We all have a good idea of what an extension is. On our legacy PBX, each handset was an extension. Pretty simple, right?
While conceptually simple, there is a little wrinkle. If all we want to do is provide a few handsets, then there's one extension per phone. But Asterisk can do so much more! We need to think of an extension as a group of commands that tells Asterisk to do some things. As amorphous as that may be, it's true.
An extension can be tied to one handset, a queue, groups of handsets, or voicemail. An extension can be attributed to many different areas of the system. If you're familiar with programming terms, perhaps you could say that extensions are polymorphic.
To go further, extensions can be used to provide access to other applications, sound files, or other services of Asterisk. Extensions are important to the magic of Asterisk.
Now that we know why we create extensions let's think about how we create them. Again, they are in the extensions.conf file, or any files that you include from there.
We may decide to break up files such as extensions.conf into multiple configuration files. A common example of this is when we create large groups of extensions and choose to give each its own file. This also applies to the other configuration files we use. |
The general format for a line in the extensions.conf file is:
exten => extensionnum,priority,action
Let's take a closer look. Each line begins with the command exten. This is a directive inside Asterisk. You do not change this for each extension.
Next, we have the extension number. Each extension has a unique number. This number is how Asterisk knows which set of commands to run. This extension can be detected in three major ways. First, the phone company may send it in with the calls, as is the case with DID numbers. Users can enter an extension using their touch-tone keys. Finally, there are a few special extensions defined. Some of these are:
s: start extension. If no other extension number is entered, then this is the extension to execute.
t: timeout extension. If a user is required to give input, but does not do so quickly enough, this is the extension that will be executed.
i: invalid extension. If a user enters an extension that is not valid, this is the extension that will be executed.
fax: fax calls. If Asterisk detects a fax, the call will be rerouted to this extension.
Then we have the priority. Asterisk will start at priority 1 by default, complete the requested command, and then proceed to priority n+1. Some commands can force Asterisk to jump to priority n+101, allowing us to route based on decisions, such as if the phone is busy.
Finally, we have the action. This is where we tell Asterisk what we want to do. Some of the more common actions we may want to perform are:
Answer: This accepts the call. Many applications require that the call be answered before they can run as expected.
Playback(filename): This command plays a file in .wav or .gsm format. It is important to note that the call must be answered before playing.
Background(filename): This command is like Playback, except that it listens for input from the user. It too requires that the call be answered first.
Goto(context,extension,priority): Here, we send the call to the specified context, extension, and priority. While useful, this can be bad style, as it can be very confusing to us if something goes wrong. However, it can be good style if it keeps us from duplicating extension definitions, as moves, adds, or changes would only have to be updated in one place.
Queue(queuename|options): This command does what it seems like it should. It places the current call in the queue, which we should have already defined in the queues.conf file.
Voicemail(extension): This transfers the current call to the voicemail application. There are some special options as well. If we precede the extension with the letter s, it skips the greeting. When we place a u before the extension, it uses the unavailable greeting, and a b uses the busy greeting.
VoicemailMain: This application allows users to listen to their messages, and also record their greetings and name, and set other configuration options.
Dial(technology/id,options,timeout): This is where we tell Asterisk to make the phone ring, and when the line is answered, to bridge the call. Common options include:
t: allow the called user to transfer the call by pressing the # key.
T: allow the calling user to transfer the call by pressing the # key.
r: indicate ringing to the calling party.
m: provide music on hold to the calling party.
H: allow the calling party to hang up by pressing the * key.
g: go on in the context if the destination hangs up.
While this list is not exhaustive, it should be enough to get us started. Suppose we just want to make a Zaptel phone ring, which is on interface 1, and we are going to work completely in the default context. Our extensions.conf file would look like:
[default] exten => s,1,Dial(Zap/1)
Pretty simple, right? Now, imagine we want to transfer to the voicemail of user 100 if someone is on the phone. Since Dial sends you to priority n+101 when the line is busy or not available, all we have to do is define what we want to do. Our dialplan would look like:
[default] exten => s,1,Dial(Zap/1) exten => s,102,Voicemail(b100)
Great! We have some of the functionality that users have come to expect. But are you happy yet? The problem is that a phone could ring for years before someone picks it up!
So, for our next exercise, suppose we want to transfer the call to voicemail when the phone is not answered in 30 seconds. So, obviously, we're going to have to use the option in Dial to define a timeout. Our dialplan would have something like:
[default] exten => s,1,Dial(Zap/1|30) exten => s,2,Voicemail(u100) exten => s,102,Voicemail(b100)
All we're doing is telling Asterisk how to handle the call, in a step-by-step way. It is important to think about all scenarios that a call can go through and plan for them. Just to reiterate a point I made earlier, planning ahead will save us hours of debugging later.
Suppose we want to send anyone who is in a place where they shouldn't be to user 0's voicemail, which will be checked periodically by the receptionist.
[default] exten => s,1,Dial(Zap/1|30) exten => s,2,Voicemail(u100) exten => s,102,Voicemail(b100) exten => i,1,Voicemail(s0) exten => t,1,Voicemail(s0)
All right, we're getting somewhere now! At least we know each call will be handled in some way. What about faxes? Suppose we have only one fax machine (or a centralized fax server) on Zaptel interface 2. Maybe our dialplan should look similar to:
[default] exten => s,1,Dial(Zap/1|30) exten => s,2,Voicemail(u100) exten => s,102,Voicemail(b100) exten => i,1,Voicemail(s0) exten => t,1,Voicemail(s0) exten => fax,1,Dial(Zap/2)
Congratulations! We now have a working phone system. Maybe not the most interesting yet, but we're making great progress. Don't worry, our phone system will grow in features.
Now, to create a list of useful extensions, we need to define a set of commands for each handset we have. Suppose we have three SIP phone users: 1001-1003, with extensions 1001-1003. Our default context would look like:
[default] exten => 1001,1,Dial(SIP/1001|30) exten => 1001,2,Voicemail(u1001) exten => 1001,102,Voicemail(b1001) exten => 1002,1,Dial(SIP/1002|30) exten => 1002,2,Voicemail(u1002) exten => 1002,102,Voicemail(b1002) exten => 1003,1,Dial(SIP/1003|30) exten => 1003,2,Voicemail(u1003) exten => 1003,102,Voicemail(b1003) exten => i,1,Voicemail(s0) exten => t,1,Voicemail(s0) exten => fax,1,Dial(Zap/2)
For every extension we add, the length of extensions.conf will grow by 4 lines (3 lines of code, and one line of whitespace). This is not very easy to read, and it is very easy to make mistakes. There has to be a better way, right? Of course there is!
We can use macros to define common actions. We will create a special macro context. The name of these contexts always starts with macro-. Suppose we want to call this one macro-normal. We would have:
[macro-normal] exten => s,1,Dial(${ARG2}|30) exten => s,2,Voicemail(u${ARG1}) exten => s,102,Voicemail(b${ARG1})
, to create the same 3 extensions, we would have:
exten => 1001,1,Macro(normal|1001|SIP/1001) exten => 1002,1,Macro(normal|1002|SIP/1002) exten => 1003,1,Macro(normal|1003|SIP/1003)
So now, each extension we add only requires one extra line in extensions.conf. This is much more efficient and less prone to errors. But what if we knew that any four-digit extension beginning with a 1 would be a normal, SIP extension?
Here it is time for us to discuss Asterisk's powerful pattern-matching capabilities. We can define extensions with certain special wildcards in them, and Asterisk will match any extension that fits the description.
Using the underscore (_) character warns Asterisk that the extension number will include pattern matching. When matching patterns, the X character represents any number (0-9), the Z character will match the numbers 1-9, the N character represents numbers 2-9, and the period (.) represents a string of any number of digits.
Also, we can use certain variables in our dialplan. One such variable is ${exten}, which represents the extension that was used.
So, for this example, we could use the following definition:
exten => _1XXX,1,Macro(normal|${exten}|SIP/${exten})
This one line of code has now defined 1000 extensions, from 1000 to 1999. All we have to do is ensure that our voicemail user, extension, and SIP user are all the same number. Pretty cool, huh?
One other note: if we wish to modify the behavior of all extensions, all we have to do is modify the macro. This should help us quite a bit as we tweak Asterisk to fit our business needs.
With this dialplan, we have only catered for incoming calls. Of course we will want to create extensions to dial out.
How these outgoing extensions look depends on the plan we made earlier. It also depends on how you want the switch to act for your users. We always want to make it as similar to any old system as possible to reduce the need to retrain users.
Most phone systems require a user to dial a certain digit to designate the call as one that has a destination outside the switch. In our legacy PBX, we accessed outgoing lines by dialing a 9. To copy this behavior, we could do something like:
[outgoing] exten => _9.,1,Dial(Zap/g1/${EXTEN:1})
Notice that we are using pattern matching as we did before. Notice also that we used g1 as the Zaptel interface. This is a good use for a group. This simply means "any free interface in group 1". Thus, if we put all of our outgoing lines in group 1, then when we dial an outside number, we do not have to guess which channel is free.
Remember that the variable exten represents the extension that we are in. If a user dials 95555555, then exten is equal to 95555555. By using ${EXTEN:1}, we instruct Asterisk to strip the first (leftmost) digit. Thus, ${EXTEN:1} equals 5555555. If we wanted to strip the two leftmost digits, it would be ${EXTEN:2}.
Many discount long distance carriers will charge the same for local calls as long distance. In a case like that, we would want to make sure that local and toll-free calls went out on lines connected to the local telephone company, while calls destined for long-distance
locations should go out through our discount carrier. For this example, we will assume that the discount carrier is Zaptel group 1, and the local telephone company is Zaptel group 2.
[outgoing] exten => _9N.,1,Dial(Zap/g2/${EXTEN:1}) exten => _91.,1,Dial(Zap/g1/${EXTEN:1})
Therefore, if the number dialed is preceded with a 9 and a 1, then the call will go out through our Zaptel group 1 lines, and if it does not have a 1, it will go out through our group 2 lines.
What if we had used:
[outgoing] exten => _9X.,1,Dial(Zap/g2/${EXTEN:1}) exten => _91.,1,Dial(Zap/g1/${EXTEN:1})
Notice that this is a problem. When we dial 9, followed by 1, we have two statements that match. When you start Asterisk, you will notice that the system parses the extensions.conf (and included files) and immediately reorders all of the extensions before building a database file. Therefore, it is ambiguous as to which statement it will execute.
While this method is technically functional, it is not the best way to do it. A better way would be:
[outgoing] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1})
This does not allow for medium distance dialing. It also does not handle the case of all lines being busy in one of the groups. Let's see how we could take care of that:
[outgoing] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXNXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXXXXX,2,Dial(Zap/g2/${EXTEN:1})
This is getting much better, but what about when all of our lines are busy, for both groups? We should probably notify the user that their call didn't go through because all lines are in use. We could do something like this:
[outgoing] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _9NXXXXXX,3,Congestion exten => _91NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXNXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXNXXXXXX,3,Congestion exten => _91NXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXXXXX,3,Congestion
Imagine a phone switch in which all extensions were exactly four digits long. How would this knowledge affect our outgoing lines? Perhaps the fundamental question is whether we really need to dial the 9 at all. While people generally expect to dial a 9 at work, they do not seem to care to do so from home. Maybe we should do this:
[outgoing] exten => _NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _NXXXXXX,3,Congestion exten => _1NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _1NXXNXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _1NXXNXXXXXX,3,Congestion exten => _1NXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _1NXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _1NXXXXXX,3,Congestion
There is a drawback to this configuration. If you are using Zaptel interfaces, and people are touch-tone dialing, Asterisk will have to wait for a timeout period to complete dialing some four-digit extensions. The reason for this is simple. Any extension number that partially matches the beginning of the patterns above will have to be held to see if more digits are coming. However, SIP and IAX phones do not seem to suffer the same issue.
Because of this issue, from here forward we will assume that all outgoing calls are preceded with the digit 9.
We have already discussed that contexts can provide security for outgoing phone calls, but this example fails to describe such security. Suppose you have two groups of employees, those who may make toll calls, and those who may not. All employees have an individual handset. The most logical choice is to make two contexts:
[longdistance] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _9NXXXXXX,3,Congestion exten => _91NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXNXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXNXXXXXX,3,Congestion exten => _91NXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXXXXX,3,Congestion [local] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _9NXXXXXX,3,Congestion
We simply place each handset into one of the two contexts, based upon what numbers we want them to be able to dial. While this would work, we duplicated three lines between the contexts. Remember when we discussed contexts, and I mentioned that we can use the include directive? Here's a good place to do so. So now, we have:
[longdistance] exten => _91NXXNXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXNXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXNXXXXXX,3,Congestion exten => _91NXXXXXX,1,Dial(Zap/g1/${EXTEN:1}) exten => _91NXXXXXX,2,Dial(Zap/g2/${EXTEN:1}) exten => _91NXXXXXX,3,Congestion include => local [local] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _9NXXXXXX,3,Congestion
Let's take a quick look at what we have. We can now place handsets in the local or longdistance context. This gives us a good bit of security, but there is one small problem. Do you see it? If we put our users into either context, they cannot dial internal extensions. Assuming we allowed calling our local extensions in the default context, we should update the local context like so:
[local] exten => _9NXXXXXX,1,Dial(Zap/g2/${EXTEN:1}) exten => _9NXXXXXX,2,Dial(Zap/g1/${EXTEN:1}) exten => _9NXXXXXX,3,Congestion include => default
By so doing, we give access to the extensions for the local context. We also give access to the default context for those in the longdistance context because longdistance includes local, which in turn includes default.
Thus, we must be very careful about what we include. When we include any context, we are in turn including all contexts it includes. It is easy to include our way out of the security we set up!
What exactly is Advanced Call Distribution? Many phone systems tout this feature, but most do not adequately define what it means. Basically, it refers to using call queues, parking calls for another user to answer, and Direct Inward Dialing (DID).
So that we keep our focus, we will look at each of these elements individually.
In Chapter 4, we configured call queues, through the /etc/asterisk/queues.conf file. As we go through how we're going to use our queues, we may decide we want to change the way our queues are configured. There is absolutely no problem with changing the configuration so that it more accurately reflects our needs. Just remember that we need to issue a reload on the Asterisk console, or type #asterisk –r –x reload at the command line.
The power and flexibility of other ACD systems can be matched or exceeded by Asterisk. As we evaluate our needs, we should remember that configuring a single aspect of Asterisk sometimes requires changes to more than one file. For example, queues will be
configured both in the queues.conf file and the extensions.conf file. Since we have already discussed the queues.conf file in Chapter 4, we will discuss how to set up extensions.conf to give us the desired result.
When dealing with call queues, we need to think about the two types of users we have. First, we have the caller who calls in and waits in the queue for the next agent. We can think of this person as our customer. Next, we have the agents who work the queue. We can think of these people as our users.
As a business, we have to decide what we want our customers' experiences to be. Our call queue can make it sound like a phone is ringing. Or we can use music on hold while the customer waits. We can also announce call position and estimated wait time if we want to.
When we place customers in a queue, we use the Queue application. To place a caller in the queue named bob, we would use something like:
exten => 1000,1,Queue(bob)
Suppose we have an operator's extension. Since Ollie the Operator may have more than one call at a time, we decide to give him a call queue. His calls are always about a minute long. The customers waiting for him are going to there because they got lost in a system of menus. His queue will be named operator.
In this instance, we will choose to have the customer hear ringing so they will believe they are about to be helped. The sound of ringing should not last more than about a minute. We will not announce call queue length because our customer should not know that he or she is in a queue.
The entry for this queue would be:
exten => 0,1,Queue(operator|tr)
Notice our use of options. Options for the queue application include
t: Allow the user to transfer the customer.
T: Allow the customer to transfer the user.
d: This is a data-quality call.
H: Allow the customer to hang up by hitting *.
n: Do not retry on timeout. The next step in the dialplan will be executed.
r: Give the customer the ringing sound instead of Music on Hold.
Thus, we told the Queue application to give the customer ringing, and the user (Ollie) the ability to transfer calls (since he's the operator).
Now, suppose we have Rebecca, the receptionist. Rebecca is at SIP phone 1006. When Ollie goes to the bathroom, we want our poor lost customers to be routed to her. So we could use the following in our extensions.conf file:
exten => 0,1,Queue(operator|trn) exten => 0,2,Dial(SIP/1006)
Now Rebecca had better answer this. Until she does, the phone will continue to ring. Notice that this call will never end up in Rebecca's voicemail, as it is not transferred to her extension, but instead dials her phone directly.
We have adequately addressed the customer's experience. But now we need to look at how our users will join and leave the queue. Previously, we discussed the power and flexibility of using Agents in queues. As with most things in Asterisk, there are many ways we can associate members to queues. The three main ways are statically, dynamically, and using agents.
Our first option is to have members statically assigned to the queue. To do this, we use the member directive in the queues.conf file. This is most helpful when we have a queue with fixed members, such as a switchboard queue.
Our second option is to allow members to log in dynamically. We do this through the AddQueueMember application. An example of this would be:
exten => 8101,1,AddQueueMember(myqueue|SIP/1001)
Whenever anybody dials extension 8101, the telephone handset SIP/1001 would be added to the queue named myqueue. All that we would have to do is define a login extension for every member of every queue.
What happens when this member no longer wishes to be in the queue? We use the RemoveQueueMember application, like this:
exten => 8201,1,RemoveQueueMember(myqueue|SIP/1001)
With this configuration, whenever anybody dials extension 8201, the telephone handset at SIP/1001 is removed. Again, we would have to define a logout extension for each member of the queue.
Suppose we did not wish to have to define a login and logout extension for each member. We have the option of leaving off the interface (SIP/1001 in the above example) and having Asterisk use our current extension. While this is very useful, Asterisk does not always use the right value. However, if it works for all extensions that need to be in the queue, we would only have to define one login and one logout per queue. The code would look like:
exten => 8101,1,AddQueueMember(myqueue) exten => 8201,1,RemoveQueueMember(myqueue)
This is better than having to define a login and logout for each member of each queue, but sometimes users are not good about remembering multiple extensions to dial. The AddQueueMember application will jump to priority n+101 if that interface is already a member of the queue. Therefore, we could define an extension like:
exten => 8101,1,Answer exten => 8101,2,AddQueueMember(myqueue) exten => 8101,3,Playback(agent-loginok) exten => 8101,4,Hangup exten => 8101,103,RemoveQueueMember(myqueue) exten => 8101,102,Playback(agent-loggedoff) exten => 8101,105,Hangup
When we define it this way, a user dialing extension 8101 is logged in if not already a member of the queue, or logged out if in the queue. Also, we added a confirmation to the action, so that the user can know if they are now in or out of the queue. Notice that before we could use the Playback application, we had to answer the call. If we have a lot of these, we could define a macro extension, like:
[macro-queueloginout] exten => s,1,Answer exten => s,2,AddQueueMember(${ARG1}) exten => s,3,Playback(agent-loginok) exten => s,4,Hangup exten => s,103,RemoveQueueMember(${ARG1}) exten => s,104,Playback(agent-loggedoff) exten => s,105,Hangup . . . [default] exten => 8101,1,Macro(queueloginout|queue1) exten => 8102,1,Macro(queueloginout|queue2) exten => 8103,1,Macro(queueloginout|queue3)
And thus we see that using a macro will save us five lines in our extensions.conf for every queue after the first. This is how we can add queue members dynamically.
Our final option for adding queue members is by using Asterisk's agent settings. We were able to define agents in /etc/asterisk/agents.conf. We create an agent by defining an ID and a password, and listing the agent's name.
In the queues.conf, we could define agents as members of queues. Calls will not be sent to agents unless they are logged in. In this way, queues can be both dynamic and static: they are static in that we do not change the members of the queues, but dynamic in that calls will go to different handsets based upon which agents are logged in.
There are two main types of agents in this world. There are the archetypical large call center agents who work with a headset and never hear ringing, and there are the lower-volume agents whose phone rings each time a call comes in. Asterisk has the flexibility to handle both types of agents, even in the same queue.
First, imagine a huge call center that takes millions of phone calls per day. Each agent is in multiple queues, and we have set each queue to use an announcement at the beginning of calls to let the agent know which queue the call came in from. As employees arrive for their shift, they sit down at an empty station, plug in their headset, and log in. Each employee will hear music in between calls, and then hear a beep, and the call will be connected. To accomplish this, we use the line:
exten => 8001,1,AgentLogin
Through the normal login, the call is kept active the whole time. The agents will logout by hanging up the phone. This allows large call centers to be quieter, as the distraction of ringing phones will be removed. It also allows for more efficient answering of lines, as the time required to pick up the phone is eliminated.
If we have employees who have other work to do as well as answer calls, or have to call other employees to consult, or simply have a low call volume, we may wish to use AgentCallbackLogin. When we do so, our agents' phones are rung when a call comes in. We do this by using:
exten => 8001,1,AgentCallbackLogin
When our users arrive at work and wish to login, they call extension 8001, where they are prompted for their agent ID, password, and then an extension number at which they will take calls. This is how Asterisk knows how to reach them. Our agents can log out when using AgentCallbackLogin by going through the same procedure as for login, except when they are prompted for their extension, they press the # key.
It may be a good idea for us to review agents.conf. If we defined autologoff, then after the specified number of seconds ringing, the agent will be automatically logged off. If we set ackcall to yes, then agents must press the # key to accept calls. If we created a wrapuptime (defined in milliseconds), the Asterisk will wait that many milliseconds before sending another call to the agent. These options can help us make our phone system as user-friendly as we want it to be.
Through the use of call queues, we can distribute our incoming calls efficiently and effectively. We have plenty of options, and can mix-and-match these three ways of joining users to queues.
In many businesses across the United States, an operator can be heard announcing "John, you have a call on line 3. John, line 3." In Asterisk, we don't really have lines in the way that analog PBXs have them. Our users are accustomed to not having to transfer calls, especially when they may not know exactly where John is.
Asterisk uses a feature known as Call Parking to accomplish this same goal. Our users will transfer calls to a special extension, which will then tell them what extension to call to retrieve the call. Then our users can direct the intended recipient to dial that extension and connect to the call.
In order to be able to use this feature, we must define our parking lot. This is done in the /etc/asterisk/parking.conf file. In this file, there are only have a few options that we will need to configure. First, we must create the extension people are to dial to park calls. This can be whatever extension is convenient for us. Then we will define a list of extensions on which to place parked calls. These extensions will be what users dial to retrieve a parked call. Next, we will define what context we want our parked calls to be in. Finally, we will define how many seconds a call remains parked before ringing back to the user who parked it. Here is an example:
[general] parkext => 8100 parkpos => 8101-8199 context => parkedcalls parkingtime => 120
These settings would mean that we can park calls by dialing 8100, and the call will be placed in extensions 8101 through 8199, giving us the ability to have up to 99 parked calls at any given time. The calls will be in the context called parkedcalls, which means we should be careful to include it in any context where users should be able to park and retrieve calls.
When our users transfer a call to extension 8100, they will hear Asterisk read out the extension that the call has been placed on. They can now make a note of it and notify the appropriate coworker of the extension to reach the calling customer on. If the call is not picked up within the given parkingtime, then the call will ring back to the user who parked the call.
By using call parking, we can help our users by providing a feature similar to that of previous generations of PBXs. This also allows users to collaborate and redirect callers to other users who are better equipped to handle our customers' needs.
Suppose we work at a healthcare company with over 100 employees. We have two PRI lines coming in, and only three switchboard agents to handle incoming calls. As a healthcare company, we schedule many appointments, answer questions about prescriptions, and help patients with billing questions. These three agents are always busy.
Now suppose the IT guy's wife calls in to ask if he wants sprouts or mash with his dinner. Do we want our switchboard agents to have to answer the call, find out who it is and what they want, and then transfer the call, or would we rather the IT guy's wife can call her husband directly?
This is where Direct Inward Dialing comes in handy. DID is a service provided by phone companies where they send an agreed-upon set of digits, depending on the number the customer dialed. For most phone companies, the sent digits will be the full 10-digit number (in the United States). But this can be as small as the last digit.
All right, so the phone company is sending digits. What are we going to do with them? Imagine you have a PRI coming in to your office, and only ten phone numbers, a block from (850) 555-5550 to 5559. Your phone company has agreed to send you only the last digit dialed, which will be from 0 to 9, because you are guaranteed for this to be unique. Asterisk can route calls based on this DID information.
If we have our PRI line's channels defined to go into a context called incoming, this context could look like:
[incoming] s,1,Goto(default,s,1) i,1,Goto(default,s,1) t,1,Goto(default,s,1) 0,1,Goto(default,1234,1) 1,1,Goto(default,2345,1) 2,1,Goto(default,3456,1) 3,1,Goto(default,4567,1) 4,1,Goto(default,5678,1) 5,1,Goto(default,6789,1) 6,1,Goto(default,7890,1) 7,1,Goto(default,1111,1) 8,1,Goto(default,1111,1) 9,1,Goto(default,1111,1)
There are a few things we should notice about this. First, we handled the error cases. What if a glitch at the phone company results in four digits being sent? We cannot allow a simple mistake on their end to interrupt our ability to receive phone calls.
Secondly, we are using Goto statements. We've briefly discussed how they can be both good and bad. In this case, by using a Goto, if a user moves from one extension to another, we do not have to update it everywhere, only in the default context.
Finally, we are allowed to send multiple incoming DIDs to the same extension, if we so desire, as in the last three lines shown above. This might be useful if extension 1111 is the operator, and we do not yet have the number 7, 8, or 9 assigned to a user.
Of course, in real life this is going to get much more complicated, as phone numbers will probably come in with the full 10 digits. But the concept is the same: we can define extensions based upon information that the phone company sends when the call is established.
By using DIDs, we can cut down on bottlenecks and give direct access to certain extensions. This tool of Asterisk helps make our phone system fast, efficient, and friendly to our users and customers.
Any time we call a large company, we are greeted by a computer voice, asking us to route our call based on what we want or need. We are all familiar with call menus. While we won't get into a philosophical debate about how good or bad they are, we will talk about how to make them.
Suppose we want to create a menu of options, such as, "For a billing question, press 1, to request a configuration change press 2 ...." Now suppose you press 1, and you hear the option of "For help reading your statement, press 1, if you wish to dispute a charge, press 2, ..." This is just a standard phone tree, with which most users are comfortable. Asterisk knows which extension to execute based upon what context we are currently in.
Suppose that your customer service reps are on SIP/1000, and the manager whom you wish to handle all disputes is on SIP/1001. Then, you have techs on SIP/1002 and SIP/1003. Our configuration file could look like:
[mainmenu] exten => s,1,Answer exten => s,2,DigitTimeout(5) exten => s,3,ResponseTimeout(30) exten => s,4,Background(welcome) exten => s,5,Background(options) exten => 1,1,Goto(billing,s,1) exten => 2,1,Dial(SIP/1002&SIP/1003) [billing] exten => s,1,Answer exten => s,2,DigitTimeout(5) exten => s,3,ResponseTimeout(30) exten => s,4,Background(billingoptions) exten => 1,1,Dial(SIP/1000) exten => 2,1,Dial(SIP/1001)
There are some very important points to make here. It is good to define your digit and response timeouts each time you are going to give an option to the user. This makes your dialplan easier to understand and maintain. Also, notice that we must use the Answer command before being able to playback files. Remember that Background allows for user input to be captured during the file, while Playback does not.
Also notice that we issued the Answer command in the billing menu as well. If we know that nobody could ever get into the billing menu without having passed through the main menu, we could probably leave the command out. However, it does not have any serious adverse reactions, and by leaving it in, we are able to offer a direct line to the billing department, if we ever choose to do so.
Suppose we want to have users be able to dial any extension at any time. All we have to do is use the magical include => default in each of the contexts. This can cause the same delay in dialing we discussed previously in the section Creating Outgoing Extensions, so it should be used with care. Also, users sometimes mash buttons at random, and may stumble across random extensions, frustrating the user. Some organizations have chosen to have users press a specific digit to be able to dial extensions directly to deal with these problems.
On another design note, most customers do not like being trapped for long periods of time in menu systems. Care should be taken to ensure menus do not get too deep. Also, it is easier for customers if you don't give too many options in one level.
Care must also be taken in selecting invalid and timeout responses. But most importantly, we have to do something. Leaving a customer in limbo with nowhere to go and no prompts to get them there is not a friendly move.
Let's build on our previous system with these concepts in mind. Of course, the prompts would be updated to suggest using the new features. For the purposes of this example, let's assume our receptionist is on SIP phone 1004.
Code View: Scroll / Show All[mainmenu] exten => s,1,Answer exten => s,2,DigitTimeout(5) exten => s,3,ResponseTimeout(30) exten => s,4,Background(welcome) exten => s,5,Background(options) exten => 1,1,Goto(billing,s,1) exten => 2,1,Dial(SIP/1002&SIP/1003) exten => 3,1,Goto(dialbyext,s,1) exten => t,1,Goto(s,1,1) exten => i,1,Goto(s,1,1) exten => 0,1,Dial(SIP/1004) [billing] exten => s,1,Answer exten => s,2,DigitTimeout(5) exten => s,3,ResponseTimeout(30) exten => s,4,Background(billingoptions) exten => t,1,Goto(billing,s,1) exten => i,1,Goto(billing,s,1) exten => 1,1,Dial(SIP/1000) exten => 2,1,Dial(SIP/1001) exten => *,1,Goto(mainmenu,s,1) ; escape to the previous menu exten => 0,1,Dial(SIP/1004) [dialbyext] exten => s,1,Answer exten => s,2,DigitTimeout(5) exten => s,3,ResponseTimeout(30) exten => s,4,Backgroud(enterextension) exten => i,1,Playback(invalid) exten => i,2,Goto(dialbyext,s,1) exten => t,1,Playback(imsorryididntgetthat) exten => t,2,Goto(dialbyext,s,1) exten => *,1,Goto(mainmenu,s,1) exten => 0,1,Dial(SIP/1004) include => default
This is a pretty good system. We can build whatever we need using these concepts. Each menu system will be different, based on your needs. As your needs change, the menu system is very easy to update. As a reminder, when you have updated the dialplan, you can refresh it by executing the reload command at the console. This command does not interrupt calls that are currently in progress.
We should take a moment and discuss what a good menu is, and what a bad menu is. We should put our most commonly chosen option first. We should not confuse our customers with too many choices. We should have errors that take you back one step, instead of all the way to the beginning of the menu. We should give an operator who can help people if they get lost. Finally, we should strive to not have our menu any deeper than four steps.
If we keep these design principles in mind, our Automated Attendant can be the best employee we've ever had. No benefits, never sick, and always cheerful and ready to help!
We have talked about how to create contexts, extensions, and how to make our system powerful. Some of the ideas we have discussed will be useful in some situations, yet not applicable in others. All of them work together to make Asterisk a flexible solution for many different needs. There are still other uses that we won't get into, as the need for them is less frequent.
There are some basic system services that we have not yet discussed. In Chapter 4, we configured our voicemail users. Asterisk also includes an application called Directory that reads the voicemail configuration and allows callers to look up an extension based on the user's last name. In the section Creating an Extension earlier in this chapter, we saw how to send calls to voicemail. How do users retrieve messages? How do we use this Directory?
exten => 8000,1,VoicemailMain(@default) exten => 8888,1,Directory(default) exten => 8888,2,Goto(1)
As you can see, providing access to the Directory (extension 8888) and voicemail (extension 8000) is easy. But priority 2 of extension 8888 may seem odd. This is in here because the Directory seems to crash from time to time. By setting priority 2 to place the user back into the Directory, the failure is almost transparent to our users.
In priority 1 of extension 8000, we tell Asterisk to send people to voicemail, in the default context. If we have only one context, we can usually get away without defining the context; however, it is better to be safe. In the Directory application, we must define what context to use, which we specified as default. Both of these contexts should match the context listed in the voicemail.conf file.
When our users call the Directory, they will be prompted to enter the first three letters of the person's last name. Pulling from the voicemail.conf file by default, Asterisk will search for all matches. If users have recorded their name (option 0, 3 in VoicemailMain), then Asterisk will play the file where the person speaks their name; otherwise, Asterisk will spell the complete name out. When it finds the person our user is looking for, they press 1. Asterisk immediately tries to dial that person.
Here we need to talk about naming our contexts. If our voicemail context is called foo, then Asterisk will try to dial extension@foo. However, if our extensions are all defined in a context called bar, then the Directory will fail. Therefore, we must make sure that the contexts in voicemail.conf (where we define the voicemail entry) and the contexts in extensions.conf (where we define the extension) match.
Now suppose we want to record prompts for our menus. Asterisk can play standard Windows .wav files; however, getting the files recorded and into the phone system may not be the most convenient thing to do. Therefore, we can create a simple extension to allow us to record a prompt. We will allow users to input a four-digit name for the file so that they can record many prompts before having to sort them. The prompts will be stored in /tmp, and be recorded as .wav files. We will assume we have a file called enter4digits and record-instructions, as well as a file called 1toaccept2torerecord3torecordanother.
exten => 8200,1,Goto(record,s,1) [record] exten => s,1,Answer exten => s,2,Read(RECORD|enter4digits|4) exten => s,3,Playback(record-instructions) exten => s,4,Record(/tmp/recording-${RECORD}|wav) exten => s,5,Wait(2) exten => s,6,Playback(/tmp/recording-${RECORD}) exten => s,7,ResponseTimeout(10) exten => s,8,Background(1toaccept2torerecord3torecordanother) exten => 1,1,Hangup exten => 2,1,Goto(s,3) exten => 3,1,Goto(s,2)
This little context will give us the option of recording whatever custom prompt we want, in a .wav format. We could add a timeout extension and an invalid extension if we so desire, just as we have done in other contexts.
Another great service that Asterisk provides is conferencing. We configured meetme.conf in Chapter 4 so that we could have conference rooms. In order for users to be able to enter the conference rooms, we must create an extension giving us access.
Suppose we have 10 conference rooms, which we want to place on extensions 8900 to 8909. We also named our conferences 8900 to 8909 in meetme.conf. Our extensions.conf should contain:
exten => 8900,1,MeetMe(8900) exten => 8900,2,Goto(default,s,1) exten => 8901,1,MeetMe(8901) exten => 8901,2,Goto(default,s,1) exten => 8902,1,MeetMe(8902) exten => 8902,2,Goto(default,s,1) . . . exten => 8909,1,MeetMe(8909) exten => 8909,2,Goto(default,s,1)
If we use a little bit of variable magic, we can get these lines down to:
exten => _890X,1,MeetMe(${EXTEN}) exten => _890X,2,Goto(default,s,1)
And so we see that by making our MeetMe conference number the same as the extension number users dial to join, our lives are made a little bit easier. Also, by having all of our conferences in a block of 10 or 100, we are able to use pattern matching to make our extensions.conf shorter.
Another service we may wish to have is a MusicOnHold extension. It will do nothing but play the music on hold that is currently running. This can be a useful tool for the administrator to check if the music is even running, or to check the volume on a handset. To add a MusicOnHold extension, we would add something like:
exten => 8010,1,MusicOnHold(default)
This extension will play the music that is playing on hold in the default class, as configured in the musiconhold.conf file. It will only end when the caller hangs up the phone. But we need to remember that it is not like the background music of some phone systems, in that it does tie up the line that is listening to the music. If calls come in while a user is listening to the music on hold, they will go through the normal procedure for a phone being busy.
In this chapter, we have looked at how to create a dialplan for our Asterisk system. We looked at how to set up:
Contexts
Extensions for incoming calls
Extensions for outgoing calls
Call Queues
Call Parking
Direct Inward Dialing
Voicemail
Automated Phone Directory
Conference Rooms
Although this list of available services is not exhaustive, it is certainly enough to get our phone system up and running. There are many further options available to us, which we will try out as we work through various case studies later in this book. These case studies will give us the full configuration of some Asterisk installations for fictitious companies. We will be able to view the configuration files and keep those parts that help us meet our particular needs.
Now let's expand upon the test dialplan we started in the previous section, allowing us to dial back into the softphone after we have configured it and to use a dialplan application called Echo() that will allow us to test bidirectional audio. Once you've entered the text into extensions.conf, reload the dialplan by running dialplan reload from the Asterisk console:
[globals] [general] [default] exten => s,1,Verbose(1|Unrouted call handler) exten => s,n,Answer() exten => s,n,Wait(1) exten => s,n,Playback(tt-weasels) exten => s,n,Hangup() [incoming_calls] [internal] exten => 500,1,Verbose(1|Echo test application) exten => 500,n,Echo() exten => 500,n,Hangup() [phones] include => internal
Asterisk dial plan - working example - voip-info.org
Asterisk dialplan sample - quick office dialplan - voip-info.org
***** Taking the call - My extensions.conf for Asterisk 1.2 and How it Works Late Night PC
ABP Technology Sample extensions.conf File standard * extention.conf
Society
Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers : Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism : The Iron Law of Oligarchy : Libertarian Philosophy
Quotes
War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda : SE quotes : Language Design and Programming Quotes : Random IT-related quotes : Somerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose Bierce : Bernard Shaw : Mark Twain Quotes
Bulletin:
Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 : Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law
History:
Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds : Larry Wall : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOS : Programming Languages History : PL/1 : Simula 67 : C : History of GCC development : Scripting Languages : Perl history : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history
Classic books:
The Peter Principle : Parkinson Law : 1984 : The Mythical Man-Month : How to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite
Most popular humor pages:
Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor
The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D
Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.
FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.
This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...
|
You can use PayPal to to buy a cup of coffee for authors of this site |
Disclaimer:
The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.
Last modified: March, 12, 2019