Monday, October 27, 2014

Asterisk quick tips 1

Quick asterisk tips part 1

1. variables

when using expressions and a variable may not exist enclose it in double quotes so it gets interpreted into valid code and doesn't thrown an error

$["${VAR}"="ENDED"]
So if the VAR variable doesn't exist this gets interpreted into ""="ENDED" which will be false.

2. variable as variable name

If you get to advanced asterisk there may be a case where you need a variable to be a variable name, here is how to check if it is set

$["${${ARG3}}"!=""]

in this example ARG3 is a variable that holds the name of the variable to check.

3. stackpop

when using subroutines you have to return() to go back to the calling location.  But inevitably there are cases where you don't want to return.  No problem, just use stackpop() to remove the return location and you can go wherever you want in the dialplan without worrying about memory issues tracking the return location which isn't needed.

4. Special extensions

Learn the asterisk special extensions available.  Specifically the T extension, it allows you to set the timeout for a call, but instead of the system just hanging up you can run dialplan code to handle the channel properly.

  • s - What to do when an extension context is entered (unless overridden by the low level channel interface) This is used in macros, and some special cases. "s" is not a generic catch-all wildcard extension.
  • i - What to do if an invalid extension is entered
  • h - The hangup extension, executed at hangup
  • t - What to do if nothing is entered in the requisite amount of time.
  • T - This is the extension that is executed when the 'absolute' timeout is reached. See "core show function TIMEOUT" for more information on setting timeouts.
  • e - This extension will substitute as a catchall for any of the 'i', 't', or 'T' extensions, if any of them do not exist and catching the error in a single routine is desired. The function EXCEPTION may be used to query the type of exception or the location where it occurred.

PRK (Lasik) after one year

After years of using glasses I finally tried contacts and loved it. So after 2 years of contacts and the daily routine required I finally started to look into lasik. I setup my appointment with LasikPlus.

1. First appointment 

assistant had me do a number of different tests, looked into 3 different machines, and then the last step of getting drops put into my eyes to numb them for more testing.  After that they give a recommendation, in my case Photorefractive keratectomy (PRK) since my cornea was apparently too thin to slice it open.  More gory details on PRK later.

2. Preparation

No contacts for 14 days prior to surgery.  And don't have any problems giving yourself eye drops since there are 3 sets of them multiple times a day leading up to the day of surgery.  Some of the drops burned a little, but not much issue.

3. Surgery day

Get someone to drive you.  Got called into the waiting room which was the first time actually meeting the surgeon, got some powerful eye drops that numbed everything around your eyes.  Surgeon talked for a few minutes, prefaced that the next few days will really suck (his actual words).  PRK differs from Lasik in that the epithelial layer of the eye is scraped off instead of a flap being created during lasik.  After the short conversation we went into the laser room, laid down on in the chair to get positioned under the laser.

4. Surgery

Overall the entire process couldn't have taken more than 5 minutes.  Here are all the details.  First they put a device to hold open the eye lids, don't worry the eyes are so numb I didn't feel a thing.  The surgeon does so many of these he is quick.  My other eye was covered with some sort of patch.  At that point the epithelial layer was removed with what seemed like a little power tool with a soft tip.  There was some pressure, but felt nothing.  He then took some brush to clear off my eye.  He positioned me under the laser and asked me to focus on the lighted circle and to keep both eyes open, which I found impossible.  At that point the laser fired, I saw flashes of purple light with my vision varying with each pulse.  It was very quick, then the eye was flushed with cold water, and a bandage contact lens was positioned on my eye and the entire process was repeated for the other eye.  After that I got up and was done, immediately saw improvement.

5 Post Surgery - First few days

It was explained that the first few days could be bad, pain, tearing etc.  For me it wasn't too bad, only one morning had tearing, I just went back to bed and was fine by the afternoon.  Eye drops continued.  After 5 days I was able to drive myself to the followup appointment where the bandage contact lens was removed.

6 Post Surgery - First month

The first month was very difficult.  I have a tech job which means a lot of work on the computer.  But for the first month, till the steroid drops were done, everything on a screen was doubled.  Nothing I could do, closing one eye or the other still everything doubled.  So it took a lot of focusing and frustration to get through that point.  Apparently the steroid drops that are continued for the first month may be there to slow the healing process of the epithelial layer that was removed so that it doesn't scar.  Good news was once those drops were done vision immediately improved.  1 month visit and I had better than 20/20 vision (which I had with my contacts prior to the surgery).

7 Post Surgery - First year

Its amazing how quickly the daily routine of waking up not being able to see the alarm clock and having to put in contacts and clean them every night is forgotten.  I am very pleased with the surgery and would recommend it if you were considering it, my experience was very good and successful.  Only issue I have is when tired there is some starburst while driving and blurryness reading the TV on screen guide.

Asterisk IVR application tips

Finding good documentation on asterisk can be a chore, there are a lot of examples using old versions, and examples using simple dial plans for an office phone, but not much for advanced IVR applications.  Here are a few of the tips and tricks we have found over the last year using asterisk as an IVR application platform.


1. Use hangup handler

Your application will usually require some processing when a call ends.  Don't put h extensions in every context.  You can have issues if you need to update, or if you are in a macro/sub when the hangup happens.  Instead asterisk has a nice feature:
Set(CHANNEL(hangup_handler_push)=CALLDONECONTEXT,s,1)
this hangup handler makes sure your code runs in all cases.  Just make sure you call that line at every entry point into the asterisk dialplan

2. Use AGI

AGI, similar to what CGI was for web applications, allows you to use development resources in other programming languages to run advanced code.  PHP is used for command line scripts for our applications.  This allows us to use the same PHP classes and code from asterisk and from our website.
AGI(SCRIPT.php,${VAR1},${VAR2})
AGI scripts can get variables directly from asterisk; however, testing from the command line then becomes impossible.
Something to keep in mind asterisk is unavailable while the script is running, so keep the scripts simple, keep reading for examples where scripts are expected to run lone (credit card processing).

3. Use GoSub and Macro

Don't duplicate dialplan code, learn to use gosub and macro functions

4. Inject audio into a channel

There are numerous reasons to play audio into a channel, whispers for time remaining, etc.  The dialplan code for this is very simple:
[YOURCONTEXT]
exten => s,1,Answer()
 same => n,Wait(0.3)
 same => n,Playback(${AUDIO})
 same => n,Hangup()

exten => do_chanspy,1,Answer()
 same => n,Chanspy(${CHANNEL},qW)
 same => n,Hangup()
the script code is what originates the call and sets the variable with the audio to play, this uses the phpagi project, though we modified the send_request function to a new version that allows multiple variables.
if ($AsteriskAMI->connect($SERVER . ':5038','AMIUSERNAME','AMIPASSWORD')) {
 $asm_data[0]['name']='Channel';
 $asm_data[0]['value']="Local/s@YOURCONTEXT";
 $asm_data[1]['name']='Context';
 $asm_data[1]['value']='YOURCONTEXT';
 $asm_data[2]['name']='Exten';
 $asm_data[2]['value']='do_chanspy';
 $asm_data[3]['name']='Priority';
 $asm_data[3]['value']=1;
 $asm_data[4]['name']='Variable';
 $asm_data[4]['value']='CHANNEL=' . $channel;
 $asm_data[5]['name']='Variable';
 $asm_data[5]['value']='AUDIO=' . $audio;
 $call = send_request2('Originate',$asm_data);
}
This code originates a call to the asterisk system, uses the chanspy app to connect to the channel you want to play the audio on, plays the audio, then hangs up.

5. Redirect a channel to another context

This is useful in a number of cases when you need another channel to be moved based on the action of another, e.g. one caller is waiting on the system to call another then move both into a conference
ChannelRedirect(${CHANNEL},CONTEXT,s,1)

6. Don't allow endless loops

Not sure why, but you will get people or scripts that just sit on the system, so make sure all options that request input from the user.
[macro-Tries]
;arg1=current count
;arg2=max count
;arg3=context to goto if at max count
;arg4=exten
;arg5=priority
exten => s,1,GotoIf($[${ARG1} >= ${ARG2}]?${ARG3},${ARG4},${ARG5})

