Thursday, October 27, 2011

Call-Back Service for IP-Telephony users Part-I

While trying to think of a bit complex dial plan example for VoIP-students I came up with the idea of a call-back service.
The idea is whenever an external call comes into IP-Telephony server for some user, if that user is unavailable to take call, the call should get routed to voice mail OR should be enlisted in a list. This list will be collection of all the callers to that user who wanted to be called back automatically whenever the user likes.
From IP-telephony user's perspective its a missed-calls register sort of list which is dialled back automatically once triggered.

Not the smartest idea but from Asterisk Dial-plan P.O.V it has lots of things to be learned.

Since this is abit complex to understand dial-plan project so I think I'll break it into two parts. First one is going to deal with Incoming call from outside and saving the number in the call-back register.
Second part will focus on the actual service where an IP-PBX user dials into the service number and go through his call-back list.

What we'll Learn:

1- Setting up voicemail service for users.
2- Using Asterisk built-in DB i.e AstDB to save and retrieve User lists.
3- Use of Macros in Dial-plan
4- Asterisk dialplan applications SayDigits, ExecIf, While/EndWhile, Voicemail
5- Asterisk dialplan functions DB, DB_EXISTS, FIELDQTY, CUT, ARRAY
6- Using Labels in dial-plan to transfer control between priorities

Setting up Voicemail:
Setting up voicemail is fairly simple task. Just edit the file /etc/asterisk/voicemail.conf and insert following lines

101 => 12345678,Dean Winchester,

101 is User's voicemailbox number - I chose it to be the same as of User's Telephony extension.
12345678 is users's voicemail access pin.
Next two fields are user name and user email respectively.

To make voicemail box configurations active don't forget to execute "voicemail reload" in asterisk command line interface.

Dial-Plan Code:
once Voicemail is configured we need to call the voicemail application if user is unavailable. As you can see from code below that voicemail is called after Dial() application. Dial application is configured to timeout after 10 seconds of ringing to the destination.

exten => _X.,1,NOOP( Call from ${CALLERID(num)} to ${EXTEN})
same => n,Answer()
same => n,SET(DEST=${EXTEN})
same => n,Dial(SIP/${EXTEN},10)
same => n,Voicemail(${EXTEN}@default,d(register-callback))
same => n,Hangup()

Once the dial application is timed out or the user in unavailable or busy incomming caller will listen the voicemail prompt. "Please record your message after the tone, when done press # or hangup".
Meanwhile listening to this message user can press one-digit key from his cell-phone and the call control will be transferred to "register-callback" context. thanks to the option "d" in voicemail application.

Hint: execute "core show application voicemail" in asterisk CLI to know more.

exten => s,1,NOOP(Caller ${CALLERID(num)} Registering Call-Back for User ${DEST})
same => n,NOOP(do some call-back tricks here)
same => n,SET(CBQ=${DB(call-back/${DEST})})
same => n,GOTOIF($["${CBQ}" == ""]?first:sec)
same => n(first),Set(DB(call-back/${DEST})=${CALLERID(num)})
same => n,GOTO(jump)
same => n(sec),Macro(duplicate-check,${CALLERID(num)})
same => n,GOTOIF($["${RESULT}" == "1"]?jump)
same => n,Set(DB(call-back/${DEST})=${CALLERID(num)}-${CBQ})
same => n(jump),NOOP(Playback(thanks-willb-called-shortly))
same => n,Hangup()

exten => i,1,GOTO(s,1)

I know, the above code isn't easy to even look at. thats why I've highlighted important things to learn here.

1- Labels:
Anything that is enclosed in () next to priority field (i.e "n" in my case) becomes a label and control can be transferred from anywhere to these labels. "first","sec","jump" are labels in the above context.

2- Asterisk DB operations:
DB(call-back/${DEST}) is used to GET or SET values from AstDB. In this case "call-back" is family name (DB name) ; Value of ${DEST} will be the Key to access one unique Value/Result set from the AstDB.

If DB() function is enclosed in ${} then asterisk will GET/fetch the value from the DB otherwise asterisk will SET the value in AstDB(given anything appears in right hand operand with operator =)

Fetch the value from AstDB and Save in variable "CBQ"

same => n,SET(CBQ=${DB(call-back/${DEST})})
Set value from "${CALLERID(num)}-${CBQ}" into the AstDB.
same => n,Set(DB(call-back/${DEST})=${CALLERID(num)}-${CBQ})
3- Using Macros

Macros are like functions which accepts arguments. Just like regular contexts now-a-days. See this link for detailed information.

same => n(sec),Macro(duplicate-check,${CALLERID(num)})
I don't recommend using macros but unfortunately these are essential part of asterisk dial-plan learning. In above dial-plan code ${CALLERID(num)} becomes argument-1 to "macro-duplicate-check"

As soon as the above line is executed call-control jumps to context "[macro-duplicate-check]"

exten => s,1,NOOP(${CBQ} Checked for Duplicate ${ARG1})
exten => s,n,SET(COUNT=${FIELDQTY(CBQ,-)})
exten => s,n,SET(ARRAY(i,RESULT)=1,0)
exten => s,n,WHILE($["${i}" <= "${COUNT}"])
exten => s,n,NOOP(${CUT(CBQ,,${i})} == ${ARG1})
exten => s,n,EXECIF($["${CUT(CBQ,,${i})}" == "${ARG1}"]?GOTO(found):SET(i=$[${i} + 1]))
exten => s,n,Endwhile()
exten => s,n,MacroExit()
exten => s,n(found),SET(RESULT=1)
exten => s,n,MacroExit()

Again, important things have been highlighted. This macro is just an exceptional handling that the same number don't get inserted into the call-back list more than once.

Everyone knows about While-looping the only difference here is that an EndWhile() defines where the While-Block ends.

EXECIF is just another application to compress 6+ Lines of dial-plan into just one line. It execute one application if the condition is true or execute the second application otherwise.

exten => s,n,EXECIF($["${CUT(CBQ,,${i})}" == "${ARG1}"]?GOTO(found):SET(i=$[${i} + 1]))

I find it easy to compress 6+ lines of GOTOIFs and applications into just one line.

Here we are done with the first part of the service.

So far we've just done what the flow-chart said in this post; Receive incoming call, and skip voicemail if user wants to register for call-back, check if the number already exists in Call-back list. Finally play message to caller that he'll be called back shortly.

Wednesday, October 26, 2011

If you think you're consultant lvl-82

Once upon a time there was a shepherd looking after his sheep on the side of a deserted road. Suddenly a brand new Porsche screeches to a halt. The driver, a man dressed in an Armani suit, Cerutti shoes, Ray-Ban sunglasses, TAG-Heuer wrist-watch, and a Versace tie, gets out and asks the Shepherd:

Man: “If I can tell you how many sheep you have, will you give me one of them?”

The shepherd looks at the young man, and then looks at the large flock of grazing sheep and replies:

Shepherd: “Okay.”

The young man parks the car, connects his laptop to the mobile-fax, enters a NASA Webster, scans the ground using his GPS, opens a database and 60 Excel tables filled with logarithms and pivot tables, then prints out a 150 page report on his high-tech mini-printer. He turns to the shepherd and says,

Man: “You have exactly 1,586 sheep here.”

The shepherd cheers,

Shepherd: “That’s correct, you can have your sheep.”

The young man makes his pick and puts it in the back of his Porsche. The shepherd looks at him and asks,

Shepherd: “If I guess your profession, will you return my animal to me?”

The young man answers;

Man: “Yes, why not?”

Shepherd: "You are an IT consultant."

Man: “How did you know?”

Shepherd: “Very simple. First, you came here without being called. Second, you charged me a fee to tell me something I already knew, and third, you don’t understand anything about my business…Now can I have my DOG back?"

Monday, October 24, 2011

Asterisk Dial-plan exercise [Speed-Dial]

Creating a Speed-Dial Functionality :
This was a test exercise I gave in one my teaching classes here last year. The idea is to develop a Speed-Dial functionality context for PBX users.

What we'll learn:
1- Connect to MySQL DB from Dial-plan.
2- Use of Asterisk Dial-plan functions CUT, FIELDQTY.
3- Use of GOTOIF Dial-plan application.
4- Use of restricted extension pattern matching by use of [ ].

Problem Statement:
The users should be able to edit their own speed dial-lists via web-interface. And whenever a SIP user dials single digit extension ranging from 0-9 should be able to speed-dial to their contacts saved in DB.

(The Php web-interface for editing contacts isn't included here, it shouldn't be difficult to make a simple page for this.)

Solution Algorithm:

Final Dial-Plan Code:
Corresponding Dial-plan for the above Algorithm is as follows.A few exceptions were handled where if no user speed-dial lists exists or no user data existed.

exten => _[0-9],1,NOOP(Starting Speed-Dial functionality)
same => n,MYSQL(Connect connid localhost asteriskuser ast_pass user_prefs)
same => n,MYSQL(Query resultid ${connid} SELECT contact_list FROM speed_dial_list WHERE user='${CALLERID(num)}')
same => n,MYSQL(Fetch fetchid ${resultid} UserList)
same => n,MYSQL(Clear ${resultid})
same => n,MYSQL(Disconnect ${connid})
same => n,GOTOIF($["${fetchid}" < "1"]?not_found:found)
same => n(not_found),Playback(No-User-List-Found)
same => n,Goto(h,1)
same => n(found),NOOP(User Speed-Dial List Found: ${UserList})
same => n,NOOP(Find if user Dialed Speed-Dial index exists)
same => n,SET(List_Length=${FIELDQTY(UserList,-)})
same => n,GOTOIF($["${EXTEN}" >= "${List_Length}"]?not_found:lengthok)
same => n(lengthok),NOOP(Now User Contact for Speed-Dialed exten ${EXTEN} Exists for Sure)
same => n,NOOP(Fetch the Speed-Dial-Contact from ${UserList})
same => n,SET(UserContact=${CUT(UserList,,${EXTEN})})
same => n,NOOP(Found user Contact ${UserContact} Corresponding to ${EXTEN})
same => n,DIAL(SIP/${UserContact})
same => n,Hangup()

