Book Image

Asterisk 1.4 - the Professional's Guide

Book Image

Asterisk 1.4 - the Professional's Guide

Overview of this book

Asterisk is the leading Open Source Telephony application and PBX software solution. It represents an effective, easy-to-administer, and accessible platform for running enterprise telephony requirements. The real world, however, offers numerous hurdles when running Asterisk in the commercial environment including call routing, resilience, or integrating Asterisk with other systems. This book will show you some of the ways to overcome these problems. As the follow-up to Packt's highly successful 2005 title Building Telephony Systems with Asterisk, this book presents the collected wisdom of Asterisk Professionals in the commercial environment. Aimed at Administrators and Asterisk Consultants who are comfortable with the basics of Asterisk operation and installation, this book covers numerous hands-on topics such as Call Routing, Network Considerations, Scalability, and Resilience ñ all the while providing practical solutions and suggestions. It also covers more business-related areas like Billing Solutions and a Winning Sales Technique. Even if your interest or experience with Asterisk is lower level, this book will provide a deeper understanding of how Asterisk operates in the real world. Asterisk is deployed across countless enterprises globally. Running on Linux, it has constantly demonstrated its resilience, stability, and scalability and is now the advanced communication solution of choice to many organizations and consultants. With a foreword from Mark Spencer, the man behind Asterisk, this book presents the accumulated wisdom of three leading Asterisk Consultants and shows the reader how to get the most out of Asterisk in the commercial environment. Over the course of eleven chapters, this book introduces the reader to topics as diverse as Advanced Dial Plans, Network Considerations, and Call Routing, through to Localization, DAHDI, Speech Technology, and Working with a GUI. The book also covers the more nebulous aspects of being an Asterisk professional such as evaluating customer requirements and pitching for contracts. This book represents the wisdom and thoughts of front line consultants. The knowledge they impart will prove informative, thought provoking and be of lasting interest to Asterisk professionals.
Table of Contents (20 chapters)
Asterisk 1.4
Credits
Foreword
About the Authors
About the Reviewers
Preface
9
Interfacing with Traditional Analog and Digital Telephony
Sample Appointment Sheet

Variables


Variables are key to making the dialplan and system work in a manner that a user expects. The user would expect the system to know everything they have set on their extension, and not have to enter codes or dial special access numbers.

There are a number of places in which variables can be stored including the dialplan, sip.conf, iax.conf, chan_DAHDI.conf (in version1.6), and the Asterisk database (AstDB). For example, if we have a number of static dial strings we wish to store for each type of call and carrier we use, and then use them in a number of sections, the [globals] section of the extensions.conf file is the obvious place to declare them. If we wish to set a variable when a call is initiated from a SIP device, external caller ID or account codes are a good example, the setvar command in the sip.conf file is ideal for that purpose. Just remember that it won't work for calls sent to that device just when the calls are made. Finally, the AstDB is great for variables that are more transient in nature, such as call counts.

Inheritance of channel variables through the dialplan

On occasion, when using complicated dialplans you may wish for a variable's value to be kept as the call progresses. This is achieved by adding a _ [underscore] or a __ [double underscore] before the variable name.

A single _ will cause that variable to be inherited into the channel that started from the original channel, for example:

Set(_name1=value1)

If you want the variable to be inherited to all child channels indefinitely, then add __ before the variable name. For example:

Set(__name2=value2)

This should not be confused with setting the variable with the g option, as this sets it as a global variable. Doing so makes the variable available to all channels globally.

So, you may ask "why might we store dial strings as a variable?" The simple reason is that it allows a minimal amount of code for dialing all numbers, but still allows for different classes of restriction, by which we mean allowing different users to have different restrictions in what they can and cannot dial.

To pass these variables we will use a macro. Macros are like a template that we can use for repeated tasks, and they allow the passing of variables in an ordered fashion to the macro context. The call will jump to the s extension. The calling extension, context, and priority are stored in ${MACRO_EXTEN}, ${MACRO_CONTEXT}, and ${MACRO_PRIORITY} respectively. Arguments passed are accessed as ${ARG1}, ${ARG2}, and so on within the Macro. While a Macro is being executed, it becomes the context, so you must be able to handle the h, i, and t extensions if required within that context.

