Tuesday, August 7, 2007

Asterisk long distance alternative

I just found out a couple of weeks ago that Fido, my cell carrier, is charging us $0.30/min for long distance. My husband's long distance last month cost over $15 for less than an hour of calling. There are long distance companies that will give you an access number and let you call from a cell phone, giving you a dialtone to place your long distance call. One of these that we used to use is WinTel, who offers a $0.25/call for long distance no time limit. They work quite well, but the call quality can be a bit questionable at times. However I already have an Asterisk server, and I already have a voip account with Link2Voip for my incoming phone numbers who offer $0.011/min across Canada and $0.019/min in the US50 with incoming calls being the same as the Canadian rate. I should be able to call in on one of my DID's to my Asterisk server and somehow get it to give me a dialtone to call back out on allowing me to use my Link2Voip long distance rates rather than the atrocious Fido rates.

I brainstormed this a bit with my colleague at work and he suggested yes that it could be done. I borrowed his O'Reilly Asterisk book for the weekend and take Monday to play around with it. After reading the chapter on dialplans I understand them for the first time, previous to this I just sortof hacked around them with examples from the default Asterisk configs and what Link2Voip supplied me.

Monday afternoon I started playing with it. I set up an extension in my outgoing context that allowed me to test functions and used the POTS phone that I have hooked up to my PAP2-NA SIP adapter. To start with my extensions.conf looked something like this:

[outgoing]
exten => 222,1,Answer()
exten => 222,2,Playback(hello-world)
exten => 222,3,Hangup

That was my basic dialplan that I had set up for extension 222, when I dialed that in my phone Asterisk would play back the sound file "hello-world.gsm" and hang up. Not all that useful, but at least I knew I had an area I could test things. I then decided to figure out the best way to authenticate a person with passcode of some sort. I found the Authenticate() app and implemented that into the dialplan:

[outgoing]
exten => 222,1,Answer()
exten => 222,2,Authenticate(54321)
exten => 222,3,Playback(hello-world)
exten => 222,4,Hangup

Now when I call 222 I get a voice response of: "Please enter your password followed by the # key" You can now enter 54321 and press # and it will play the "hello-world.gsm" audio file. If you enter the wrong password it will let you try 2 more times, then fail and hang up. If the authorization is successful, I wanted it to play back a message saying so, so I dug around in /var/lib/asterisk/sounds and found the "pin-number-accepted.gsm" file and added that to the dialplan:

[outgoing]
exten => 222,1,Answer()
exten => 222,n,Authenticate(54321)
exten => 222,n,Playback(pin-number-accepted)
exten => 222,n,Hangup

I got sick of reordering the priorities in the dialplan so I switched to their auto-order format by setting the first one to "1", then the rest to "n" for "next".

Now that I have authentication working I need to figure out how to read in a number from a user to forward the call to. I found the Read() app and after some playing with it I figured out how to use it to capture a phone number 10 digits in length to a variable, to verify that it was working and reading the digit's correctly, I used the SayDigits() app to have it read them back to me:

[outgoing]
exten => 222,1,Answer()
exten => 222,n,Authenticate(54321)
exten => 222,n,Playback(pin-number-accepted)
exten => 222,n,Read(NUM_TO_DIAL,vm-enter-num-to-call,10,,3,15)
exten => 222,n,SayDigits(NUM_TO_DIAL)
exten => 222,n,Hangup

Once I was able to confirm that that was working, I needed to figure out how to forward it to another extention, for this I used the Goto() to send it to the pattern matching extension that would normally handle these types of calls:

[outgoing]
exten => 222,1,Answer()
exten => 222,n,Authenticate(54321)
exten => 222,n,Playback(pin-number-accepted)
exten => 222,n,Read(NUM_TO_DIAL,vm-enter-num-to-call,10,,3,15)
exten => 222,n,SayDigits(NUM_TO_DIAL)
exten => 222,n,Goto(outgoing,${NUM_TO_DIAL},1)
exten => 222,n,Hangup

This pretty much completes the steps needed to authenticate the user, read in the number to dial and then to dial it. My next problem was that I wanted to be able to access this when calling in on any of my DID's. I set up a 2 second delay where when a user calls in on any of my DID's, if they press a key they will be asked for a password. If no key is pressed, the DID will follow it's normal behavior and forward the call to it's appropriate destination.

I first set a 1 second Wait() then play a beep, just as an identifier to know that I've been connected to the Asterisk server and then wait 2 seconds to see if a key had been pressed. I use Read() to listen for the keypress and GotoIf to go to the appropriate extenstion based on the results:

[incoming]
exten => 16045551212,1,Answer() ; Answer the call
exten => 16045551212,n,Wait(1) ; Wait 1 second to make sure we're connected
exten => 16045551212,n,Read(KEYPRESS|beep|1||1|2) ; listen for any key, for up to 2 seconds
;If the results of the read above has at least one digit in it
; forward to the outgoing context, authout extension, priority 1
; otherwise send the call to the current context, incomingdid extension and priority 1.
exten => 16045551212,n,GotoIf(${LEN(${KEYPRESS})} > "0"?outgoing,authout,1:incomingdid,1)

exten => incomingdid,1,Dial(SIP/home,60) ; incomingdid extension, priority 1

[outgoing]
exten => authout,1,Answer()
exten => authout,n,Authenticate(54321)
exten => authout,n,Playback(pin-number-accepted)
exten => authout,n,Read(NUM_TO_DIAL,vm-enter-num-to-call,10,,3,15)
exten => authout,n,SayDigits(NUM_TO_DIAL)
exten => authout,n,Goto(outgoing,${NUM_TO_DIAL},1)
exten => authout,n,Hangup

; The macro's Link2Voip gives to the user to dial out their trunk
exten => _1NXXNXXXXXX,1,Macro(diallink2voip,${EXTEN})
exten => _NXXNXXXXXX,1,Macro(diallink2voip,1${EXTEN})

I'm happy to say that this all works. I can dial in on any DID, preempt the standard dialplan and allow myself to authenticate and choose a new number to dial. Calling from my cell phone this makes my long distance charges $0.022/min to Canada and $0.03/min to the US about 1/10th of what Fido is charging me. If I use one of my Toll-Free DID's that I purchased from Link2Voip it puts the cost below $0.06/min, still 1/5th of what Fido is charging.

Michelle Trusty

No comments: