Asterisk cmd Macro
Created by: oej,Last modification on Tue 27 of May, 2008 [08:18 UTC] by JustRumours
Synopsis
Macro ImplementationDescription
Macro(macroname,arg1,arg2...)
Executes a macro using the context 'macro-<macroname>', jumping to the 's' extension of that context and executing each step, then returning when the steps end or a call to MacroExit is encounted.
The calling extension, context, and priority are stored in ${MACRO_EXTEN}, ${MACRO_CONTEXT} and ${MACRO_PRIORITY} respectively. Arguments become ${ARG1}, ${ARG2}, etc in the macro context.
If you Goto out of the Macro context, the Macro will terminate and control will return at the location refered to by the Goto. Otherwise if ${MACRO_OFFSET} is set at termination, Macro will attempt to continue at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.
It is worth noting that if you use the "include => contextname" directive to include another context, that the values of ${ARG1} etc. will also be available in that context. This could be used e.g. to set up a standard extension dialing macro with time of day based dependancies.
Quote Tilghmann, May 2008: "Macro isn't very good at going several levels deep. It is by design limited to 7 levels deep, although I've seen people tweak it to go 22 levels deep, and I've even seen a crash caused by Macro going only 5 levels deep."
Example
[macro-stdexten];; ${ARG1} - Extension (we could have used ${MACRO_EXTEN} here as well
; ${ARG2} - Device(s) to ring
;
exten => s,1,Dial(${ARG2},20) ; Ring the interface, 20 seconds maximum
exten => s,2,Goto(s-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
exten => s-NOANSWER,1,Voicemail(u${ARG1}) ; If unavailable, send to voicemail w/ unavail announce
exten => s-NOANSWER,2,Goto(default,s,1) ; If they press #, return to start
exten => s-BUSY,1,Voicemail(b${ARG1}) ; If busy, send to voicemail w/ busy announce
exten => s-BUSY,2,Goto(default,s,1) ; If they press #, return to start
exten => _s-.,1,Goto(s-NOANSWER,1) ; Treat anything else as no answer
exten => a,1,VoicemailMain(${ARG1}) ; If they press *, send the user into VoicemailMain
To call this macro you would use:
exten => 1234,1,Macro(stdexten,1234,SIP/7960)
Macro Exit example
The following macro will exit when 'MacroExit' is called or after the NoOp is called.[macro-Exit]
exten => s,1,Set(var=1)
exten => s,n,GotoIf($["${var}" = "1"]?playback1,playback2)
exten => s,n(playback1),Playback(message1)
exten => s,n,MacroExit
exten => s,n(playback2),Playback(message2)
exten => s,n,NoOp("message 2 played")
I prefer using an explicit MacroExit as the last line of the macro.
[macro-Exit-Preferred]
exten => s,1,Set(var=1)
exten => s,n,GotoIf($["${var}" = "1"]?playback1,playback2)
exten => s,n(playback1),Playback(message1)
exten => s,n,MacroExit
exten => s,n(playback2),Playback(message2)
exten => s,n,NoOp("message 2 played")
exten => s,n,MacroExit ; Note the explict macro exit, while not required it makes for easier reading.
Other macro example
[macro-stdexten];
exten => s,1,Dial(SIP/${ARG1},20)
exten => s,n,Goto(call-${DIALSTATUS})
exten => s,n (call-NOANSWER), Voicemail(${ARG1},u)
exten => s,n (call-BUSY), Voicemail(${ARG1},b)
exten => s,n (call-), Goto(s-NOANSWER)
Don't try to do this - it would be correct to instead use Goto() to branch into and outof the subsection if there is logic that needs to be isolated from the main context:
[macro-process-routing]
; XXX-NNN-6800
exten => _6800,1,Macro(6800-interceptor)
; This is matched when 8 is dialed during macro-6800-interceptor,s,4
exten => _8,1,Playback(welcome)
exten => _8,2,Hangup
[macro-6800-interceptor]
exten => s,1,DigitTimeout,2
exten => s,2,ResponseTimeout,7
exten => s,3,Answer
exten => s,4,Background(autoattendant-ivr/grtg-6) ; Play full after-hours greeting
exten => t,1,Goto(s,1)
exten => i,1,Goto(s,1)
; However, this is never be matched if 8 is dialed during (s,4) above
exten => _8,1,Playback(typhoon)
exten => _8,2,Hangup
Note 1
Note that you cannot use any other extension than 's' to construct the macro as control is returned to the calling context when the end of the 's,' priorities is reached. Not strictly true. Other extensions can be used (as are used in the examples below), but 'macro-name,s,1' is always the starting point. The macro exits when, for the current extension, the priority 'current priority' + 1 does not exist (assuming that control would have passed to that priority had it have existed).
However, watch for this bug/feature, that I just discovered:
Let's suppose that the initial 'macro-name,s,1' contain a GoTo(4567,1). If inside the macro body there is more than one pattern matching that extension (e.g., _4. and _45.), as usual the control will pass to the priority '1' of the first match in the usual sort order: in our case, 'macro-name,_4.,1'. Now let's suppose that, after a few steps, the control proceed down to a non-existent 'macro-name,_4.,7': you'd expect the macro to return, right? WRONG: it'll continue the execution at 'macro-name,_45.,7' (if it exists), i.e. at the next priority of the next matching pattern. Bottom line: if you want to make sure that the macro returns, don't just rely upon a "no more priorities" condition: put an explicit GoTo to a priority that surely does not exist for any pattern in the macro body, such as "GoTo(999)".
Note 2
Note that key presses within a macro will cause a jump to the calling context and WILL NOT jump to the appropriate extension within the macro context. This is a shame and means code becomes a lot more complex. (The same appears to happen also with jumps to the 'h' extension: if a macro executes a Dial(), when the called party hangs up the control passes to the 'h' extension of the calling context. However, please note that the 'h' extension is still needed inside the Macro context in case of a command, application, or extension exiting non-zero - i.e. the user hangs up in the middle of a Record() - in this case the 'h' extension of the Macro context is used, not the 'h' extension of the calling context.) By way of example, with the following dial plan, the caller hears "One" and not "Two".
[default]
; Call starts at s,1 here
exten => s,1,Macro(examplemacro,ARG1,...ARGx)
exten => s,n,Goto(1)
; When caller presses '1' inside the macro, we jump here instead
; of within the macro. Bummer.
exten => 1,1,SayDigits(1)
exten => 1,n,Hangup
[macro-examplemacro]
; ARGx - whatever you want
exten => s,1,Set(TIMEOUT(response)=5)
; Ask the caller to press '1'.
exten => s,n,Background(pressone)
; You would expect this extension to be jumped to
; when the caller presses '1'. It isn't.
exten => 1,1,SayDigits(2)
exten => t,1,Goto(s,1)
Note 2.1
I'm not sure since when but Background does support specifying a context as parameter so by doing a exten => s,n,Background(pressone,macro-examplemacro) it would correctly say two and not one.See also
- Asterisk cmd Gosub: This will be the preferred method in Asterisk 1.6 (as opposed to Macro)
- extensions.conf: The asterisk dialplan
- Asterisk variables
- Asterisk contexts
Asterisk | Applications | Functions | Variables | Expressions | Asterisk FAQ

Comments
333Re: Why use macros instead of contexts?
macro-enduser
exten => s,1,NoOp(End User To Call To ${MACRO_EXTEN} ON ${ARG1}) ;used to log whats happenening
exten => s,n,Dial(${ARG1},10)
exten => s,n,NoOp(${DIALSTATUS})
exten => s,n,GoToIf("${DIALSTATUS}"="NOANSWER"]?UNAVAIL)
exten => s,n,GoToIf("${DIALSTATUS}"="CHANUNAVAIL"]?UNAVAIL)
exten => s,n,GoToIf("${DIALSTATUS}"="CONGESTION"]?UNAVAIL)
exten => s,n,GoToIf("${DIALSTATUS}"="CANCEL"]?HANGUP)
exten => s,n,GoToIf("${DIALSTATUS}"="BUSY"]?BUSY)
exten => s,n,Goto(CONGEST)
exten => s,n(UNAVAIL),Answer()
exten => s,n,Wait(1)
exten => s,n,VoiceMail(${MACRO_EXTEN}@default,u)
exten => s,n,Hangup()
exten => s,n(BUSY),Answer()
exten => s,n,Wait(1)
exten => s,n,VoiceMail(${MACRO_EXTEN}@default,b)
exten => s,n,Hangup()
exten => s,n(CONGEST),Answer()
exten => s,n,Wait(1)
exten => s,n,Congestion()
exten => s,n,Hangup()
user-context
exten => 1111,1,Macro(enduser,SIP/user1) ;This calls on the macro created above
exten => 2222,1,Macro(enduser,SIP/user2)
exten => 3333,1,Macro(enduser,SIP/user2)
333Macros after hangup
exten => s,n,Dial(Zap/g1/${ARG1}|120|g)
exten => s,n,System(/usr/scripts/asterisk_etl.php ${UNIQUEID})
Any help would be greatly appreciated.
333One less argument!
macro-stdexten
exten => s,1,goto(${MACRO_EXTEN},1)
exten => _14XXX,1,dial(....etc
333Macros after Hangup
333Why use macros instead of contexts?
regards,
Rolf (at rowi.net)