Revision
14488
Author
gled
Date
2009-08-11 10:13:51 -0500 (Tue, 11 Aug 2009)

Log Message

initial ivr class, needs a lot of work

Added Paths

Diff

Added: freeswitch/trunk/contrib/gled/php/class.ivr.php (0 => 14488)


--- freeswitch/trunk/contrib/gled/php/class.ivr.php	                        (rev 0)
+++ freeswitch/trunk/contrib/gled/php/class.ivr.php	2009-08-11 15:13:51 UTC (rev 14488)
@@ -0,0 +1,195 @@
+<?php
+declare(ticks=1);
+pcntl_signal(SIGPIPE,  "sig_fs");
+
+function sig_fs($signo) {
+	file_put_contents('/devel/log/ivr.log',date("Y-m-d H:i:s").": BROKEN PIPE, call has been hung up\n",FILE_APPEND);
+	exit();
+}
+
+class IVR {
+	var $in = NULL;
+	var $out = NULL;
+	var $con_data = array();
+	var $logfile = '/devel/log/ivr.log';
+
+	function IVR() {
+		ob_implicit_flush(true);
+		$this->in = defined('STDIN') ? STDIN : fopen('php://stdin', 'r');
+		$this->out = defined('STDOUT') ? STDOUT : fopen('php://stdout', 'w');
+
+		stream_set_blocking( $this->in,0);
+
+		fwrite($this->out,"connect\n\n");
+		$buf = $this->wait_answer();
+		if ($buf == '') {
+			$this->log('Huhoo, cannot read setup infos... exiting');
+			exit();
+		}
+		$this->con_data = $this->parse_response($buf);
+		$this->log("New call uuid:{$this->con_data['channel-unique-id']}");
+/*
+		fwrite($this->out,"myevents\n\n");
+		$buf = $this->wait_answer();
+*/
+	}
+
+	function log($str) {
+		file_put_contents($this->logfile,date("Y-m-d H:i:s").": $str\n",FILE_APPEND);
+	}
+
+	function check_hangup($ret='') {
+		if ($ret == '')
+			$ret = $this->parse_response($this->try_read());
+		if ( isset( $ret['content-type'] ) && isset( $ret['content-disposition'] )
+			&& $ret['content-type'] == 'text/disconnect-notice' 
+			&& $ret['content-disposition'] == 'disconnect' )
+				return true;
+		return false;
+	}
+
+	function send_cmd($cmd,$app=FALSE,$args=FALSE) {
+		fwrite($this->out, "sendmsg\n");
+		fwrite($this->out, 'call-command:'. trim($cmd)."\n");
+		if ($app)
+			fwrite($this->out, 'execute-app-name: '.trim($app)."\n");
+		if ($args)
+			fwrite($this->out, 'execute-app-arg: '.trim($args)."\n\n");
+		fwrite($this->out,"\n\n");
+		return $this->wait_answer();
+	}
+
+	function execute($app,$args=FALSE) {
+		return $this->send_cmd('execute',$app,$args);
+	}
+
+	function execute_wait($app,$args=FALSE) {
+		return $this->send_cmd_wait('execute',$app,$args);
+	}
+
+	function send_cmd_wait($cmd,$app=FALSE,$args=FALSE) {
+		fwrite($this->out, "sendmsg\n");
+		fwrite($this->out, 'call-command:'. trim($cmd)."\n");
+		if ($app)
+			fwrite($this->out, 'execute-app-name: '.trim($app)."\n");
+		if ($args)
+			fwrite($this->out, 'execute-app-arg: '.trim($args)."\n\n");
+		fwrite($this->out,"\n\n");
+		return $this->wait_answer_block();
+	}
+
+
+	/*
+	* Wait till we find an answer, trouble is that we may have a following and we cut.
+	* we should sleep 100ms more to check if the response is closed ( or read till we find a \n\n
+	*/
+	function wait_answer() {
+		$gc=0;
+		$buf='';
+		while ( $gc++ < 10000 ) { // we wait at max: 10 000 * 200 microseconds = 2 000 000 = 2seconds
+			usleep(200);
+			$c=0;
+			do {
+				$str = fgets($this->in);
+				if ($str == "\n")
+					break 2;
+				else if ($str != '')
+					$buf .= trim($str)."\n";
+			} while (  $str != "" && $c++ < 100 );
+		}
+		return trim($buf);
+	}
+
+	function wait_answer_block() {
+		$gc=0;
+		$buf='';
+		while ( true ) {
+			usleep(200);
+			$c=0;
+			do {
+				$str = fgets($this->in);
+				if ($str == "\n")
+					break 2;
+				else if ($str != '')
+					$buf .= trim($str)."\n";
+			} while (  $str != "" && $c++ < 100 );
+		}
+		return trim($buf);
+	}
+
+	function try_read() {
+		$c=0;
+		$buf='';
+		do {
+			$str = fgets($this->in);
+			if ($str == "\n")
+				break;
+			else if ($str != '')
+				$buf .= trim($str)."\n";
+		} while (  $str != "" && $c++ < 100 );
+		return trim($buf);
+	}
+
+	/* Parse the returning values into an associative array */
+	function parse_response($tmp) {
+		$ret = array();
+		if (trim($tmp) == '')
+			return $ret;
+		$tmp = explode("\n",$tmp);
+		foreach ($tmp as $line) {
+			list($key,$val) = explode(':',$line);
+			$ret[strtolower($key)] = strtolower(trim( urldecode($val) ));
+		}
+		return $ret;
+	}
+
+	function check_retcode($ret) {
+		if ( isset( $ret['content-type'] ) && isset( $ret['reply-text'] )
+			&& $ret['content-type'] == 'command/reply' 
+			&&  ( $ret['reply-text'] == '+ok' || $ret['reply-text'] == 'ok' ) )
+				return true;
+		return false;
+	}
+
+	function answer() {
+		$ret = $this->parse_response($this->execute('answer'));
+		if ( ! $this->check_retcode($ret) )
+			$this->log("Huhooo Answer wasn't ack'd");
+	}
+	
+	function ivr_sleep($time) {
+		$ts = time() + $time;
+		while ( time() < $ts ) {
+			if ( $this->check_hangup() ) {
+				$this->log('Call has been hungup, exiting...');
+				exit();
+			}
+		}	
+	}
+
+	function hangup() {
+		$ret = $this->parse_response($this->send_cmd('hangup'));
+		if ( ! $this->check_retcode($ret) )
+			$this->log("Huhooo Hangup wasn't ack'd");
+	}
+
+	/*
+	* Play a file and returns when finished. ( wrong way to do the job, if user hangup we're not warned and wait for nothing )
+	*/
+
+	function playback($file) {
+		$ret = $this->parse_response($this->execute_wait('playback',$file));
+		if ( ! $this->check_retcode($ret) )
+			$this->log("Huhooo playback wasn't ack'd");
+	}
+
+
+	function close() {
+		if ($this->in != NULL)
+			fclose($this->in);
+		if ($this->out != NULL)
+			fclose($this->out);
+	}
+}
+
+?>