📄 phpagi.php
字号:
{
if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
$proceed = true;
}
if($buffer == '' || $proceed)
{
$res = $this->say_punctuation($text, $escape_digits, $frequency);
if($res['code'] == AGIRES_OK && $res['result'] > 0)
$buffer .= chr($res['result']);
return $res;
}
return array('code'=>AGIRES_OK, 'result'=>ord($buffer{strlen($buffer)-1}));
}
/**
* Plays the given file and receives DTMF data.
* Return early if $buffer is adequate for request.
*
* This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
* while STREAM FILE returns immediately after the first DTMF digit is detected.
*
* Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
*
* If the user doesn't press any keys when the message plays, there is $timeout milliseconds
* of silence then the command ends.
*
* The user has the opportunity to press a key at any time during the message or the
* post-message silence. If the user presses a key while the message is playing, the
* message stops playing. When the first key is pressed a timer starts counting for
* $timeout milliseconds. Every time the user presses another key the timer is restarted.
* The command ends when the counter goes to zero or the maximum number of digits is entered,
* whichever happens first.
*
* If you don't specify a time out then a default timeout of 2000 is used following a pressed
* digit. If no digits are pressed then 6 seconds of silence follow the message.
*
* If you don't specify $max_digits then the user can enter as many digits as they want.
*
* Pressing the # key has the same effect as the timer running out: the command ends and
* any previously keyed digits are returned. A side effect of this is that there is no
* way to read a # key using this command.
*
* @link http://www.voip-info.org/wiki-get+data
* @param string $buffer
* @param string $filename file to play. Do not include file extension.
* @param integer $timeout milliseconds
* @param integer $max_digits
* @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present.
*
* This differs from other commands with return DTMF as numbers representing ASCII characters.
*/
function fastpass_get_data(&$buffer, $filename, $timeout=NULL, $max_digits=NULL)
{
if(is_null($max_digits) || strlen($buffer) < $max_digits)
{
if($buffer == '')
{
$res = $this->get_data($filename, $timeout, $max_digits);
if($res['code'] == AGIRES_OK)
$buffer .= $res['result'];
return $res;
}
else
{
while(is_null($max_digits) || strlen($buffer) < $max_digits)
{
$res = $this->wait_for_digit();
if($res['code'] != AGIRES_OK) return $res;
if($res['result'] == ord('#')) break;
$buffer .= chr($res['result']);
}
}
}
return array('code'=>AGIRES_OK, 'result'=>$buffer);
}
// *********************************************************************************************************
// ** DERIVED **
// *********************************************************************************************************
/**
* Menu.
*
* This function presents the user with a menu and reads the response
*
* @param array $choices has the following structure:
* array('1'=>'*Press 1 for this', // festival reads if prompt starts with *
* '2'=>'some-gsm-without-extension',
* '*'=>'*Press star for help');
* @return mixed key pressed on sucess, -1 on failure
*/
function menu($choices, $timeout=2000)
{
$keys = join('', array_keys($choices));
$choice = NULL;
while(is_null($choice))
{
foreach($choices as $prompt)
{
if($prompt{0} == '*')
$ret = $this->text2wav(substr($prompt, 1), $keys);
else
$ret = $this->stream_file($prompt, $keys);
if($ret['code'] != AGIRES_OK || $ret['result'] == -1)
{
$choice = -1;
break;
}
if($ret['result'] != 0)
{
$choice = chr($ret['result']);
break;
}
}
if(is_null($choice))
{
$ret = $this->get_data('beep', $timeout, 1);
if($ret['code'] != AGIRES_OK || $ret['result'] == -1)
$choice = -1;
elseif($ret['result'] != '' && strpos(' '.$keys, $ret['result']))
$choice = $ret['result'];
}
}
return $choice;
}
/**
* Goto - Set context, extension and priority.
*
* @param string $context
* @param string $extension
* @param string $priority
*/
function goto($context, $extension='s', $priority=1)
{
$this->set_context($context);
$this->set_extension($extension);
$this->set_priority($priority);
}
/**
* Parse caller id.
*
* @example examples/dtmf.php Get DTMF tones from the user and say the digits
* @example examples/input.php Get text input from the user and say it back
*
* "name" <proto:user@server:port>
*
* @param string $callerid
* @return array('Name'=>$name, 'Number'=>$number)
*/
function parse_callerid($callerid=NULL)
{
if(is_null($callerid))
$callerid = $this->request['agi_callerid'];
$ret = array('name'=>'', 'protocol'=>'', 'username'=>'', 'host'=>'', 'port'=>'');
$callerid = trim($callerid);
if($callerid{0} == '"' || $callerid{0} == "'")
{
$d = $callerid{0};
$callerid = explode($d, substr($callerid, 1));
$ret['name'] = array_shift($callerid);
$callerid = join($d, $callerid);
}
$callerid = explode('@', trim($callerid, '<> '));
$username = explode(':', array_shift($callerid));
if(count($username) == 1)
$ret['username'] = $username[0];
else
{
$ret['protocol'] = array_shift($username);
$ret['username'] = join(':', $username);
}
$callerid = join('@', $callerid);
$host = explode(':', $callerid);
if(count($host) == 1)
$ret['host'] = $host[0];
else
{
$ret['host'] = array_shift($host);
$ret['port'] = join(':', $host);
}
return $ret;
}
/**
* Use festival to read text.
*
* @example examples/dtmf.php Get DTMF tones from the user and say the digits
* @example examples/input.php Get text input from the user and say it back
* @example examples/ping.php Ping an IP address
*
* @link http://www.cstr.ed.ac.uk/projects/festival/
* @param string $text
* @param string $escape_digits
* @param integer $frequency
* @return array, see evaluate for return information.
*/
function text2wav($text, $escape_digits='', $frequency=8000)
{
$text = trim($text);
if($text == '') return true;
$hash = md5($text);
$fname = $this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR;
$fname .= 'text2wav_' . $hash;
// create wave file
if(!file_exists("$fname.wav"))
{
// write text file
if(!file_exists("$fname.txt"))
{
$fp = fopen("$fname.txt", 'w');
fputs($fp, $text);
fclose($fp);
}
shell_exec("{$this->config['festival']['text2wave']} -F $frequency -o $fname.wav $fname.txt");
}
else
{
touch("$fname.txt");
touch("$fname.wav");
}
// stream it
$ret = $this->stream_file($fname, $escape_digits);
// clean up old files
$delete = time() - 2592000; // 1 month
foreach(glob($this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'text2wav_*') as $file)
if(filemtime($file) < $delete)
unlink($file);
return $ret;
}
/**
* Use Cepstral Swift to read text.
*
* @link http://www.cepstral.com/
* @param string $text
* @param string $escape_digits
* @param integer $frequency
* @return array, see evaluate for return information.
*/
function swift($text, $escape_digits='', $frequency=8000, $voice=NULL)
{
if(!is_null($voice))
$voice = "-n $voice";
elseif(isset($this->config['cepstral']['voice']))
$voice = "-n {$this->config['cepstral']['voice']}";
$text = trim($text);
if($text == '') return true;
$hash = md5($text);
$fname = $this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR;
$fname .= 'swift_' . $hash;
// create wave file
if(!file_exists("$fname.wav"))
{
// write text file
if(!file_exists("$fname.txt"))
{
$fp = fopen("$fname.txt", 'w');
fputs($fp, $text);
fclose($fp);
}
shell_exec("{$this->config['cepstral']['swift']} -p audio/channels=1,audio/sampling-rate=$frequency $voice -o $fname.wav -f $fname.txt");
}
// stream it
$ret = $this->stream_file($fname, $escape_digits);
// clean up old files
$delete = time() - 2592000; // 1 month
foreach(glob($this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'swift_*') as $file)
if(filemtime($file) < $delete)
unlink($file);
return $ret;
}
/**
* Text Input.
*
* Based on ideas found at http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
*
* Example:
* UC H LC i , SP h o w SP a r e SP y o u ?
* $string = '*8'.'44*'.'*5'.'444*'.'00*'.'0*'.'44*'.'666*'.'9*'.'0*'.'2*'.'777*'.'33*'.'0*'.'999*'.'666*'.'88*'.'0000*';
*
* @link http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
* @example examples/input.php Get text input from the user and say it back
*
* @return string
*/
function text_input($mode='NUMERIC')
{
$alpha = array( 'k0'=>' ', 'k00'=>',', 'k000'=>'.', 'k0000'=>'?', 'k00000'=>'0',
'k1'=>'!', 'k11'=>':', 'k111'=>';', 'k1111'=>'#', 'k11111'=>'1',
'k2'=>'A', 'k22'=>'B', 'k222'=>'C', 'k2222'=>'2',
'k3'=>'D', 'k33'=>'E', 'k333'=>'F', 'k3333'=>'3',
'k4'=>'G', 'k44'=>'H', 'k444'=>'I', 'k4444'=>'4',
'k5'=>'J', 'k55'=>'K', 'k555'=>'L', 'k5555'=>'5',
'k6'=>'M', 'k66'=>'N', 'k666'=>'O', 'k6666'=>'6',
'k7'=>'P', 'k77'=>'Q', 'k777'=>'R', 'k7777'=>'S', 'k77777'=>'7',
'k8'=>'T', 'k88'=>'U', 'k888'=>'V', 'k8888'=>'8',
'k9'=>'W', 'k99'=>'X', 'k999'=>'Y', 'k9999'=>'Z', 'k99999'=>'9');
$symbol = array('k0'=>'=',
'k1'=>'<', 'k11'=>'(', 'k111'=>'[', 'k1111'=>'{', 'k11111'=>'1',
'k2'=>'@', 'k22'=>'$', 'k222'=>'&', 'k2222'=>'%', 'k22222'=>'2',
'k3'=>'>', 'k33'=>')', 'k333'=>']', 'k3333'=>'}', 'k33333'=>'3',
'k4'=>'+', 'k44'=>'-', 'k444'=>'*', 'k4444'=>'/', 'k44444'=>'4',
'k5'=>"'", 'k55'=>'`', 'k555'=>'5',
'k6'=>'"', 'k66'=>'6',
'k7'=>'^', 'k77'=>'7',
'k8'=>"\\",'k88'=>'|', 'k888'=>'8',
'k9'=>'_', 'k99'=>'~', 'k999'=>'9');
$text = '';
do
{
$command = false;
$result = $this->get_data('beep');
foreach(explode('*', $result['result']) as $code)
{
if($command)
{
switch($code{0})
{
case '2': $text = substr($text, 0, strlen($text) - 1); break; // backspace
case '5': $mode = 'LOWERCASE'; break;
case '6': $mode = 'NUMERIC'; break;
case '7': $mode = 'SYMBOL'; break;
case '8': $mode = 'UPPERCASE'; break;
case '9': $text = explode(' ', $text); unset($text[count($text)-1]); $text = join(' ', $text); break; // backspace a word
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -