Asterisk cmd Macro


Macro Implementation



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.

'h' extension: If a macro executes a Dial() and the called party hangs up, then the control passes to the 'h' extension of the calling context.
However, 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.)
Tilghman, May 2010: So Macro returns upon hangup to execute the "h" extension in the original calling context, though even that is conditional, based upon it having been broken for a long time.

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.

Nesting of macro statements:
If a macro calls another macro the ${ARGx} variables are not cleared! That means if macro-1 was called with ARG1 and ARG2, and in turn called macro-2 with only ARG1, then ARG2 and its value are still being passed on to macro-2 unless you specifically set it to "" first.
(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."

Usage together with Gosub:
You really shouldn't be calling a Gosub routine from Macro. We've already had to deal with some really odd interactions between the two. If you're going to make the jump to Gosub, go completely over and only use Gosub. Don't use Macro in conjunction with Gosub (Tilghman, May 2010).


  ;   ${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.

  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.

  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

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:


  ; 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

  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. By way of example, with the following dial plan, the caller hears "One" and not "Two".

; 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

; 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 | Applications | Functions | Variables | Expressions | Asterisk FAQ

Created by: oej, Last modification: Mon 13 of Feb, 2012 (08:53 UTC) by pcouderd
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+