Archive

Archive for the ‘Asterisk’ Category

SSH onto iTouch, PHP AGI optimisation and hangup code for Asterisk

March 24th, 2009 No comments

Hi all,

Have been back on the php trail again recently. On problem I’ve had is to do with executing a certain piece of code every 20 seconds. One way in which I was doing it was:

[code lang="php"]
startTime = time();

while(true)

{ endTime = time();

if(endTime - startTime > 20)

{ startTime = time();

//Code

}

}
[/code]

This however is quite harsh on the CPU. If came up with a better and more obvious way to do time-based looping

[code lang="php"]
while(true)

{ sleep(20);

//Code

}
[/code]

This loops around every 20 seconds and runs the piece of code and is much nicer on the CPU :)

I’ve been using PHP AGI which hooks into the Asterisk Extensions.conf dialplan.

One of the other problems I’ve been having is that the php scripts weren’t being killed by asterisk when a user hangs up in the middle of the call.

The solution is to register a handler to react to the hangup event

[code lang="php"]
if(function_exists('pcntl_signal'))

{ pcntl_signal(SIGHUP,'sig_handler');

}
[/code]

This registers the function sig_handler to be run when a hangup is detected within the php script execution

[code lang="php"]
function sig_handler($signo)

{ //Other code, CDR and closing MYSQL conns

exit(0);

}
[/code]

The exit closes the php script thus freeing up the CPU.

I ssh’ed onto my iTouch yesterday. I followed the instructions here http://hacktheiphoneitouch.blogspot.com/2007/12/installing-ssh-client-on-112-iphone.html for the MAC, works nicely. Put on Apache and PHP, not tested them as of yet but I’m sure they’ll work nicely as a simple webserver. Haven’t upgraded from 1.1.2 as of yet couldn’t be bothered jailbreaking again but when 1.1.3 is jailbroken out I’ll consider upgrading. Want to get the mail, stocks etc new apps at some stage……free preferably. Thinking of looking for a ColdFusion server for the iTouch, major long shot but would be hilarious if I got it working!

Categories: Archive Post, Asterisk, Mac, PHP AGI Tags:

PHP Agi – beware!

March 24th, 2009 1 comment

Hi all,

I setup a new install of Asterisk on a Virtual Ubuntu Server this week. As expected I ran into several problems when trying to get the whole thing up and running, mostly to do with CDR. I’m using a mySQL backend to record CDR data. I obtained the asterisk-addons package and the instructions indicate to do the usual ./configure, make and make install to cleanly install the cdr_addon_mysql module which is loaded by Asterisk at startup and is used to connect and write to the MySQL DB. The build goes fine, no problems indicated along the way.

So I went and got all the sql conf files up to speed(add cdr_addon_mysql to modules.conf, set enabled to yes in cdr.conf and add a mysql module to the end of it and altered cdr_mysql.conf & res_mysql.conf to match my DB settings) but nothing happened to my CDR table. After looking at the modules loaded in Asterisk I saw that the cdr_addon_mysql.so wasn’t being loaded. Seeing that I went back to the Makefile in the asterisk-addons directory and saw that asterisk.h was missing. Looking at the Asterisk wiki I was indicated to create a symbolic link to /usr/src/asterisk so that the build could find Asterisk. I did this but the error persisted. I placed the asterisk.h in the same directory but still the same problem.

Become impatient I looked for other ways to get the mysql module installed. I added the lines deb:ftp://ftp.us.debian.org/debian unstable main and deb-src ftp://ftp.us.debian.org/debian unstable main to /etc/apt/sources.list and did an apt-get update. Now I was able to do apt-get install asterisk-mysql and the addon was automatically got and placed in my /usr/lib/asterisk/modules and loaded up at startup of Asterisk :) Still isn’t working though my settings must be wrong somewhere.

