Difference between revisions of "Cepstral"

From ViciWiki
Jump to: navigation, search
(Ensure both Vicidial and Cepstral server can access table)
(Cepstral Services the Call)
Line 108: Line 108:
   
 
==== Cepstral Services the Call ====
 
==== Cepstral Services the Call ====
  +
===== /etc/asterisk/extensions.conf on Cepstral =====
  +
<pre>
  +
[cepstral]
  +
;Random Numbers will all be above 3001. 3000 and below is safe for other utilities and tests.
  +
exten =>_XXX.,1,NoOp()
  +
;same =>n,swift(Here we go.)
  +
same =>n,Set(TESTAT=${CUT(SIP_HEADER(From),@,2)})
  +
same =>n,NoOp(${TESTAT:0:13})
  +
same =>n,agi(Cepstral.agi)
  +
same =>n,NoOp(${SWIFT_DTMF})
  +
same =>n,agi(Process_DTMF_Cepstral.agi,${SWIFT_DTMF})
  +
same =>n,Hangup()
  +
</pre>
  +
===== /var/lib/asterisk/agi-bin/Cepstral.agi =====
  +
<pre>
  +
#!/usr/bin/perl
  +
use lib ('/var/lib/asterisk/agi-bin/modules');
  +
use Cepstral_Include;
  +
use Cepstral_Database;
  +
use DBI;
  +
use Asterisk::AGI;
  +
use Switch;
  +
  +
my $now_date_time = utilities::now_date_time;
  +
my $now_date = utilities::now_date;
  +
  +
$AGI = new Asterisk::AGI;
  +
  +
$dbhA = DBI->connect("DBI:mysql:asterisk:xxx.xxx.xxx.xxx: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=Cepstral_Database::get_tts_data($dbhA,$extension);
  +
print STDERR "before: 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";
  +
  +
</pre>
  +
 
# 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
 
# Collect keys pressed (if any) and place in dtmfpassback
 
# Collect keys pressed (if any) and place in dtmfpassback
 
# Terminate call
 
# Terminate call
  +
 
==== Vicidial Server Continues call ====
 
==== Vicidial Server Continues call ====
 
# Upon termination of Cepstral leg, capture dtmfpassback and route accordingly.
 
# Upon termination of Cepstral leg, capture dtmfpassback and route accordingly.

Revision as of 01:54, 12 July 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;

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 so this is where we left it.

Pass call from Vicidial to Cepstral

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;
}
Gather Data and DTMF Rules on Vicidial Server
Store Data from Vicidial server in table using Number generated
Dial Number from Vicidial to Cepstral

Perl AGI example

  • 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
  • Note that this particular script is designed to get a 10 digit phone number and has rules in it to demonstrate this.
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=utilities::NUID();
                # 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' )");
                # Dial GUID through cepstral
                $AGI->exec('Dial', "SIP/cepstral/$NUID||g");
                # Capture DTMF response from db record.
                $choice = database::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';
            }

    }

Cepstral Services the Call

/etc/asterisk/extensions.conf on Cepstral
[cepstral]
;Random Numbers will all be above 3001. 3000 and below is safe for other utilities and tests.
exten =>_XXX.,1,NoOp()
;same  =>n,swift(Here we go.)
same =>n,Set(TESTAT=${CUT(SIP_HEADER(From),@,2)})
same =>n,NoOp(${TESTAT:0:13})
same  =>n,agi(Cepstral.agi)
same =>n,NoOp(${SWIFT_DTMF})
same  =>n,agi(Process_DTMF_Cepstral.agi,${SWIFT_DTMF})
same =>n,Hangup()
/var/lib/asterisk/agi-bin/Cepstral.agi
#!/usr/bin/perl
use lib ('/var/lib/asterisk/agi-bin/modules');
use Cepstral_Include;
use Cepstral_Database;
use DBI;
use Asterisk::AGI;
use Switch;

my $now_date_time = utilities::now_date_time;
my $now_date = utilities::now_date;

$AGI = new Asterisk::AGI;

$dbhA = DBI->connect("DBI:mysql:asterisk:xxx.xxx.xxx.xxx: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=Cepstral_Database::get_tts_data($dbhA,$extension);
print STDERR "before: 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";

  1. Use number dialed (DID) as key to grab TTS and DTMF rules
  1. Use Cepstral to play sound
  2. Collect keys pressed (if any) and place in dtmfpassback
  3. 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!