Now Database turn.
Connect to MySQL and Create table "speed_dial_list" and push some dummy values corresponding to PBX users

mysql>use asterisk
mysql>CREATE TABLE `speed_dial_list` (`user` varchar(80) NOT NULL default '',`contact_list` varchar(555) NOT NULL default '');
mysql>INSERT into speed_dial_list(user,contact_list) VALUES ('100','110-132-400-161-101-123'),('200','100-201-115-101'),('110','201-200-119'),('210','150-161-110-199-923452167923');
mysql>GRANT all on asterisk.* to 'asteriskuser'@'localhost' Identified by 'ast_pass';
mysql>flush privileges;

Sample output on Asterisk CLI when SIP User 100 dialled Speed-Dial Extension '3'

So, we made a Speed-Dial context here, include this context in your [default] dial-plan context and all one-digit extensions will be matched in Speed-Dial context and perform the functionality if anything matches else it'll be skipped.

Wednesday, October 19, 2011

Asterisk Stress testing (with Media) Using SIPp

Today I was required to stress test a client setup with media.
Signalling only can make us feel that our server is capable of handle call volume greater than even 2000 calls per asterisk server. This may not be the case when Media is involved in the call.

Using SIPp with some media file was causing me way too much troubling setting up. So what I did is, use Asterisk Servers as source for Media stream and trigger Bulk of Calls using SIPp. This Asterisk server then start a new call to Client's SBC.

The Dialplan of the originator Asterisk Servers was written such that whenever the call is answered by remote end it transfer the call flow control to another macro "play-media" where I waited for some time and then SendDTMF (required by the remote end) as Extension where I need call to be forwarded and then Start Playing MusicOnHold there.

This simple setup enabled me to load-test the deployment within minutes.

Following are the configurations and steps I took on Originator Asterisk Servers.

1- Install SIPp

#cd /usr/src
#tar zxvf sipp.svn.tar.gz
#cd sipp.svn

This installed SIPP on my machine. then I made its link to sbin directory so sipp be used anywhere from the shell.

#ln -s /usr/src/sipp.svn/sipp /usr/sbin

2- Add sipp user in sip.conf

#vim /etc/asterisk/sip.conf
Add these


Save and quit.

2- Add Dialplan for use with sipp.

#vim /etc/asterisk/extensions.conf

Add these lines.
;include => default

exten => service,1,SET(count=1)
same => n,SET(CALLEER=${RAND(0,9999)})
same => n,SET(CALLERID(num)=$[4130000000 + ${CALLEER}])
same => n,DIAL(SIP/5609871234@CLIENTSBCPEER,,M(play-media))
same => n,hangup()

exten => s,1,Wait(2)
same => n,SendDTMF(879123455232#) ; Destination Extension with indefinite MusicOnHold
same => n,Musiconhold(); Transmit Music from my side to remote server/extension
same => n,Hangup()

Save and exit to linux console.

3- Start sending Calls from sipps - I know its a long command

#sipp -pause_msg_ign -trace_err -users 1 -t u1 -watchdog_minor_maxtriggers 12000 -watchdog_major_maxtriggers 1000 -i [current.asterisk.server.ip] -p 7000 -aa -default_behaviors pingreply -sleep 1 -mp 10000 [current.asterisk.server.ip]:[asterisk_sip_port]

Finally you'll see calls starting in Originator Asterisk console and soon will be reaching destination machine.
Make sure your destination machine knows your Call attack is coming and the destination where you need calls be terminating could be an infinite MusiconHold() command so all the calls stay established while you keep in increasing the call volume.

Monday, October 10, 2011

Asterisk Use Cases

Asterisk Usage Scenarios

This is going to be a very high level view of what our VoIP server can do. In future posts we'll configure our server to provide the functionality as presented in attached image, but before that I'll try show different Live deployment scenarios ranging from SMEs to Large scale environments i.e a VoIP provider company.

Here are a few use cases for Asterisk VoIP Server.

1- IP-PBX (Personal telephone exchange for home or offices)
2- Call Centers
3- IVR services
4- Calling Card Solutions
5- Fax 2 email, Email 2 Fax
6- Automated message broadcasting systems
7- Conference Calling Services
8- So much more....