Here is what I did to install Asterisk….

 Need to get install seperately :
    apt-get install Asterisk
    apt-get install Build-essential
    apt-get instal subversion

    Setup Call Logging CDR - still not working fully
    MySQL - cmd MySQL for CDR
    apt-get instal Mysql-server
    apt-get install Mysql-devel
    Download asterisk-addons from digium svn and compile, this is whats giving me bother building is failing. Follow instructions above.

    Execute MYSQL scripts to create database tables. Grant privileges to asterisk@localhost user.

    apt-get Install PHP5-cli php5-common php5-pear php5-mysql

    Install SOX and Lame for mp3 playback and file conversions
    apt-get install sox lame mpg123

    For TTS:
    apt-get festival festvox-8k
    Change /etc/Festival.scm to match one at http://www.voip-info.org/wiki/view/Asterisk+festival+installation

    Update festival.scm to set the default to be voice_rab_diphone
    Change the .scm /usr/share/festival/voices/whatever the voice is called/festvox/voicename.scm. Search for Duration_Stretch and change this value. Restart festival and test. I used 1.4 for rab_diphone.

    Get PHPAGI.php and the other agi modules at http://phpagi.sourceforge.net/ put them in /usr/share/asterisk/bin directory
    Get Magpie RSS for podcast reader and place MagpieRSS directory in /usr/share/asterisk/bin
    Create a cache directory that is writable by Asterisk in the /usr/share/asterisk/bin directory

    Copy existing iax.conf,sip.conf, extensions.conf over to /etc/asterisk

    Also copy existing cdr.conf, jabber.conf, gtalk.conf, festival.conf, dsnmgr.conf,cdr_custom.conf,res_mysql_conf

    Need to get new sound files and put in /usr/share/asterisk/sounds
    Get php scripts and put in /var/lib/asterisk/agi-bin OR /usr/share/asterisk/bin

    Disable res_pgsql and res_odbc

Have been doing a lot of work with PHP AGI in the last week. I’ve been charged with the job of grabbing some XML from a database, parsing it and then playing back a bunch of files whilst recording user input. So looking around I saw that SimpleXML is a nice easy way of parsing XML with PHP and is built into PHP5. Sweet. So I began to go parse some of the xml using SimpleXML…below is an XML snippet like what I had:


    xyz

So I basically created the SimpleXMLElement

$theXML = new SimpleXMLElement('xyz');

Then to access the child of the root element I did this:

$child = $theXML->child;

All good so far. To see what was coming back I used the ‘verbose’ function of phpagi. As all that was being saved in the child variable was a string I was suprised to see what was being output on the Asterisk console:

SimpleElement Object
{
    [0] -> xyz
}

So I began to think an array was being saved in ‘child’ and tried accessing and outputting $child[o]. Again the verbose function output the EXACT same output for the $child[0] and $child. Confused I was going around in circles and doing lots of tutorials to see where I was going wrong but couldn’t find it, it is very simple after all its hard to get wrong!

The problem was to do with the php agi VERBOSE function which does a print_r on the passed in information. I decided to test if Asterisk would convert the ‘array’ in $child to text so I used the text2wav function to output the variable. Funny thing was it would just say ‘xyz’ which is exactly what I wanted in $child. So essentially I was troubleshooting a problem that didn’t exist all because of some funky output from the verbose function.

All in all my advice to any php agi Asterisk programmers would be : DON’T TRUST THE PHP AGI VERBOSE FUNCTION!!

Categories: Archive Post, Asterisk, PHP AGI Tags:

PHP named locks, redirecting & logging

March 24th, 2009 No comments

Hi all haven’t posted in a while have a couple of posts to catch up on :)

I’ve recently have the need to perform locking in php on the server level. Basically I want just a single php script to execute a piece of code at any time. This requirement was brought about by race conditions whereby two php scripts would go and execute the same piece of code which would consequently conflict with one another. I needed to stop this. The solution is nice and easy and works a treat.

Whenever a php script comes in and requests a lock on a piece of code it attempts to create a directory using phps mkdir with a specific name myLock1. If the directory already exists then the mkdir returns false and the locking fails. If the mkdir completes then the php script has locked the section of code. Now when another seperate php script comes in and tries to create the directory mkdir will return false and the locking will fail.

When the php script is finished with a piece of code then it unlocks by deleting the directory using rmdir. Now a new php script is free to come in lock the piece of code again.

This locking works across all php scripts (i.e. is server wide) and provides named locks as you can give the directories different names. So one section of code may be locking a myLock1 directory and another part be locking myLock2 directory but these won’t interfere with one another. I’ve attached the code for this simple locking below and highlighed how it would be used to lock a piece of code.

class FLock
	{	private $files = array();
		private $oUUID = "";

		function __construct()
		{	$this->oUUID = new UUID();
		}	

		function __destruct()
		{	foreach($this->files as $file)
			{
				fclose($this->files['$file']);
			}
		}

		private function saveFileHandle($filepath)
		{
			if(!array_key_exists("$filepath",$this->files))
			{
				$this->files["$filepath"] = array();
				$this->files["$filepath"]['directory'] = $filepath;
				$this->files["$filepath"]['locked'] = false;

			}

		}

		public function attemptFileLock($filepath=false, $lockFile=true)
		{
			global $fileLockingLocation; 

		    $this->saveFileHandle($filepath);

			$canLock = false;

		    if($lockFile == true)
			{	if(!$this->files["$filepath"]['locked'])
				{	try
					{
						$canLock = mkdir("$filepath");
						if($canLock)
						{
							$this->files["$filepath"]['locked'] = true;

						}

					}
					catch(Exception $ex)
					{
						LogError($ex);
					}
				}
			}
			else
			{	if($this->files["$filepath"]['locked'])
				{
					rmDir("$filepath");

					$this->files["$filepath"]['locked'] = false;

					//TODO - Fix
					return true;

				}
			}

		    return $canLock;
		} 

		public function removeAllFileLocks()
		{	foreach($this->files as $file)
			{	rmDir($file['directory']);
				$this->files[$file['directory']]['locked'] = false;
			}
		}
	}

To lock the some code you need to just do like what I’ve done below.

$this->oFL = new fLock();
$fileLockResult = $this->oFL->attemptFileLock("/fileLocks/".$lockName."_lock",true);
if($fileLockResult)
{
      //Perform mySQL inserts,deletes etc.
      $fileLockResult = $this->oFL->attemptFileLock("/fileLocks/".$lockName."_lock",false);
}
else
{
     //Sleep between 0.5 - 1 second
     usleep(500000+(mt_rand(1,10))*500000);
}

I’ve had to perform php redirects of late also, its nice and easy but as Michael found out, even when you put a redirect in a chunk of code, the rest of the script gets parsed and the redirection doesn’t occur straight away. So you may want to put in a die() or something after the redirect if you wish to abort the rest of the page’s processing.

   header( 'Location: http://www.yoursite.com/new_page.html' ) ;

Performing error logging with PHP is another task I’ve wanted to do of late. Basically I’ve created a php wrapper page that takes in a script location from the Asterisk dial plan and executes the passed in script within a try catch block. Wrapping the script execution within the try provides a simple error logging mechanism. Anywhere I want to log errors that are fatal to the application I can just perform a throw within a php script and the top-most wrapper will always catch and log the error.

#!/usr/bin/php -q
get_variable("scriptName");
		$agi->exec("AGI",$scriptName['data']);

	}
	catch(Exception $ex)
	{	if(!isset($agi))
		{	$agi = new AGI();
		}

		$errorFileName = 'error-'."date-".date("dmy_His");
		$errorInfo = "Error message: ".$ex->getMessage();
		$errorCode = "Error code: ".$ex->getCode();
		$errorFile = "File: ".$ex->getFile();
		$errorLineNo = "Line number: ".$ex->getLine();

		if(!isset($agi))
		{
			$errorCode = $errorCode." - AGI cannot be created.";
			$errorFile = $errorFile." - applicationWrapper.php catch block.";
		}

		//Log to error log directory
		writeVariableToFile($errorInfo,$errorFileName);
		writeVariableToFile($errorCode,$errorFileName,true);
		writeVariableToFile($errorFile,$errorFileName,true);
		writeVariableToFile($errorLineNo,$errorFileName,true);

		if(isset($agi))
		{	//Log to terminal if possible
			$agi->verbose($errorInfo);
			$agi->verbose($errorCode);
			$agi->verbose($errorFile);
			$agi->verbose($errorLineNo);
			$agi->text2wav($ex->getMessage());
		}

		//Log to php error log
		error_log($errorInfo);
		error_log($errorCode);
		error_log($errorFile);
		error_log($errorLineNo);

		exit(0);

	}

	exit(0);
?>

The error_log is a built in php error logging system. You can specify where PHP logs errors to within you php.ini config file, I set it up to log to the system log by uncommenting the error_log = syslog line but you can easily setup your own location for logging errors.

From the Asterisk dial plan i.e. the extensions.conf you basically have something like

exten => s,n,Set(scriptName=/my/Path/To/File/myfile.php)
exten => s,n,AGI(/path/to/wrapper/applicationWrapper.php)
exten => s,n,Hangup()
Categories: Archive Post, Asterisk, PHP Tags:

WP error,copying XML children,ztdummy fun and ArrayDeleteAt gotcha