[CONTEXT]
exten => s,1,Set(Tries=0)
 same =>   n(start),Set(Tries=$[${Tries} + 1])
 same =>   n,Macro(Tries,${Tries},10,BadTries,s,1)
 same =>   n,GoSub(Press_Or_Say,start,1(AUDIOFILE,1,129*,DTMF))
 same =>   n,GoToIf($[${RETURN_CODE}=1]?opt${ENTRY},1)
 same =>   n,Goto(s,start)
this is the framework of an example that will only allow a subroutine, that gets the users menu input, and if the expected results aren't received will retry for 10 times, then forward to the BadTries context where you can give an audio message or just hangup.

7. Long running AGI

As mentioned above AGI holds up asterisk processing, you don't want seconds of dead air while a customer is on the phone.  Here is one example on running a script in the background, looping audio while waiting for a response.
GoSub(BackgroundProcess,s,1(PREAUDIO,PHPSCRIPT.php,VARIABLE,LOOPAUDIO,20,"","",${VAR1}
\"${VAR2}\"))



[TTMBackgroundProcess]
;ARG1 audio that plays
;ARG2 script to call - script has to accept channel as first parameter
;ARG3 variable to check - script must set this variable on the channel given using AMI
;ARG4 audio while processing
;ARG5 number of times to play audio recording before returning failure
;ARG6 return without playing the arg1 audio if script is done quickly
;ARG7 redirect channel immediatly on completed processing - script has to accept this as second parameter
;ARG8 arguments to pass to script, space separated
exten => s,1,Set(i=0)
 same =>   n,AGI(BackgroundProcess.php,${CDR(channel)},${ARG7},${ARG2},${ARG8})
 same =>   n,ExecIF($[${ARG6}=1 && "${${ARG3}}"!=""]?Return())
 same =>   n,Playback(${ARG1})
 same =>   n(waitingloop),ExecIF($["${${ARG3}}"!=""]?Goto(success,1))
 same =>   n,ExecIF($[${ARG5}<${i}]?Goto(failure,1))
 same =>   n,Playback(${ARG4})
 same =>   n,Set(i=$[${i} + 1])
 same =>   n,Goto(waitingloop)

exten => success,1,Set(BACKGROUNDPROCESS=TRUE)
 same =>   n,Return()

exten => failure,1,Set(BACKGROUNDPROCESS=FALSE)
 same =>   n,Return()
And the PHP script
#!/usr/bin/php
/* BackgroundProcess
 * runs a script in the background so AGI can return to asterisk
 * script should take channel and redirect as first to parameters
 * script should set variable that the dialplan expects, or redirects the user to the redirect context,channel,priority
 * 
 */
try {
if (!empty($argv[1]) && is_numeric($argv[1])) {
 $script_override_theater_id = $argv[1];
}

//this is an internal function that sets up the arg variables
$data = asterisk_arguments($argv, array(
 'channel' => 'string', //users channel inside asterisk
 'redirect' => 'string', //context,extension,priority to redirect to or empty if no redirect
 'script_name' => 'string', //php script to run, assumes in the agi-bin/TL directory of the project
 'parameters' => 'string' //parameters to pass to the script, should be space and quoted already
));

$result = array(
 // NO RESPONSE
);

if (!empty($data)) {
 //$AsteriskAGI->verbose(str_replace("\n","",print_r($data,true)));
 $cmd_start = '/var/lib/asterisk/agi-bin/TL/' . $data['script_name'];
 $cmd_end = ' > /dev/null &';
 
 $cmd = $cmd_start . ' "' . $data['channel'] . '" ' .      
  '"' . $data['redirect'] . '" ' .
  $data['parameters'] . 
  $cmd_end;
 $AsteriskAGI->verbose(str_replace('"','|',$cmd));
 exec($cmd);
}

} catch (exception $e) {

}

Thursday, October 23, 2014

New site

First post

Just setting up the new domain and email.  I will be using this site to post about the many technologies I use, hints/tips I have come across, my opinions, etc.  So far upcoming posts include: review of my PRK (lasik) surgery after the first year, android wear, moto360, android phone (been a windows phone user forever, and still prefer it), surface 3 (if it ever gets here), windows phone 8.1, xbox one, xfinity x1 platform, xfinity web streaming, facial recognition, advanced asterisk, and many others.  Follow on twitter as I will begin tweeting out many of the things after I get these initial blog posts completed.