Asterisk: forward if peer unreachable

I would like to respond to incoming calls by checking if a specific peer is reachable, and dial the appropriate number accordingly.

Presently I did this:

exten => 1200,1,Answer()
same => n,Set(reachable=${SHELL(asterisk -rx "sip show peers" | grep ^cedrich-phone.*OK)})
same => n,GotoIf($["${LEN(${reachable})}" = "0"]?extoffline)
same => n,Dial(SIP/cedrich-phone,20)
same => n(extoffline),Dial(SIP/another-phone,20,tr)
same => n,Hangup()

Could you tell me if this is acceptable and if it can be improved by using the best practices?


Executing a shell of asterisk on an incoming call just doesn't feel right to me. It probably works ok but shouldn't the status of a peer be already known to asterisk?

I use the function SIPPEER() with which you can request the status of a peer. If the first 3 characters (of OK (44 ms)) is OK then you can call the peer. All other situations you can forward to another peer.

I do something like this:

exten => _202,1,Log(NOTICE,Dial Status of ${EXTEN}: ${SIPPEER(${EXTEN},status)})
exten => _202,n,GotoIf($["${SIPPEER(${EXTEN},status):0:3}"="OK "]?ok1:forward)
exten => _202,n(ok1),Log(NOTICE,Calling number is available)
exten => _202,n,Dial(SIP/${EXTEN},50,wW)
exten => _202,n,Hangup()
exten => _202,n(forward),Log(NOTICE,Calling forward number)
exten => _202,n,Dial(SIP/201,50,wW)
exten => _202,n,Hangup()

This checks the status before we're going to Dial() and goes to n(forward) if the peer is unavailable, busy or otherwise not OK.

There is however a small problem with this. When the peer denies the call (or is for another reason unavailable, e.g. he went online before our next online-check) the call doesn't get through.

There is a function DIALSTATUS we can use after the Dial() to check if the call was answered succefully. So use this after the Dial() and if it's not answered also do the forward. (It worked in a test i did. Denying the call gave BUSY in the log and went to the next peer)

You get something like this:

exten => _202,1,Log(NOTICE,Dial Status of ${EXTEN}: ${SIPPEER(${EXTEN},status)})
exten => _202,n,GotoIf($["${SIPPEER(${EXTEN},status):0:3}"="OK "]?ok1:forward)
exten => _202,n(ok1),Log(NOTICE,Calling number is available)
exten => _202,n,Dial(SIP/${EXTEN},50,wW)
exten => _202,n,Log(NOTICE,Dial status: ${DIALSTATUS})
exten => _202,n,GotoIf($["${DIALSTATUS)}"="ANSWER"]?ok2:forward)
exten => _202,n(ok2),Log(NOTICE,Successfull call)
exten => _202,n,Hangup()
exten => _202,n(forward),Log(NOTICE,Calling forward number)
exten => _202,n,Dial(SIP/201,50,wW)
exten => _202,n,Hangup()

I didn't test this last bit (with DIALSTATUS) extensively so you should do some test but here it seems to work.


As @arheops mentioned, you can use DEVICE_STATE() to get the status of a specific device, if it's 1:1 mapping (1 account on 1 device). You can use the following:

${DEVICE_STATE(${CHANNEL(channeltype)}/${CHANNEL(peername)})}

Another possibility is EXTENSION_STATE() function in case you have 1:many mapping (one extension with more than one device).

Both can have hints as described here if you need to have one user to use multiple devices. Here you can see how to make dynamic hints