March 24th, 2009 No comments

Hi,
I haven’t posted in a while as my site got blocked by IT at work for some reason!

I’ve had a lot of stuff recently that I could have posted it but unfortunately I’ve forgotten most of it so don’t have a massive amount to write about.

Firstly I had a problem with my wordpress account that when someone attempted to subscribe to the blog I would get an error something like

 “Cannot modify header information - headers already sent” 

After having a look around the place I saw that this is resolved but having extra whitespace before or after tags. I had some JS in one of my php that was causing the RSS subscription to crap out. Fixed it so should be working now.

Got my MSc result in the last couple of days, got 95% in my thesis which can be got here. That means I got a ‘Distinction’ in my MSc which I’m very happy about. You can read about my progress through the GOAP archives in the blog.

I got an error when using ColdFusion’s XMLParse to go through two XML documents and copy one part of the XML to another document. I was getting the error ‘WRONG_DOCUMENT_ERR’ when attempting to do an ArrayAppend to an existing XML node. So I had to go and create each node individually using recursion. Here’s a snippet of the code, I had to create each node individually and set the attributes, Cdata etc.


	
	
       


        
        
	
		
	
	       
	











WARNING: I’ve modified this from my original code and not tested fully so mightn’t work but is v close to working only needs a few small changes to work I’d imagine.

I was having a problem with Asterisk on a VM Ubuntu server during the week. The error message I was getting was ‘app_meetme.c: Unable to open pseudo device’. The reason for this error is that MeetMe requires a timing device to work, there is Zaptel hardware for Asterisk that you can buy and use. On the Asterisk CLI type zap show status, if you don’t have anything there then thats you’re problem. A module called Ztdummy can emulate the Zaptel hardware and allow the Meetme app to work. To do this I got the Zaptel source from SVN svn co http://svn.digium.com/svn/zaptel/branches/1.4 . , did a ./configure, make and make install and make config. After that I ran this script to finish the install.

genzaptelconf -sdvM
/etc/init.d/zaptel start

Finally for now I had another issue when deleting items from a ColdFusion array. I was looping through one by one and on a certain condition delete an element and move on. I ended up getting the error:

Cannot insert/delete at position 9.
    The array passed has 8 indexes. Valid positions are from 1 to 8.

      
          
      

Coldfusion reorders the indexes after deleting and isn’t too clever about it so for some reason seems to think that there is 9 elements in the array when 1 has been deleted. The solution is very simple(although I think the language should be a little clever to handle this properly):

Categories: Archive Post, Asterisk, ColdFusion, XML Tags:

ODBC Cdr with Asterisk

March 24th, 2009 No comments

Hi all,
Today I’ve been setting up Asterisk to work with ODBC and MySQL.

I started out by creating the MySQL table, the code is:

CREATE TABLE cdr(calldate DATETIME NOT NULL,clid varchar(80) NOT NULL DEFAULT 'aDefaultValue',src varchar(80) NOT NULL DEFAULT 'aDefaultValue',dst VARCHAR(80) NOT NULL DEFAULT 'aDefaultValue',dcontext VARCHAR(80) NOT NULL DEFAULT  'aDefaultValue',channel VARCHAR(80) NOT NULL DEFAULT  'aDefaultValue',dstchannel VARCHAR(80) NOT NULL DEFAULT 'aDefaultValue',lastapp VARCHAR(80) NOT NULL DEFAULT  'aDefaultValue',lastdata VARCHAR(80) NOT NULL DEFAULT  'aDefaultValue',duration int(11) NOT NULL DEFAULT '0',billsec int(11) NOT NULL DEFAULT '0',disposition VARCHAR(45) NOT NULL DEFAULT  'aDefaultValue',amaflags int(11) NOT NULL DEFAULT '0',accountcode VARCHAR(20) NOT NULL DEFAULT  'aDefaultValue',uniqueid VARCHAR(32) NOT NULL DEFAULT  'aDefaultValue',userfield VARCHAR(255) NOT NULL DEFAULT 'aDefaultValue');

WARNING: I’ve found that any spaces in the above create table code will cause syntax errors in mySQL.

I did the install in Ubuntu so you may need to do other steps to install the drivers needed for ODBC on your OS.
You need to get MySQL and iODBC and unixodbc.

apt-get install unixodbc libmyodbc unixodbc iodbc

This should install all the packages needed for MySQL and ODBC.

