Difference between revisions of "Cepstral"

From ViciWiki
Jump to: navigation, search
(/var/lib/asterisk/agi-bin/Cepstral.agi)
(Vicidial Server Perl AGI example /var/lib/asterisk/agi-bin/cepstral_request.agi)
 
(29 intermediate revisions by the same user not shown)
Line 29: Line 29:
 
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
 
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
 
</pre>
 
</pre>
  +
*IMPORTANT
  +
*You must empty this table regularly. Dump the contents into an archive table with the same name nightly for instance. BEFORE this table reaches 100k entries ... it will die!
  +
*IMPORTANT
  +
 
==== Ensure both Vicidial and Cepstral server can access table ====
 
==== Ensure both Vicidial and Cepstral server can access table ====
 
On Both Servers:
 
On Both Servers:
Line 40: Line 44:
 
Add this line with proper credentials modified to match Vicidial server phone
 
Add this line with proper credentials modified to match Vicidial server phone
 
register => ccXXX:[email protected]
 
register => ccXXX:[email protected]
*NOTE: Oddly, this line did not work on PIAF when place in other locations. But it worked here so this is where we left it.
+
*NOTE: Oddly, this line did not work on PIAF when place in other locations. But it worked here at line 543 so this is where we left it.
  +
==== Set up SIP Account in Cepstral ====
  +
nano /etc/asterisk/sip_custom.conf
  +
*Note: mostly this is for the "context=cepstral" line to point calls away from the PIAF dialplan and into our cepstral dialplan
  +
*Be sure "host" ip matches or it will not capture those inbound calls and route them.
  +
*Multiple host lines are possible to capture multiple inbound servers, or this can be handled in different accounts
  +
[vicidial_D1]
  +
type=friend
  +
host=XXXXXXXXXXXX
  +
canreinvite=no
  +
;context=default
  +
context=cepstral
   
 
==== Pass call from Vicidial to Cepstral ====
 
==== Pass call from Vicidial to Cepstral ====
  +
===== Quick Test version =====
  +
===== Vicidial Extensions.conf =====
  +
nano +1000 /etc/asterisk/extensions.conf
  +
Replace "XXXX" in "SIP/XXXX" with the actual context for the Cepstral Server in sip.conf
  +
<pre>
  +
[cepstral-testing]
  +
;Test a simple passthrough to cepstral at it's presently registered sip account
  +
exten => _X.,1,NoOp(cepsral-testing|${EXTEN})
  +
exten => _X.,n,agi(cepstral_request.agi)
  +
exten => _X.,n,DIAL(SIP/7002/${EXTEN}||g)
  +
exten => _X.,n,Hangup
  +
  +
;Every context must have this in Vicidial, so in it goes:
  +
exten => h,1,DeadAGI(agi://127.0.0.1:4577/call_log--HVcauses--PRI-----NODEBUG-----${HANGUPCAUSE}-----${DIALSTATUS}-----${DIALEDTIME}-----${ANSWEREDTIME})
  +
</pre>
  +
  +
===== /etc/asterisk/extensions.conf on Cepstral =====
  +
nano +1000 /etc/asterisk/extensions.conf
  +
<pre>
  +
[cepstral]
  +
exten =>_XXX.,1,NoOp(cepstral|${EXTEN}|1)
  +
exten =>_XXX.,n,Set(foo=${CURL(http://ip.whowebwhere.com/TTSTest.php?cepstral=output)})
  +
exten =>_XXX.,n,swift(${foo})
  +
exten =>_XXX.,n,agi(Cepstral.agi)
  +
exten =>_XXX.,n,NoOp(${SWIFT_DTMF})
  +
exten =>_XXX.,n,agi(Process_DTMF_Cepstral.agi,${SWIFT_DTMF})
  +
exten =>_XXX.,n,Hangup()
  +
</pre>
  +
  +
===== quick connect test =====
  +
Then test with this command from the asterisk command line:
  +
dial 5555555@cepstral-testing
  +
*Will generate various failures (missing agi scripts below!) but should execute swift to play the recorded message in the command line visibly.
  +
===== if it worked, try a phone call =====
  +
Register a phone to the Vicidial server (admin->phones). Change the exten context and phone context to "cepstral-testing". This will allow the phone to dial through the cepstral dialplan and into the TTS machine. The system is presently set to catch any number and still play the same audio (Until we get the agi scripts online, at which point the numbers will need to match a table entry to grab the text from that entry).
  +
 
===== Create Random Number to identify this call =====
 
===== Create Random Number to identify this call =====
 
This version leaves numbers below 3001 available for other types of calls within this same structure (for testing or special TTS requests)
 
This version leaves numbers below 3001 available for other types of calls within this same structure (for testing or special TTS requests)
Line 55: Line 95:
 
}
 
}
 
</pre>
 
</pre>
===== Gather Data and DTMF Rules on Vicidial Server =====
+
==== Vicidial AGI ====
===== Store Data from Vicidial server in table using Number generated =====
+
===== Vicidial Server Perl AGI example /var/lib/asterisk/agi-bin/cepstral_request.agi =====
===== Dial Number from Vicidial to Cepstral =====
+
touch /var/lib/asterisk/agi-bin/cepstral_request.agi
Perl AGI example
+
chmod +x /var/lib/asterisk/agi-bin/cepstral_request.agi
* Depends on "utilities" perl module having the above NUID function and "database" perl module having a "db_no_return" function and a "db_with_return" capable of connecting to the DB/table in question
+
nano /var/lib/asterisk/agi-bin/cepstral_request.agi
* Note that this particular script is designed to get a 10 digit phone number and has rules in it to demonstrate this.
+
Remember: '''Change $cepstral_account='SIP/7002';''' to proper account below
 
<pre>
 
<pre>
  +
#!/usr/bin/perl
  +
#
  +
  +
$script = 'cepstral_request.agi';
  +
  +
$A = 1; # set to 1 for AMD output messages mode
  +
$AMD_LOG = 1; # set to 1 for logfile
  +
  +
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  +
$year = ($year + 1900);
  +
$mon++;
  +
if ($mon < 10) {$mon = "0$mon";}
  +
if ($mday < 10) {$mday = "0$mday";}
  +
if ($hour < 10) {$hour = "0$hour";}
  +
if ($min < 10) {$min = "0$min";}
  +
if ($sec < 10) {$sec = "0$sec";}
  +
  +
$now_date_epoch = time();
  +
$now_date = "$year-$mon-$mday $hour:$min:$sec";
  +
  +
# default path to astguiclient configuration file:
  +
$PATHconf = '/etc/astguiclient.conf';
  +
  +
open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n";
  +
@conf = <conf>;
  +
close(conf);
  +
$i=0;
  +
foreach(@conf)
  +
{
  +
$line = $conf[$i];
  +
$line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
  +
if ( ($line =~ /^PATHhome/) && ($CLIhome < 1) )
  +
{$PATHhome = $line; $PATHhome =~ s/.*=//gi;}
  +
if ( ($line =~ /^PATHlogs/) && ($CLIlogs < 1) )
  +
{$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;}
  +
if ( ($line =~ /^PATHagi/) && ($CLIagi < 1) )
  +
{$PATHagi = $line; $PATHagi =~ s/.*=//gi;}
  +
if ( ($line =~ /^PATHweb/) && ($CLIweb < 1) )
  +
{$PATHweb = $line; $PATHweb =~ s/.*=//gi;}
  +
if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) )
  +
{$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;}
  +
if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) )
  +
{$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) )
  +
{$VARserver_ip = $line; $VARserver_ip =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARDB_server/) && ($CLIDB_server < 1) )
  +
{$VARDB_server = $line; $VARDB_server =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARDB_database/) && ($CLIDB_database < 1) )
  +
{$VARDB_database = $line; $VARDB_database =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARDB_user/) && ($CLIDB_user < 1) )
  +
{$VARDB_user = $line; $VARDB_user =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARDB_pass/) && ($CLIDB_pass < 1) )
  +
{$VARDB_pass = $line; $VARDB_pass =~ s/.*=//gi;}
  +
if ( ($line =~ /^VARDB_port/) && ($CLIDB_port < 1) )
  +
{$VARDB_port = $line; $VARDB_port =~ s/.*=//gi;}
  +
$i++;
  +
}
  +
  +
if (!$VARDB_port) {$VARDB_port='3306';}
  +
if (!$AGILOGfile) {$AGILOGfile = "$PATHlogs/agiout.$year-$mon-$mday";}
  +
if (!$CEPLOGfile) {$CEPLOGfile = "$PATHlogs/Cepstral.$year-$mon-$mday";}
  +
  +
use DBI;
  +
use Asterisk::AGI;
  +
$AGI = new Asterisk::AGI;
  +
  +
  +
$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass")
  +
or die "Couldn't connect to database: " . DBI->errstr;
  +
  +
### Grab Server values from the database
  +
$stmtA = "SELECT agi_output FROM servers where server_ip = '$VARserver_ip';";
  +
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
  +
$sthArows=$sthA->rows;
  +
if ($sthArows > 0)
  +
{
  +
$AGILOG = '0';
  +
@aryA = $sthA->fetchrow_array;
  +
$DBagi_output = $aryA[0];
  +
if ($DBagi_output =~ /STDERR/) {$AGILOG = '1';}
  +
if ($DBagi_output =~ /FILE/) {$AGILOG = '2';}
  +
if ($DBagi_output =~ /BOTH/) {$AGILOG = '3';}
  +
}
  +
$sthA->finish();
  +
  +
### begin parsing run-time options ###
  +
if (length($ARGV[0])>1)
  +
{
  +
if ($AGILOG)
  +
{$agi_string = "Perl Environment Dump:"; &agi_output;}
  +
$i=0;
  +
while ($#ARGV >= $i)
  +
{
  +
$args = "$args $ARGV[$i]";
  +
if ($AGILOG) {$agi_string = "$i|$ARGV[$i]"; &agi_output;}
  +
$i++;
  +
}
  +
  +
### list of command-line array arguments:
  +
@ARGV_vars = split(/-----/, $ARGV[0]);
  +
$CLI_exten = $ARGV_vars[0];
  +
$force_playback = $ARGV_vars[1];
  +
}
  +
  +
  +
$|=1;
  +
while(<STDIN>)
  +
{
  +
chomp;
  +
last unless length($_);
  +
if ($AGILOG)
  +
{
  +
if (/^agi_(\w+)\:\s+(.*)$/)
  +
{
  +
$AGI{$1} = $2;
  +
}
  +
}
  +
  +
if (/^agi_uniqueid\:\s+(.*)$/) {$unique_id = $1; $uniqueid = $unique_id;}
  +
if (/^agi_priority\:\s+(.*)$/) {$priority = $1;}
  +
if (/^agi_channel\:\s+(.*)$/) {$channel = $1;}
  +
if (/^agi_extension\:\s+(.*)$/) {$extension = $1;}
  +
if (/^agi_type\:\s+(.*)$/) {$type = $1;}
  +
if (/^agi_callerid\:\s+(.*)$/) {$callerid = $1; $calleridnum = $callerid;}
  +
if (/^agi_calleridname\:\s+(.*)$/) {$calleridname = $1;}
  +
}
  +
  +
# extension variables if set: 8320*TESTCAMP*1*9998888112*194239
  +
if ($extension =~ /\*/)
  +
{
  +
@EXT_vars = split(/\*/, $extension);
  +
$referring_extension = $EXT_vars[0];
  +
$CLIcampaign_id = $EXT_vars[1];
  +
$CLIphone_code = $EXT_vars[2];
  +
$CLIphone_number = $EXT_vars[3];
  +
$CLIlead_id = $EXT_vars[4];
  +
}
  +
  +
if ( (length($callerid)>20) && ($callerid =~ /\"\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S/) )
  +
{
  +
$callerid =~ s/^\"//gi;
  +
$callerid =~ s/\".*$//gi;
  +
# ### set the callerid to the ACQS value(calleridname)
  +
# print "SET CALLERID $callerid\n";
  +
# checkresult($result);
  +
# print STDERR "callerID changed: $callerid\n";
  +
}
  +
if ( (
  +
(length($calleridname)>5) && ( (!$callerid) or ($callerid =~ /unknown|private|00000000/i) or ($callerid =~ /5551212/) )
  +
) or ( (length($calleridname)>17) && ($calleridname =~ /\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) ) )
  +
{
  +
$callerid = $calleridname;
  +
# ### set the callerid to the ACQS value(calleridname)
  +
# print "SET CALLERID $callerid\n";
  +
# checkresult($result);
  +
# print STDERR "callerID changed: $callerid\n";
  +
}
  +
  +
  +
if ($AGILOG) {$agi_string = "AGI Environment Dump:"; &agi_output;}
  +
  +
foreach $i (sort keys %AGI)
  +
{
  +
if ($AGILOG) {$agi_string = " -- $i = $AGI{$i}"; &agi_output;}
  +
}
  +
  +
if ($AGILOG) {$agi_string = "AGI Variables: |$unique_id|$channel|$extension|$type|$callerid|"; &agi_output;}
  +
  +
  +
$VDADcampaign='';
  +
$VDADphone='';
  +
$VDADphone_code='';
  +
  +
$callerid =~ s/\"//gi;
  +
$callerid =~ s/ .*//gi;
  +
$CIDlead_id = $callerid;
  +
$CIDlead_id = substr($CIDlead_id, 10, 10);
  +
$CIDlead_id = ($CIDlead_id + 0);
  +
if ( ($CLIlead_id > 0) && ($CIDlead_id < 1) ) {$CIDlead_id = $CLIlead_id;}
  +
$VD_lead_id = $CIDlead_id;
  +
  +
if ($AGILOG) {$agi_string = "+++++ VD cepstral_request START : |$CIDlead_id|$now_date|$AST_ver|$priority|$calleridname|"; &agi_output;}
  +
  +
###########################################
  +
  +
$cepstral_account='SIP/7002';
  +
  +
$cepstral_request_text='I am some Text';
  +
  +
$phone_number=customer_get_multi_cepstral( $AGI, $cepstral_request_text, '0123456789', '10', '5000' );
  +
  +
  +
  +
  +
  +
  +
  +
  +
###########################################
  +
exit;
  +
  +
##########################################
 
sub customer_get_multi_cepstral
 
sub customer_get_multi_cepstral
 
{
 
{
Line 71: Line 314:
 
$entry_chances++;
 
$entry_chances++;
 
# Generate numeric UID
 
# Generate numeric UID
$NUID=utilities::NUID();
+
$NUID=NUID();
 
# Create record in table with GUID/text/dtmf rules/dtmf passback/date for harvesting
 
# Create record in table with GUID/text/dtmf rules/dtmf passback/date for harvesting
database::db_no_return( $dbhA, $uniqueid, "insert into cepstral_passthru ( NUID,dtmfrules,text ) values ( '$NUID','|$wait_time|$digits_length','$TTS_text' )");
+
db_no_return( $dbhA, $uniqueid, "insert into cepstral_passthru ( NUID,dtmfrules,text ) values ( '$NUID','|$wait_time|$digits_length','$TTS_text' )");
 
# Dial GUID through cepstral
 
# Dial GUID through cepstral
$AGI->exec('Dial', "SIP/cepstral/$NUID||g");
+
$AGI->exec('Dial', "$cepstral_account/$NUID||g");
 
# Capture DTMF response from db record.
 
# Capture DTMF response from db record.
$choice = database::db_with_return( $dbhA, $uniqueid, "select dtmfpassback from cepstral_passthru where NUID ='$NUID'");
+
$choice = db_with_return( $dbhA, $uniqueid, "select dtmfpassback from cepstral_passthru where NUID ='$NUID'");
 
#If "Zero", kick it out now cuz phone numbers do not start with Zero so this is an operator request
 
#If "Zero", kick it out now cuz phone numbers do not start with Zero so this is an operator request
 
print STDERR " response: |Length: ". length($choice) ." |Value: $choice|\n";
 
print STDERR " response: |Length: ". length($choice) ." |Value: $choice|\n";
Line 105: Line 348:
   
 
}
 
}
</pre>
 
   
==== Cepstral Services the Call ====
 
  +
sub NUID {
===== /etc/asterisk/extensions.conf on Cepstral =====
 
  +
my $range = 1000000000000000;
<pre>
 
  +
my $random_number = int(rand($range));
[cepstral]
 
  +
$random_number=$random_number+3001;
;Random Numbers will all be above 3001. 3000 and below is safe for other utilities and tests.
 
  +
return $random_number;
exten =>_XXX.,1,NoOp()
 
  +
}
;same =>n,swift(Here we go.)
 
  +
same =>n,Set(TESTAT=${CUT(SIP_HEADER(From),@,2)})
 
  +
sub db_no_return {
same =>n,NoOp(${TESTAT:0:13})
 
  +
( $dbhA, $uniqueid, $query ) = @_;
same =>n,agi(Cepstral.agi)
 
  +
print STDERR " db_no_return|$query\n";
same =>n,NoOp(${SWIFT_DTMF})
 
  +
$sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
same =>n,agi(Process_DTMF_Cepstral.agi,${SWIFT_DTMF})
 
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
same =>n,Hangup()
 
  +
## Log if appropriate
  +
}
  +
  +
sub db_with_return {
  +
( $dbhA, $uniqueid, $query ) = @_;
  +
print STDERR " db_with_return|$query\n";
  +
$sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
  +
$sthArows=$sthA->rows;
  +
if ($sthArows > 0)
  +
{
  +
@aryA = $sthA->fetchrow_array;
  +
$return_value = $aryA[0];
  +
$sthA->finish();
  +
}
  +
else
  +
{$return_value = '';}
  +
return $return_value;
  +
}
  +
  +
##########################################################
  +
sub checkresult
  +
{
  +
my ($res) = @_;
  +
my $retval;
  +
$tests++;
  +
chomp $res;
  +
if ($res =~ /^200/)
  +
{
  +
$res =~ /result=(-?\d+)/;
  +
if (!length($1))
  +
{
  +
# print STDERR "FAIL ($res)\n";
  +
$fail++;
  +
}
  +
else
  +
{
  +
# print STDERR "PASS ($1)\n";
  +
$pass++;
  +
}
  +
}
  +
else
  +
{
  +
# print STDERR "FAIL (unexpected result '$res')\n";
  +
$fail++;
  +
}
  +
}
  +
  +
  +
sub agi_output
  +
{
  +
if ($AGILOG >=2)
  +
{
  +
### open the log file for writing ###
  +
open(Lout, ">>$AGILOGfile")
  +
|| die "Can't open $AGILOGfile: $!\n";
  +
print Lout "$now_date|$script|$agi_string\n";
  +
close(Lout);
  +
}
  +
### send to STDERR writing ###
  +
if ( ($AGILOG == '1') || ($AGILOG == '3') )
  +
{print STDERR "$now_date|$script|$agi_string\n";}
  +
$agi_string='';
  +
}
  +
 
</pre>
 
</pre>
  +
  +
==== Cepstral Server AGI ====
 
===== /var/lib/asterisk/agi-bin/Cepstral.agi =====
 
===== /var/lib/asterisk/agi-bin/Cepstral.agi =====
 
# Use number dialed (DID) as key to grab TTS and DTMF rules
 
# Use number dialed (DID) as key to grab TTS and DTMF rules
 
# Use Cepstral to play sound
 
# Use Cepstral to play sound
  +
  +
touch /var/lib/asterisk/agi-bin/Cepstral.agi
  +
chmod +x /var/lib/asterisk/agi-bin/Cepstral.agi
  +
nano /var/lib/asterisk/agi-bin/Cepstral.agi
  +
Remember: '''Change IP Address of server in DBI->connect string below'''
 
<pre>
 
<pre>
 
#!/usr/bin/perl
 
#!/usr/bin/perl
use lib ('/var/lib/asterisk/agi-bin/modules');
 
use Cepstral_Include;
 
use Cepstral_Database;
 
 
use DBI;
 
use DBI;
 
use Asterisk::AGI;
 
use Asterisk::AGI;
 
use Switch;
 
use Switch;
   
my $now_date_time = utilities::now_date_time;
+
my $now_date_time = now_date_time;
my $now_date = utilities::now_date;
+
my $now_date = now_date;
   
 
$AGI = new Asterisk::AGI;
 
$AGI = new Asterisk::AGI;
   
$dbhA = DBI->connect("DBI:mysql:asterisk:xxx.xxx.xxx.xxx:3306", "cron", "1234")
+
$dbhA = DBI->connect("DBI:mysql:asterisk:192.168.0.44:3306", "cron", "1234")
 
or die "Couldn't connect to database: " . DBI->errstr;
 
or die "Couldn't connect to database: " . DBI->errstr;
   
Line 180: Line 490:
   
 
############ PREP - Get Text and DTMF Rules
 
############ PREP - Get Text and DTMF Rules
$tts_data=Cepstral_Database::get_tts_data($dbhA,$extension);
+
$tts_data=get_tts_data($dbhA,$extension);
print STDERR "before: exec swift \"$tts_data\"\n";
+
print STDERR "before text changes: exec swift \"$tts_data\"\n";
 
$tts_data =~ s/,/<break strength='weak' \/>/g;
 
$tts_data =~ s/,/<break strength='weak' \/>/g;
 
$tts_data =~ s/\. /<break strength='strong' \/> /g;
 
$tts_data =~ s/\. /<break strength='strong' \/> /g;
Line 189: Line 499:
 
$dtmf_return=$AGI->get_variable($SWIFT_DTMF);
 
$dtmf_return=$AGI->get_variable($SWIFT_DTMF);
 
print STDERR "dtmf return: $dtmf_return\n";
 
print STDERR "dtmf return: $dtmf_return\n";
  +
put_tts_dtmf($dbhA, $extension,$dtmf_return);
   
</pre>
 
  +
1;
  +
exit;
   
# Collect keys pressed (if any) and place in dtmfpassback
 
  +
###############################################
<pre>
 
  +
# Returns 'Nov 20 00:46:59'
#!/usr/bin/perl
 
  +
sub now_date_time {
use lib ('/var/lib/asterisk/agi-bin/modules');
 
  +
(my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime(time);
use Cepstral_Include;
 
  +
my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
use Cepstral_Database;
 
  +
$mon=$abbr[$mon];
use DBI;
 
  +
$sec = sprintf("%02d", $sec);
use Asterisk::AGI;
 
  +
$min = sprintf("%02d", $min);
use Switch;
 
  +
$hour = sprintf("%02d", $hour);
  +
$mday = sprintf("%02d", $mday);
  +
my $now_date_time = "$mon $mday $hour:$min:$sec";
  +
return $now_date_time;
  +
}
  +
# Returns '2011-11-20'
  +
sub now_date {
  +
(my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime(time);
  +
$year=$year+1900;
  +
$mon++;
  +
$sec = sprintf("%02d", $sec);
  +
$min = sprintf("%02d", $min);
  +
$hour = sprintf("%02d", $hour);
  +
$mday = sprintf("%02d", $mday);
  +
my $now_date = "$year-$mon-$mday";
  +
return $now_date;
  +
}
   
my $now_date_time = utilities::now_date_time;
 
  +
sub db_no_return {
my $now_date = utilities::now_date;
 
  +
( $dbhA, $uniqueid, $query ) = @_;
  +
print STDERR " db_no_return|$query\n";
  +
$sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
  +
## Log if appropriate
  +
}
   
$AGI = new Asterisk::AGI;
 
  +
sub db_with_return {
  +
( $dbhA, $uniqueid, $query ) = @_;
  +
print STDERR " db_with_return|$query\n";
  +
$sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
  +
$sthArows=$sthA->rows;
  +
if ($sthArows > 0)
  +
{
  +
@aryA = $sthA->fetchrow_array;
  +
$return_value = $aryA[0];
  +
$sthA->finish();
  +
}
  +
else
  +
{$return_value = '';}
  +
return $return_value;
  +
}
   
$dbhA = DBI->connect("DBI:mysql:asterisk:xxx.xxx.xxx.xxx:3306", "cron", "1234")
 
  +
sub get_tts_data {
or die "Couldn't connect to database: " . DBI->errstr;
 
  +
( $dbhA, $extension ) = @_;
  +
print STDERR "$extension\n";
  +
my $stmtA = "select dtmfrules,text from cepstral_passthru where NUID='$extension' limit 1;";
  +
print STDERR "$stmtA\n";
  +
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
  +
$sthArows=$sthA->rows;
  +
if ($sthArows > 0)
  +
{
  +
@aryA = $sthA->fetchrow_array;
  +
$dtmfrules = "$aryA[0]";
  +
$text = "$aryA[1]";
  +
$return="$text$dtmfrules";
  +
$sthA->finish();
  +
}
  +
else
  +
{$return="No Text Returned. $stmtA";}
  +
print STDERR "$return\n";
  +
return $return;
  +
}
   
$|=1;
 
  +
sub put_tts_dtmf {
while(<STDIN>)
 
  +
( $dbhA, $extension,$dtmf_response ) = @_;
{
 
  +
print STDERR "$extension\n";
chomp;
 
  +
my $stmtA = "update cepstral_passthru set dtmfpassback='$dtmf_response' where NUID='$extension' limit 1;";
last unless length($_);
 
  +
print STDERR "$stmtA\n";
if ($V)
 
  +
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
{
 
  +
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
if (/^agi_(\w+)\:\s+(.*)$/)
 
  +
$sthArows=$sthA->rows;
{
 
  +
if ($sthArows > 0)
$AGI{$1} = $2;
+
{
}
+
@aryA = $sthA->fetchrow_array;
}
+
$dtmfrules = "$aryA[0]";
  +
$text = "$aryA[1]";
  +
$return="$text$dtmfrules";
  +
$sthA->finish();
  +
}
  +
else
  +
{$return="No Text Returned. $stmtA";}
  +
print STDERR "$return\n";
  +
return $return;
  +
}
   
if (/^agi_context\:\s+(.*)$/) {$context = $1;}
 
  +
</pre>
if (/^agi_priority\:\s+(.*)$/) {$priority = $1;}
 
if (/^agi_uniqueid\:\s+(.*)$/) {$unique_id = $1; $uniqueid = $1;}
 
if (/^agi_extension\:\s+(.*)$/) {$extension = $1;}
 
if (/^agi_channel\:\s+(.*)$/) {$channel = $1;}
 
if (/^agi_callerid\:\s+(.*)$/) {$callerid = $1;}
 
if (/^agi_calleridname\:\s+(.*)$/) {$calleridname = $1;}
 
if (/^agi_dnid\:\s+(.*)$/) {$dnid = $1;}
 
   
}
 
if ( ($callerid =~ /\".*\"/) && ( (!$calleridname) or ($calleridname =~ /unknown/) ) )
 
{
 
$calleridname = $callerid;
 
$calleridname =~ s/\<\d\d\d\d\d\d\d\d\d\d\>//gi;
 
$calleridname =~ s/\"|\" //gi;
 
}
 
$callerid =~ s/\D//gi;
 
$calleridname =~ s/unknown//gi;
 
if ( (!$callerid) or ($callerid =~ /unknown/) )
 
{$callerid = $calleridname;}
 
$phone_number=$callerid;
 
 
print STDERR " Extension: $extension\n";
 
 
############ PREP - Get Text and DTMF Rules
 
$dtmf_return = $AGI->get_variable("SWIFT_DTMF");
 
print STDERR "dtmf return: $dtmf_return\n";
 
Cepstral_Database::db_no_return( $dbhA, $uniqueid, "update cepstral_passthru set dtmfpassback='$dtmf_return' where NUID='$extension' limit 1");
 
 
</pre>
 
 
# Terminate call
 
# Terminate call
   
Line 259: Line 598:
 
= Details for missing steps coming momentarily =
 
= Details for missing steps coming momentarily =
 
* Cleaning out client data!
 
* Cleaning out client data!
  +
= TEST In Vicidial Server =
  +
Set up: Observe ASTERISK command line interface of both Vicidial and Cepstral servers. In the Vicidial server, execute the following from the asterisk command line:
  +
dial 5555555@cepstral-testing

Latest revision as of 22:17, 29 August 2012

New version of Cepstral is not Compatible with Vicidial

  • Note: Vicidial supports Asterisk 1.4 and 1.2. Cepstral now supports only asterisk 1.6 and above.

Solution: Separate Cepstral server to play sounds to Vicidial.

Method

  1. Vicidial stores text and number in a table.
  2. Vicidial calls Cepstral with the number.
  3. Cepstral reaches into the table for that number that was called (DID) and retrieves the Text.
  4. Cepstral plays the Text-To-Speech. Interrupt is captured to another field of the same table entry if it occurs.
  5. Cepstral terminates call, returning control to Vicidial

Instructions

  1. Require asterisk 1.6 or above fresh install: Install PIAF Purple on fresh server
  2. Install Cepstral on PIAF server

Create table to hold TTS Data

--
-- Table structure for table `cepstral_passthru`
--

CREATE TABLE IF NOT EXISTS `cepstral_passthru` (
  `NUID` varchar(36) NOT NULL,
  `dtmfrules` varchar(20) NOT NULL,
  `dtmfpassback` varchar(20) NOT NULL,
  `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `text` varchar(600) NOT NULL,
  PRIMARY KEY  (`NUID`)
) ENGINE=MEMORY DEFAULT CHARSET=latin1;
  • IMPORTANT
  • You must empty this table regularly. Dump the contents into an archive table with the same name nightly for instance. BEFORE this table reaches 100k entries ... it will die!
  • IMPORTANT

Ensure both Vicidial and Cepstral server can access table

On Both Servers:

mysql -h xxx.xxx.xxx.xxx -u cron -p1234 asterisk
  • Where xxx.xxx.xxx.xxx is the ip of the DB server (localhost or omit "-h" entry entirely if this IS the DB server)
  • And cron is the db username and 1234 is the db password (default user/pass in Vicidial, any other user can be created for this purpose by an experienced MySQL admin)

Register Cepstral SIP trunk to Vicidial SIP account

On PIAF/Cepstral Server:

nano +543 /etc/asterisk/sip.conf

Add this line with proper credentials modified to match Vicidial server phone

register => ccXXX:[email protected]
  • NOTE: Oddly, this line did not work on PIAF when place in other locations. But it worked here at line 543 so this is where we left it.

Set up SIP Account in Cepstral

nano /etc/asterisk/sip_custom.conf
  • Note: mostly this is for the "context=cepstral" line to point calls away from the PIAF dialplan and into our cepstral dialplan
  • Be sure "host" ip matches or it will not capture those inbound calls and route them.
  • Multiple host lines are possible to capture multiple inbound servers, or this can be handled in different accounts
[vicidial_D1]
type=friend
host=XXXXXXXXXXXX
canreinvite=no
;context=default
context=cepstral

Pass call from Vicidial to Cepstral

Quick Test version
Vicidial Extensions.conf
nano +1000 /etc/asterisk/extensions.conf

Replace "XXXX" in "SIP/XXXX" with the actual context for the Cepstral Server in sip.conf

[cepstral-testing]
;Test a simple passthrough to cepstral at it's presently registered sip account
exten => _X.,1,NoOp(cepsral-testing|${EXTEN})
exten => _X.,n,agi(cepstral_request.agi)
exten => _X.,n,DIAL(SIP/7002/${EXTEN}||g)
exten => _X.,n,Hangup

;Every context must have this in Vicidial, so in it goes:
exten => h,1,DeadAGI(agi://127.0.0.1:4577/call_log--HVcauses--PRI-----NODEBUG-----${HANGUPCAUSE}-----${DIALSTATUS}-----${DIALEDTIME}-----${ANSWEREDTIME})
/etc/asterisk/extensions.conf on Cepstral
nano +1000 /etc/asterisk/extensions.conf
[cepstral]
exten =>_XXX.,1,NoOp(cepstral|${EXTEN}|1)
exten =>_XXX.,n,Set(foo=${CURL(http://ip.whowebwhere.com/TTSTest.php?cepstral=output)})
exten =>_XXX.,n,swift(${foo})
exten =>_XXX.,n,agi(Cepstral.agi)
exten =>_XXX.,n,NoOp(${SWIFT_DTMF})
exten =>_XXX.,n,agi(Process_DTMF_Cepstral.agi,${SWIFT_DTMF})
exten =>_XXX.,n,Hangup()
quick connect test

Then test with this command from the asterisk command line:

dial 5555555@cepstral-testing
  • Will generate various failures (missing agi scripts below!) but should execute swift to play the recorded message in the command line visibly.
if it worked, try a phone call

Register a phone to the Vicidial server (admin->phones). Change the exten context and phone context to "cepstral-testing". This will allow the phone to dial through the cepstral dialplan and into the TTS machine. The system is presently set to catch any number and still play the same audio (Until we get the agi scripts online, at which point the numbers will need to match a table entry to grab the text from that entry).

Create Random Number to identify this call

This version leaves numbers below 3001 available for other types of calls within this same structure (for testing or special TTS requests)

Perl AGI example from "utilities" module

sub NUID {
    my $range = 1000000000000000;
    my $random_number = int(rand($range));
    $random_number=$random_number+3001;
    return $random_number;
}

Vicidial AGI

Vicidial Server Perl AGI example /var/lib/asterisk/agi-bin/cepstral_request.agi
touch /var/lib/asterisk/agi-bin/cepstral_request.agi
chmod +x /var/lib/asterisk/agi-bin/cepstral_request.agi
nano /var/lib/asterisk/agi-bin/cepstral_request.agi

Remember: Change $cepstral_account='SIP/7002'; to proper account below

#!/usr/bin/perl
#

$script = 'cepstral_request.agi';

$A = 1;		# set to 1 for AMD output messages mode
$AMD_LOG = 1;	# set to 1 for logfile

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year = ($year + 1900);
$mon++;
if ($mon < 10) {$mon = "0$mon";}
if ($mday < 10) {$mday = "0$mday";}
if ($hour < 10) {$hour = "0$hour";}
if ($min < 10) {$min = "0$min";}
if ($sec < 10) {$sec = "0$sec";}

$now_date_epoch = time();
$now_date = "$year-$mon-$mday $hour:$min:$sec";

# default path to astguiclient configuration file:
$PATHconf =		'/etc/astguiclient.conf';

open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n";
@conf = <conf>;
close(conf);
$i=0;
foreach(@conf)
	{
	$line = $conf[$i];
	$line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
	if ( ($line =~ /^PATHhome/) && ($CLIhome < 1) )
		{$PATHhome = $line;   $PATHhome =~ s/.*=//gi;}
	if ( ($line =~ /^PATHlogs/) && ($CLIlogs < 1) )
		{$PATHlogs = $line;   $PATHlogs =~ s/.*=//gi;}
	if ( ($line =~ /^PATHagi/) && ($CLIagi < 1) )
		{$PATHagi = $line;   $PATHagi =~ s/.*=//gi;}
	if ( ($line =~ /^PATHweb/) && ($CLIweb < 1) )
		{$PATHweb = $line;   $PATHweb =~ s/.*=//gi;}
	if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) )
		{$PATHsounds = $line;   $PATHsounds =~ s/.*=//gi;}
	if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) )
		{$PATHmonitor = $line;   $PATHmonitor =~ s/.*=//gi;}
	if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) )
		{$VARserver_ip = $line;   $VARserver_ip =~ s/.*=//gi;}
	if ( ($line =~ /^VARDB_server/) && ($CLIDB_server < 1) )
		{$VARDB_server = $line;   $VARDB_server =~ s/.*=//gi;}
	if ( ($line =~ /^VARDB_database/) && ($CLIDB_database < 1) )
		{$VARDB_database = $line;   $VARDB_database =~ s/.*=//gi;}
	if ( ($line =~ /^VARDB_user/) && ($CLIDB_user < 1) )
		{$VARDB_user = $line;   $VARDB_user =~ s/.*=//gi;}
	if ( ($line =~ /^VARDB_pass/) && ($CLIDB_pass < 1) )
		{$VARDB_pass = $line;   $VARDB_pass =~ s/.*=//gi;}
	if ( ($line =~ /^VARDB_port/) && ($CLIDB_port < 1) )
		{$VARDB_port = $line;   $VARDB_port =~ s/.*=//gi;}
	$i++;
	}

if (!$VARDB_port)	{$VARDB_port='3306';}
if (!$AGILOGfile)	{$AGILOGfile = "$PATHlogs/agiout.$year-$mon-$mday";}
if (!$CEPLOGfile)	{$CEPLOGfile = "$PATHlogs/Cepstral.$year-$mon-$mday";}

use DBI;
use Asterisk::AGI;
$AGI = new Asterisk::AGI;

  
$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass")
    or die "Couldn't connect to database: " . DBI->errstr;

### Grab Server values from the database
$stmtA = "SELECT agi_output FROM servers where server_ip = '$VARserver_ip';";
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
$sthArows=$sthA->rows;
if ($sthArows > 0)
	{
	$AGILOG = '0';
	@aryA = $sthA->fetchrow_array;
	$DBagi_output =			$aryA[0];
	if ($DBagi_output =~ /STDERR/)	{$AGILOG = '1';}
	if ($DBagi_output =~ /FILE/)	{$AGILOG = '2';}
	if ($DBagi_output =~ /BOTH/)	{$AGILOG = '3';}
	}
$sthA->finish();

### begin parsing run-time options ###
if (length($ARGV[0])>1)
	{
	if ($AGILOG) 
		{$agi_string = "Perl Environment Dump:";   &agi_output;}
	$i=0;
	while ($#ARGV >= $i)
		{
		$args = "$args $ARGV[$i]";
		if ($AGILOG) {$agi_string = "$i|$ARGV[$i]";   &agi_output;}
		$i++;
		}
	
	### list of command-line array arguments:
	@ARGV_vars = split(/-----/, $ARGV[0]);
	$CLI_exten =		$ARGV_vars[0];
	$force_playback = 	$ARGV_vars[1];
	}


$|=1;
while(<STDIN>) 
	{
	chomp;
	last unless length($_);
	if ($AGILOG)
		{
		if (/^agi_(\w+)\:\s+(.*)$/)
			{
			$AGI{$1} = $2;
			}
		}

	if (/^agi_uniqueid\:\s+(.*)$/)		{$unique_id = $1; $uniqueid = $unique_id;}
	if (/^agi_priority\:\s+(.*)$/)		{$priority = $1;}
	if (/^agi_channel\:\s+(.*)$/)		{$channel = $1;}
	if (/^agi_extension\:\s+(.*)$/)		{$extension = $1;}
	if (/^agi_type\:\s+(.*)$/)		{$type = $1;}
	if (/^agi_callerid\:\s+(.*)$/)		{$callerid = $1;   $calleridnum = $callerid;}
	if (/^agi_calleridname\:\s+(.*)$/)	{$calleridname = $1;}
	}

# extension variables if set: 8320*TESTCAMP*1*9998888112*194239
if ($extension =~ /\*/)
	{
	@EXT_vars = split(/\*/, $extension);
	$referring_extension =	$EXT_vars[0];
	$CLIcampaign_id =		$EXT_vars[1];
	$CLIphone_code = 		$EXT_vars[2];
	$CLIphone_number =		$EXT_vars[3];
	$CLIlead_id =			$EXT_vars[4];
	}

if ( (length($callerid)>20) && ($callerid =~ /\"\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S\S/) )
	{
	$callerid =~ s/^\"//gi;
	$callerid =~ s/\".*$//gi;
#	### set the callerid to the ACQS value(calleridname)
#	print "SET CALLERID $callerid\n";
#	checkresult($result);
#	print STDERR "callerID changed: $callerid\n";
	}
if ( (
(length($calleridname)>5) && ( (!$callerid) or ($callerid =~ /unknown|private|00000000/i) or ($callerid =~ /5551212/) )
) or ( (length($calleridname)>17) && ($calleridname =~ /\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) ) )
	{
	$callerid = $calleridname;
#	### set the callerid to the ACQS value(calleridname)
#	print "SET CALLERID $callerid\n";
#	checkresult($result);
#	print STDERR "callerID changed: $callerid\n";
	}


if ($AGILOG) {$agi_string = "AGI Environment Dump:";   &agi_output;}

foreach $i (sort keys %AGI) 
	{
	if ($AGILOG) {$agi_string = " -- $i = $AGI{$i}";   &agi_output;}
	}

if ($AGILOG) {$agi_string = "AGI Variables: |$unique_id|$channel|$extension|$type|$callerid|";   &agi_output;}


$VDADcampaign='';
$VDADphone='';
$VDADphone_code='';

$callerid =~ s/\"//gi;
$callerid =~ s/ .*//gi;
$CIDlead_id = $callerid;
$CIDlead_id = substr($CIDlead_id, 10, 10);
$CIDlead_id = ($CIDlead_id + 0);
if ( ($CLIlead_id > 0) && ($CIDlead_id < 1) ) {$CIDlead_id = $CLIlead_id;}
$VD_lead_id = $CIDlead_id;

if ($AGILOG) {$agi_string = "+++++ VD cepstral_request START : |$CIDlead_id|$now_date|$AST_ver|$priority|$calleridname|";   &agi_output;}

###########################################

$cepstral_account='SIP/7002';

$cepstral_request_text='I am some Text';

$phone_number=customer_get_multi_cepstral( $AGI, $cepstral_request_text, '0123456789', '10', '5000' );








###########################################
exit;

##########################################
sub customer_get_multi_cepstral
    {
        ( $AGI, $TTS_text, $ivr_option_digits, $digits_length, $wait_time  ) = @_;
        my $entry_chances=0;
        my $choice='';
        while ( ( $entry_chances < 3 ) && ( length($choice) < $digits_length ) )
            {
                $entry_chances++;
                # Generate numeric UID
                $NUID=NUID();
                # Create record in table with GUID/text/dtmf rules/dtmf passback/date for harvesting
                db_no_return( $dbhA, $uniqueid, "insert into cepstral_passthru ( NUID,dtmfrules,text ) values ( '$NUID','|$wait_time|$digits_length','$TTS_text' )");
                # Dial GUID through cepstral
                $AGI->exec('Dial', "$cepstral_account/$NUID||g");
                # Capture DTMF response from db record.
                $choice = db_with_return( $dbhA, $uniqueid, "select dtmfpassback from cepstral_passthru where NUID ='$NUID'");
                #If "Zero", kick it out now cuz phone numbers do not start with Zero so this is an operator request
                print STDERR "     response: |Length: ". length($choice) ." |Value: $choice|\n";
                if ( (length($choice) == 1) && ($choice == 0) ) {
                    print STDERR "     Operator Request Received: |$choice|\n";
                    return $choice;
                }
                $choice =~ s/\D//gi;
                $phone_number = $choice;
                if ($choice) {
                    print STDERR "     |$choice|\n";
                }

             }
            if (length($phone_number)=='10') {
                print STDERR "     |$phone_number|\n";
                return $phone_number;
            }
            if (length($phone_number)>'0') {
                print STDERR "     Invalid Reply: |$phone_number|\n";
                return $phone_number;
            }
            if ((length($phone_number)=='0') && ($entry_chances == '3' )) {
                print STDERR "      No Reply |$choice|\n";
                return 'call_return_to_menu';
            }

    }

sub NUID {
    my $range = 1000000000000000;
    my $random_number = int(rand($range));
    $random_number=$random_number+3001;
    return $random_number;
}

sub db_no_return {
    ( $dbhA, $uniqueid, $query ) = @_;
    print STDERR "                         db_no_return|$query\n";
    $sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    ## Log if appropriate
}

sub db_with_return {
    ( $dbhA, $uniqueid, $query ) = @_;
    print STDERR "                       db_with_return|$query\n";
    $sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    $sthArows=$sthA->rows;
    if ($sthArows > 0)
            {
            @aryA = $sthA->fetchrow_array;
            $return_value = $aryA[0];
            $sthA->finish();
            }
    else
            {$return_value = '';}
    return $return_value;
}

##########################################################
sub checkresult 
	{
	my ($res) = @_;
	my $retval;
	$tests++;
	chomp $res;
	if ($res =~ /^200/) 
		{
		$res =~ /result=(-?\d+)/;
		if (!length($1)) 
			{
		#	print STDERR "FAIL ($res)\n";
			$fail++;
			} 
		else 
			{
		#	print STDERR "PASS ($1)\n";
			$pass++;
			}
		}
	else
		{
	#	print STDERR "FAIL (unexpected result '$res')\n";
		$fail++;
		}
	}


sub agi_output
	{
	if ($AGILOG >=2)
		{
		### open the log file for writing ###
		open(Lout, ">>$AGILOGfile")
				|| die "Can't open $AGILOGfile: $!\n";
		print Lout "$now_date|$script|$agi_string\n";
		close(Lout);
		}
		### send to STDERR writing ###
	if ( ($AGILOG == '1') || ($AGILOG == '3') )
		{print STDERR "$now_date|$script|$agi_string\n";}
	$agi_string='';
	}

Cepstral Server AGI

/var/lib/asterisk/agi-bin/Cepstral.agi
  1. Use number dialed (DID) as key to grab TTS and DTMF rules
  2. Use Cepstral to play sound
touch /var/lib/asterisk/agi-bin/Cepstral.agi
chmod +x /var/lib/asterisk/agi-bin/Cepstral.agi
nano /var/lib/asterisk/agi-bin/Cepstral.agi

Remember: Change IP Address of server in DBI->connect string below

#!/usr/bin/perl
use DBI;
use Asterisk::AGI;
use Switch;

my $now_date_time = now_date_time;
my $now_date = now_date;

$AGI = new Asterisk::AGI;

$dbhA = DBI->connect("DBI:mysql:asterisk:192.168.0.44:3306", "cron", "1234")
    or die "Couldn't connect to database: " . DBI->errstr;

$|=1;
while(<STDIN>)
        {
        chomp;
        last unless length($_);
        if ($V)
                {
                if (/^agi_(\w+)\:\s+(.*)$/)
                        {
                        $AGI{$1} = $2;
                        }
                }

        if (/^agi_context\:\s+(.*)$/)           {$context = $1;}
        if (/^agi_priority\:\s+(.*)$/)          {$priority = $1;}
        if (/^agi_uniqueid\:\s+(.*)$/)          {$unique_id = $1;   $uniqueid = $1;}
        if (/^agi_extension\:\s+(.*)$/)         {$extension = $1;}
        if (/^agi_channel\:\s+(.*)$/)           {$channel = $1;}
        if (/^agi_callerid\:\s+(.*)$/)          {$callerid = $1;}
        if (/^agi_calleridname\:\s+(.*)$/)      {$calleridname = $1;}
        if (/^agi_dnid\:\s+(.*)$/)      {$dnid = $1;}

        }
if ( ($callerid =~ /\".*\"/) && ( (!$calleridname) or ($calleridname =~ /unknown/) ) )
        {
        $calleridname = $callerid;
        $calleridname =~ s/\<\d\d\d\d\d\d\d\d\d\d\>//gi;
        $calleridname =~ s/\"|\" //gi;
        }
        $callerid =~ s/\D//gi;
        $calleridname =~ s/unknown//gi;
if ( (!$callerid) or ($callerid =~ /unknown/) )
        {$callerid = $calleridname;}
$phone_number=$callerid;

print STDERR "        Extension: $extension\n";


############ PREP - Get Text and DTMF Rules
$tts_data=get_tts_data($dbhA,$extension);
print STDERR "before text changes: exec swift \"$tts_data\"\n";
$tts_data =~ s/,/<break strength='weak' \/>/g;
$tts_data =~ s/\. /<break strength='strong' \/> /g;
print STDERR "after: exec swift \"$tts_data\"\n";
print "exec swift \"$tts_data\"\n";
#print "exec swift \"Howdy Pardner<break strength='x-weak' />yorr really looking like you could use<break strength='weak' /> a break\"\n";
$dtmf_return=$AGI->get_variable($SWIFT_DTMF);
print STDERR "dtmf return: $dtmf_return\n";
put_tts_dtmf($dbhA, $extension,$dtmf_return); 

1;
exit;

###############################################
# Returns 'Nov 20 00:46:59'
sub now_date_time {
   (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime(time);
    my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
    $mon=$abbr[$mon];
    $sec = sprintf("%02d", $sec);
    $min = sprintf("%02d", $min);
    $hour = sprintf("%02d", $hour);
    $mday = sprintf("%02d", $mday);
    my $now_date_time = "$mon $mday $hour:$min:$sec";
    return $now_date_time;
}
# Returns '2011-11-20'
sub now_date {
   (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime(time);
    $year=$year+1900;
    $mon++;
    $sec = sprintf("%02d", $sec);
    $min = sprintf("%02d", $min);
    $hour = sprintf("%02d", $hour);
    $mday = sprintf("%02d", $mday);
    my $now_date = "$year-$mon-$mday";
    return $now_date;
}

sub db_no_return {
    ( $dbhA, $uniqueid, $query ) = @_;
    print STDERR "                         db_no_return|$query\n";
    $sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    ## Log if appropriate
}

sub db_with_return {
    ( $dbhA, $uniqueid, $query ) = @_;
    print STDERR "                       db_with_return|$query\n";
    $sthA = $dbhA->prepare($query) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    $sthArows=$sthA->rows;
    if ($sthArows > 0)
            {
            @aryA = $sthA->fetchrow_array;
            $return_value = $aryA[0];
            $sthA->finish();
            }
    else
            {$return_value = '';}
    return $return_value;
}

sub get_tts_data {
    ( $dbhA, $extension ) = @_;
    print STDERR "$extension\n";
    my $stmtA = "select dtmfrules,text from cepstral_passthru where NUID='$extension' limit 1;";
    print STDERR "$stmtA\n";
    $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    $sthArows=$sthA->rows;
    if ($sthArows > 0)
            {
            @aryA = $sthA->fetchrow_array;
            $dtmfrules =        "$aryA[0]";
            $text =     "$aryA[1]";
            $return="$text$dtmfrules";
            $sthA->finish();
            }
    else
            {$return="No Text Returned. $stmtA";}
    print STDERR "$return\n";
    return $return;
}

sub put_tts_dtmf {
    ( $dbhA, $extension,$dtmf_response ) = @_;
    print STDERR "$extension\n";
    my $stmtA = "update cepstral_passthru set dtmfpassback='$dtmf_response'  where NUID='$extension' limit 1;";
    print STDERR "$stmtA\n";
    $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
    $sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
    $sthArows=$sthA->rows;
    if ($sthArows > 0)
            {
            @aryA = $sthA->fetchrow_array;
            $dtmfrules =        "$aryA[0]";
            $text =     "$aryA[1]";
            $return="$text$dtmfrules";
            $sthA->finish();
            }
    else
            {$return="No Text Returned. $stmtA";}
    print STDERR "$return\n";
    return $return;
}

  1. Terminate call

Vicidial Server Continues call

  1. Upon termination of Cepstral leg, capture dtmfpassback and route accordingly.

Details for missing steps coming momentarily

  • Cleaning out client data!

TEST In Vicidial Server

Set up: Observe ASTERISK command line interface of both Vicidial and Cepstral servers. In the Vicidial server, execute the following from the asterisk command line:

dial 5555555@cepstral-testing