login | register
Tue 02 of Dec, 2008 [03:21 UTC]

voip-info.org

Discuss [5] History

Asterisk cmd Macro

Created by: oej,Last modification on Tue 27 of May, 2008 [08:18 UTC] by JustRumours

Synopsis

Macro Implementation

Description


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


Comments

Comments Filter
222

333Re: Why use macros instead of contexts?

by jetdriver, Friday 24 of October, 2008 [03:41:02 UTC]
Normally if you have a small home or office setup, there would be no need to use macros. However, if you are dealing with a large organization with hundreds of employees, macros will make things much easier when adding/or deleting users and when implementing universal changes. Below is a simple macro that will call an end user and if his/her line is busy or unavailable for various reasons, will send you to their voicemail. If in the future, we would like tro implement a change to the way the dialplan handles an incomming call, we only have to modify the macro and not a dialplan for each and every employee.

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)





222

333Macros after hangup

by bblackmoor, Friday 01 of December, 2006 [16:06:00 UTC]
I need to run a System command after a call has ended and the CDR record has been written. I have tried everything I can think of, using Dial "g", System, Macro, Goto, GotoIf, etc., and either the System() command executes before the CDR record is written, or it does not execute at all. At it's simplest, this is what I would like to have happen:

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.
222

333One less argument!

by tc0nn, Wednesday 21 of June, 2006 [08:45:38 UTC]
I started redefining my macros as below. It saves me from having to design a whole macro using "s" and having to pass the dialed extension as ${ARG1}...

macro-stdexten
exten => s,1,goto(${MACRO_EXTEN},1)

exten => _14XXX,1,dial(....etc

222

333Macros after Hangup

by anaphaxeton, Thursday 27 of October, 2005 [21:08:01 UTC]
After a call has entered the h (Hangup) extension of a context, been disconnected, or has failed, Macros no longer function. The first one or two steps will execute and then Asterisk seems to forget to continue interpreting your script and returns control to the next step of the calling context.
222

333Why use macros instead of contexts?

by rowitech, Tuesday 29 of March, 2005 [14:16:40 UTC]
I wonder if someone knows why to use macros instead of just conexts to jump into. The only difference I see is the ability to pass arguments (arg1, arg2, ...) when using macros. But is there any other difference?

regards,
Rolf (at rowi.net)