Go and edit your /etc/odbcinst.ini and paste in:

[MySQL]
Description     = MySQL ODBC MyODBC Driver
Driver          = /usr/lib/odbc/libmyodbc.so
Setup           = /usr/lib/odbc/libodbcmyS.so
CPTimeout       = 0
CPReuse         = 0

Now go and edit /etc/odbc.ini

[MySQL-asterisk]
Description     = MYSQL ODBC Driver Testing
Driver          = MySQL
Socket          = /var/run/mysqld/mysqld.sock
Server          = localhost
User            = YourUsername
Password        = YourPassword
Database        = YourDatabase
Option          = 3

No go and edit /etc/asterisk/cdr.conf and set enabled = yes and at the bottom of the cdr.conf add the following

[odbc]
usegmtime=yes
loguniqueid=yes
loguserfiled=yes

Then go and edit /etc/asterisk/res_odbc.conf, add this:

[mysql]
enabled => yes
dsn => MySQL-asterisk
username => YourUsername
password => YourPassword
pre-connect => yes

Finally edit /etc/asterisk/cdr.conf and replace the existing global with:

[global]
dsn=MySQL-asterisk
;username=asterisk
;password=asterisk
loguniqueid=yes
dispositionstring=yes
table=cdr               ;"cdr" is default table name
usegmtime=no

Go to your asterisk console ( type asterisk -vvvvvvvvr) and type restart now
Connect once more and type module reload res_odbc. Make sure it all looks good
Type module reload cdr_odbc and see if it is connecting ok.

If it doesn’t make sure you can access mysql from the command line and make sure you have given asterisk permissions on the mysql database. i did this but it may be a bit insecure, I’m only developing at the moment

GRANT ALL PRIVILEGES ON asterisk.* TO YourUsername@localhost IDENTIFIED BY 'YourPassword'
Categories: Archive Post, Asterisk Tags:

Installing and customising App Conference Vicidial

March 24th, 2009 2 comments

After getting App_conference working recently but after using it for a bit I found that it is a little TOO stripped down for my liking. It doesn’t do anything else besides put people into a conference. This may be fine for some people but I need more than that so I decided to check out the Vicidial version of app_conference that sends DTMFs to the Vicidial Manager. It also plays enter and exit sounds which I thought would be nice to have. I thought that if I could see what was receiving the DTMFs and sending them off to the Vicidial manager I could modify this and perform custom actions.

Well after getting the code for app_conference here and first attempted to compile it I got a few errors. I’m compiling on a Ubuntu Server with Asterisk already installed, see my previous post about what the pre-requisites are for app_conference. Some of the errors are below:

app_conference.c:51: warning: data definition has no type or storage class
app_conference.c:51: warning: type defaults to ‘int’ in declaration of ‘STANDARD_HANGUP_LOCALUSERS’
app_conference.c:52: warning: data definition has no type or storage class
app_conference.c:52: warning: type defaults to ‘int’ in declaration of ‘LOCAL_USER_DECL’
app_conference.c:55: warning: no previous prototype for ‘unload_module’
app_conference.c: In function ‘unload_module’:
app_conference.c:58: warning: passing argument 1 of ‘__ast_module_user_hangup_all’ from incompatible pointer type
app_conference.c: At top level:
app_conference.c:67: warning: no previous prototype for ‘load_module’
app_conference.c:80: warning: no previous prototype for ‘description’
app_conference.c:85: warning: no previous prototype for ‘usecount’
app_conference.c: In function ‘usecount’:
app_conference.c:87: warning: implicit declaration of function ‘STANDARD_USECOUNT’
app_conference.c: At top level:
app_conference.c:92: warning: no previous prototype for ‘key’
app_conference.c: In function ‘app_conference_main’:
app_conference.c:106: warning: implicit declaration of function ‘LOCAL_USER_ADD’
app_conference.c:112: warning: implicit declaration of function ‘LOCAL_USER_REMOVE’
app_conference.c:106: warning: ‘u’ is used uninitialized in this function
app_conference.c: In function ‘usecount’:
app_conference.c:87: warning: ‘res’ is used uninitialized in this function

Quite a few errors. After some Google’ing around I found that a lot of these errors were because the newer version of Asterisk no longer supported these variables/functions. I began to churn through the errors by going into app_conference.c, fixing them and recompiling.

Below are the steps I took to get the app_conference going