Let's build our small macro dialplan. We have a variable defined in the globals section of the extensions.conf file as follows:

[globals]
INT_CALL=IAX2/username@peer_out/
INT_CALL_ID=01234123456 ; default international callerID
INT_CALL_LIMIT=5 ; Limit on the number of calls

In the context that we use for dialing, we have:

; International long distance through trunk
exten => _90.,1,Macro(outdial,${INT_CALL})

Here, we have defined the macro we are going to pass the call to, along with a single variable we defined in the globals section (the value of the calling extension can be retrieved within the macro by using ${MACRO_EXTEN}).

The macro context looks like this:

[macro-outdial]
exten => s,4,Dial(${ARG1}${MACRO_EXTEN:1},180)

This is the same as the dial string:

exten => s,4,Dial(IAX2/username@peer_out/01234123456,180)

We have seen that we can pass one dial string, but let's now pass other variables to the Dial() application, such as a backup route for outgoing calls, and the caller ID we want to use for the call.

exten => _90.,1,Macro(outdial,${INTCALL},${INT_CALL_ID},${INT_CALL_LIMIT})
[macro-outdial]
exten => s,1,Set(GROUP()=OUTBOUND_GROUP) ;Set Group
exten => s,2,GotoIf($[${GROUP_COUNT(OUTBOUND_GROUP)} > ${ARG3}]?103) ;Exceeded?
exten => s,3,Set(CALLERID(num)=${ARG2})
exten => s,4,Dial(${ARG1}${MACRO_EXTEN:1},180)

Now it's time to bring some .conf file variables into the mix. Using the setvar facility in the sip.conf, iax.conf and chan_dahdi.conf files, we can set variables specific for every user such as unique caller ID, call limits, whether we want to record the call, account codes. Basically, anything that will help you handle calls more efficiently.

setvar=account_code=2206
setvar=callidnum=01234123456
setvar=tenantID=2

Note

One problem using .conf files is that the relevant channel module needs to be reloaded after a change, and in the case of DAHDI, Asterisk would need to be restarted. This isn't too much of an issue but the need can be removed by using the AstDB for storing commonly changed settings, such as caller ID and recordings.

You may think that all this variable use is over-complicated, but consider a system that supports multiple tenants. Using these techniques, you will only need one dialplan for multiple tenants instead of one per tenant. Simply set the tenantID in the relevant .conf file and then store the tenants' features in the globals section of the dialplan and in the AstDB, and all calls will go out as that tenant group. The concept is the same for other scenarios, such as departments that require cross charging of telephone costs.

Using the AstDB

Setting and retrieving variables in the AstDB is very simple and achieved through the use of the Set() application. Variables can exist in splendid isolation or be grouped into families. The syntax for setting a variable is:

Set(DB(family/variable)=value)

Retrieving the variable's value is equally as simple:

Set(result=${DB(family/variable)})

So, let's have a look at how we can implement a simple multi-tenant dialplan using multiple variable stores:

INT_CALL1=IAX2/username@peer_out_1/
INT_CALL2=IAX2/username@peer_out_1/
INT_CALL_LIMIT1=5 ; Limit on the number of calls
INT_CALL_LIMIT2=5 ; Limit on the number of calls
exten => _90[1-2]XXXXXXXXX,1,Set(INTCALL=INTCALL${tenantID})
exten => _90[1-2]XXXXXXXXX,n,Set(INT_CALL_LIMIT=INT_CALL_LIMIT${tenantID})
exten => _90[1-2]XXXXXXXXX,n,Macro(outdial,${INTCALL}, ${callidnum},${INT_CALL_LIMIT})

As we can see, we have been able to cut down the amount of code and make it universal for different types of users and systems. Using a macro lets us pass an ordered list of arguments. It is easiest to think of macro arguments as a list of variables since they are handled the same way.

Note

Due to the way macro is implemented, it executes the priorities contained within it via a sub-engine, and a fixed per-thread memory stack allowance. Macros are limited to seven levels of nesting. It can be possible that stack-intensive applications in deeply-nested macros could cause Asterisk to crash. Take this into account and be very careful when nesting macros.