Links

Links

Marcos in Asterisk

Macros are a very useful construct designed to avoid repetition in the dialplan. They also help in making changes to the dialplan. To illustrate this point, let’s look at this sample dialplan.

exten => 101,1,Dial(${ABC},10)
exten => 101,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => 101,n(unavail),Voicemail(101@default,u)
exten => 101,n,Hangup()
exten => 101,n(busy),VoiceMail(101@default,b)
exten => 101,n,Hangup()

Now if we have a hundred users on your Asterisk system—setting up the extensions would involve a lot of copying and pasting. Then imagine that you need to make a change to the way your extensions work. That would involve a lot of editing,and we’d be almost certain to have errors.
Instead, we can define a macro that contains a list of steps to take, and then have all of the phone extensions refer to that macro.

Defining Macros
Let’s take the dialplan logic we used above to set up voicemail for ABC and turn it into a macro. Then we’ll use the macro to give ABC and XYZ the same functionality.

Macro definitions look a lot like contexts. We define a macro by placing macro- and the name of our macro in square brackets, like this:

[macro-voicemail]
Macro names must start with macro-. This distinguishes them from regular contexts. The commands within the macro are built almost identically to anything else in the dialplan; the only limiting factor is that macros use only the s extension. Let’s add our voicemail logic to the macro, changing the extension to s as we go:

[macro-voicemail]
exten => s,1,Dial(${ABC},10)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(101@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(101@default,b)
exten => s,n,Hangup()

That’s a start, but it’s not perfect, as it’s still specific to ABC and his mailbox number. To make the macro generic so that it will work not only for ABC but also for XYZ, we’ll take advantage of another property of macros: arguments. But first, let’s see how we call macros in our dialplan.
Calling Macros from the Dialplan. To use a macro in our dialplan, we use the Macro() application. This application calls the specified macro and passes it any arguments. For example, to call our voicemail macro from our dialplan, we can do the following:

exten => 101,1,Macro(voicemail)

The Macro() application also defines several special variables for our use. They include:
${MACRO_CONTEXT}
The original context in which the macro was called.
${MACRO_EXTEN}
The original extension in which the macro was called.
${MACRO_PRIORITY}
The original priority in which the macro was called.
${ARG n }
The nth argument passed to the macro. For example, the first argument would be ${ARG1}, the second ${ARG2}, and so on.

As we explained earlier, the way we initially defined our macro was hardcoded for ABC,instead of being generic. Let’s change our macro to use ${MACRO_EXTEN} instead of 101 for the mailbox number. That way, if we call the macro from extension 101 the voicemail messages will go to mailbox 101, and if we call the macro from extension 102 messages will go to mailbox 102, and so on:

[macro-voicemail]
exten => s,1,Dial(${ABC},10)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(${MACRO_EXTEN}@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(${MACRO_EXTEN}@default,b)
exten => s,n,Hangup()

Using Arguments in Macros

Okay, now we’re getting closer to having the macro the way we want it, but we still have one thing left to change; we need to pass in the channel to dial, as it’s currently still hardcoded for ${ABC} . Let’s pass in the channel as an argument, and then our first macro will be complete:

[macro-voicemail]
exten => s,1,Dial(${ARG1},10)
exten => s,n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy:unavail)
exten => s,n(unavail),Voicemail(${MCARO_EXTEN}@default,u)
exten => s,n,Hangup()
exten => s,n(busy),VoiceMail(${MCARO_EXTEN}@default,b)
exten => s,n,Hangup()

Now that our macro is done, we can use it in our dialplan. Here’s how we can call our macro to provide voicemail to ABC & XYZ:

exten => 101,1,Macro(voicemail,${ABC})
exten => 102,1,Macro(voicemail,${XYZ})

A more advanced version of the macro might look something like this:

[macro-voicemail]
exten => s,1,Dial(${ARG1},20)
exten => s,n,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Voicemail(${MACRO_EXTEN},u)
exten => s-NOANSWER,n,Goto(incoming,s,1)
exten => s-BUSY,1,Voicemail(${MACRO_EXTEN},b)
exten => s-BUSY,n,Goto(incoming,s,1)
exten => _s-.,1,Goto(s-NOANSWER,1)

This macro depends on a nice side effect of the Dial() application: when you use the Dial() application, it sets the DIALSTATUS variable to indicate whether the call was successful or not. In this case, we’re handling the NOANSWER and BUSY cases, and treating all other result codes as a NOANSWER.

Shishir