Asterisk, My Telephone And Operation “Busy”
Finally and after a long time, again a blog entry about Asterisk, the open-source telephone system. I haven't been using Asterisk for a while since I haven't had a server at hand and only my laptop and a softphone, but now I found some spare time to install the latest Ubuntu release and Asterisk on an older computer. I connected an ordinary ISDN telephone to the computer, basically using my older How-To, but this time with Beronet's mISDN drivers instead of the bristuff.
One issue that had bothered for a long time was the fact that Asterisk cannot produce (or better that I could not make Asterisk produce) a correct "busy" signal to a SIP caller. Instead, when somebody called me via my SIP telephone number and I was talking to someone else already, the line remained dead to the caller and timed out after a while. Although there are commands like DIALSTATUS or ChanIsAvail, they don't seem to work with a SIP call.
So I spent the whole weekend (yes, I had nothing else to do) figuring out what I could do about this. If you use it, you are responsible for any mistakes that might still be in there yourself, so this is just BETA, but for me it works perfectly. I came up with the following solution, in case someone is interested:
The theory is as follows: Suppose we have a few internal telephones, all with numbers 21XX. Now everytime a phone calls another phone, a "busy" variable is incremented. For instance, telephone 1 calls telephone 2. For both phones the busy variable is increased by one, so that busy2101=1 and busy2102=1 (2101 and 2102 are the numbers of the phones, respectively). If now a third phone (2103) calls 2101, Asterisk checks the busy variable. If it is greater than 0 (meaning that the phone is busy), it will signal the caller "busy" or route the call to the voicemail or whatever. If the busy variable is 0, it means the extension is free and the call goes through.
So why not simply use 1 for "busy" and 0 for "free" in the busy variable instead of increasing it? This was actually my first attempt, but the problem occured when the call was hung up. Then the variable was set back to 0 for both the caller and the callee, although the callee might still be in a conversation with someone else. If you then were to try the extension again, the busy variable would show 0 and thus free and the call would be routed to the extension, although being "busy".
By incrementing the variables, it is possible to solve this problem. If 2101 calls 2102, both get 1 in their variables. If then 2103 calls 2102, 2103 gets 1 in its busy variable and checks the status of 2102's busy variable. Even when this is busy now, the variable of 2102 is incremented again by 1 so that it becomes 2. If 2103 now hangs up the call, both variables 2103 and 2102 are reduced by 1 so that 2103 gets 0 and 2102 get 2-1=1. This means that 2102 is still busy. When 2101 ends the call with 2102, both reduce their variables by 1 and finally 2102's busy variable becomes 0 and the extension free.
It might be a bit difficult to understand but maybe it looks clearer in the dialplan (oh, I still hate Asterisk's syntax):
I wrote it as a macro, which you call via this:
exten => _21.,1,Macro(internalcallsetup,${EXTEN},${CALLERIDNUM})
EXTEN gives the macro the dialled extension, CALLERIDNUM gives the number of the telephone which is calling.
[macro-internalcallsetup]
; ${ARG1} = Extension
; ${ARG2} = Caller ID number
; internal calls possible, therefore both parties need to be set "busy"
;this is just to wait for further digits to be dialled (mISDN specific)
exten => s,1,Waitfordigits(3000)
;the busy variables have to be 0 before we start, therefore
;check whether variables are defined and if not so, set them 0
;thanks to the IP-Phone-Forum.de for helping me with the correct IF function
exten => s,2,GoToIF($[x${busy${ARG2}}=x]?3:4)
exten => s,3,SetGlobalVar(busy${ARG2}=0)
exten => s,4,GotoIF($[x${busy${ARG1}}=x]?5:6)
exten => s,5,SetGlobalVar(busy${ARG1}=0)
;now the caller is set busy (increment +1)
exten => s,6,SetGlobalVar(busy${ARG2}=$[${busy${ARG2}}+1])
;now we check if the callee is busy, if so we jump to 50, else ...
exten => s,n,Gotoif($["${busy${ARG1}}" > "0"]?50)
; ... we set callee busy now (increment +1)
exten => s,n,SetGlobalVar(busy${ARG1}=$[${busy${ARG1}}+1])
; ... and call
exten => s,n,Dial(SIP/${ARG1},60)
exten => s,n,Hangup
; if busy, we nevertheless increment the callee +1
exten => s,50,SetGlobalVar(busy${ARG1}=$[${busy${ARG1}}+1])
; and do whatever we like to show that he/she is busy
exten => s,n,Answer
exten => s,n,Playback(vm-nobodyavail)
exten => s,n,Busy
exten => s,n,Hangup
;now we reset the busy variables by subtracting 1 to the prior state
;when the connection is hung up
exten => h,1,SetGlobalVar(busy${ARG2}=$[${busy${ARG2}}-1])
exten => h,n,SetGlobalVar(busy${ARG1}=$[${busy${ARG1}}-1])
That's it! I know there is this GROUP feature in Asterisk, which basically does the same (I haven't tested it, though), but this here works as well. Of course the example above is only for internal calls, if you call externally you also need to set the caller busy. In my dialplan I have implemented this for all contexts and it seems to work so far.
You could also use the busy variables to limit the number of calls to an extension. For instance, 2103 could be allowed to only receive or call 2 numbers at a time and so on.