Replace ‘STANDARD_HANGUP_LOCALUSERS’ with
ast_module_user_hangup_all(); // defined in asterisk/module.h

struct localuser *u ; with
struct ast_module_user *u ;

LOCAL_USER_ADD( u ) ; with
u = ast_module_user_add(chan);

LOCAL_USER_REMOVE( u ) ; with
ast_module_user_remove(u);

place static before the ‘int’ & char for all methods with it except for app_conference main function.

Paste into the very bottom of app_conference main. This registers the Conference as an Asterisk module.

#define AST_MODULE “Conference”
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY,
“Channel Independent Conference Application”);
#undef AST_MODULE

I’ve attached the new app_conference.c that I know definitely compiles to this post. After doing ‘make’ on the app_conference there are still a few warnings but they don’t matter. You’ll be left with app_conference.so. Copy this to /usr/lib/asterisk/modules. When you try to connect to the Asterisk CLI it will automatically shutdown as it spots a shared object that it previously didn’t have so you’re better off just doing /etc/init.d/asterisk restart and then joining the Asterisk CLI. Test if the module is present by typing show modules like conference and you should see it returned. If not something is wrong, you may need to add it in modules.conf so that its loaded at load time. Check out the Asterisk wiki for the Conference commands and how to run it – the version we’ve installed is down under the ‘app conference with VICIDIAL ‘ section but works well so far.

There is code in the process_incoming function in member.c that can be modified to allow dtmf actions. See the default below:

[code lang="c"]
if (
f->frametype == AST_FRAME_DTMF
&& member->send_dtmf
)
{ // send the DTMF event to the MGR interface..
manager_event(
EVENT_FLAG_CALL,
"ConferenceDTMF",
"Channel: %s\r\n"
"Key: %c\r\n",
member->channel_name,
f->subclass
) ;
[/code]

The default is to pass on the DTMF to the Vicidial manager but I’ve removed this and added in a menu system and allow the user quit out of the conference and will be adding some more features. The f->subclass contains the current DTMF pressed.

I’ve found one problem with this app at present. When audio is being played and we attempt to play another piece of audio on the same channel I get a whole bunch of repeated errors:

[Mar 10 06:47:17] WARNING[9898]: codec_gsm.c:144 gsmtolin_framein: Invalid GSM data (1)
[Mar 10 06:47:17] WARNING[9898]: translate.c:199 framein: gsmtolin did not update samples 0

This is caused as the app isn’t clever enough to realise that audio is already playing so just need to put a check in the play_basic_sound function but haven’t got round to doing this yet.

Categories: Archive Post, Asterisk Tags:

PHP AGI Hangup

March 24th, 2009 2 comments

Hi all,

Hangups are handled by PHP AGI by registering a sig_handler function. Whenever a user hangs up then this function is called. However as I found out recently you cannot use the agi within the hangup handler. You can use the verbose command and see what it outputs to the system/error log as the verbose command outputs to the default php error log as well as to the Asterisk CLI. Here is some simple code to register your hangup handler:

function sig_handler($signo)
{	//Do some stuff in here
	exit(0);
}

//Register the hangup handler
if (function_exists('pcntl_signal'))
{
      pcntl_signal(SIGHUP,  "sig_handler");
}

I’ve no idea what pcntl_signal is but its installed alongside Asterisk by default I believe so you shouldn’t need to do anything extra to get it working.

If you are stuck, the approach we took is to set some variables in the dialplan and have some conditional statements within the dialplan to check these variables. There is a special extension ‘h’ which is called when a hangup occurs. The conditional Gotoif checks for a boolean statement which if true will attempt to go to the first extension, if false it will go to the second extension.

exten => h,1,GotoIf($[${EXISTS(${aVar})}]?2:4)
exten => h,2,DoSomething()
exten => h,3,GotoIf(${aVar} > 0 ? 4:5)
exten => h,4,Goto(some_extension)
exten => h,5,Goto(some_extension)

PS. I’ve noted that labels don’t appear to be working(for me at least) in the dialplan. By labels I mean:

exten => h(myLabel),2,DoSomething()

According to the docs I should be able either of below within a GotoIf:

exten => h,1,GotoIf($[${EXISTS(${aVar})}]?myLabel:4)
exten => h,1,GotoIf($[${EXISTS(${aVar})}]?2(myLabel):4)

Both of these fail for me, telling me that the extension doesn’t exist.

Categories: Archive Post, Asterisk, PHP, PHP AGI Tags: