How to capture IVR dtmf input along with the timestamp using dynamic routes

Hi everyone,

I would like a setup where I can capture the dtmf input as well as its timestamp on each level on a multilevel IVR. The end user gives a miss call and then the system calls back the user.

I am using FreePBX system version 12.7.8-2306-1.sng7 and PBX version 16.0.40.7.

I am using dynamic routes and custom agi to create the setup. I looked around in the forums and they helped me like here and here. I got the ivr to work and i can capture the dtmf but I cannot capture the timestamp in the log/database. The timestamp reflects in the asterisk console. Any kind of guidance of how I can achieve this would be of great help. Maybe a fresh set of eyes can catch my mistake.

Thanks in advance.

How the dynamic route looks like

zoomed in dynamic route

lvl1time.php agi

#!/usr/bin/php -q
<?php

$logFile = '/var/log/agi/lvl1dtmf.log';  // Replace with the desired log file path
$logHandle = fopen($logFile, 'a');

echo "Debug: Script started\n";

#parse the data from AGI
require('phpagi.php');
$agi = new AGI();
#$lvl1timestamp = strval($lvl1timestamp);
echo "Debug: AGI object created\n";
$lvl1dtmfinput = $agi->request['agi_arg_1'];
$lvl1timestamp = $agi->request['agi_arg_2'];

// Concatenate AGI values with commas as separators
$logString = "$lvl1dtmfinput, $lvl1timestamp";

// Write the log string to the log file
fwrite($logHandle, $logString . "\n");

fclose($logHandle);


#pass value to other agi
$agi->exec('SET VARIABLE', 'lvl1time=' . $lvl1timestamp);
// Invoke the second PHP AGI script
$agi->exec('AGI', 'ivrdtmfvalues.php');
echo "Debug: lvl1timestamp: $lvl1timestamp\n";
// Set the channel variable 'lvl1time'
$agi->set_variable('lvl1time', $lvl1timestamp);


echo "Debug: DTMF input: $lvl1dtmfinput\n";
echo "Debug: Timestamp: $lvl1timestamp\n";
#echo "Debug: lvl1time is $lvl1time\n";

#DB connection parameters
$hostname = "localhost";
$username = "freepbx";
$password = "freepbx";
$dbName = "ivrdtmf";

#parse SQL calling data
$conn = new mysqli($hostname, $username, $password, $dbName);

echo "Debug: Attempting to connect to the database\n";

# Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

echo "Debug: SQL connection successful\n";

$sql = "INSERT INTO dtmf_data (`digit`, `timestamp`) VALUES ('$lvl1dtmfinput', '$lvl1timestamp');";

echo "Debug: SQL query: $sql\n";

if ($conn->query($sql) === TRUE) {
    echo "IVR DTMF input saved to the database: $lvl1dtmfinput\n";
    echo "IVR DTMF time saved to the database: $lvl1timestamp\n";
} else {
    echo "Error: " . $sql . "<br>" . $conn->error;
}

$conn->close();
?>

ivrdtmfvalues.php

#!/usr/bin/php -q
<?php
#parse the data from AGI
require('phpagi.php');
$agi = new AGI();
$uniqueid = $agi->request['agi_uniqueid'];
$cid = $agi->request['agi_channel'];
$lvl1dtmfinput = $agi->request['agi_arg_1'];
$lvl2dtmfinput = $agi->request['agi_arg_2'];
$disposition = $agi->request['agi_arg_3'];
$calldate = $agi->request['agi_arg_4'];
$duration = $agi->request['agi_arg_5'];
$billsec = $agi->request['agi_arg_6'];

// Retrieve the level 1 timestamp passed as an argument
$lvl1timestamp = $agi->request['agi_arg_7'];
echo "lvl1time: $lvl1timestamp\n";
// Retrieve the channel variable set in the first AGI script
#$lvl1time = $agi->get_variable('lvl1time');
#$lvl1time = trim($lvl1time['data']);
#$lvl1timestamp = $agi->get_variable('lvl1time');
#$lvl2timestamp = $agi->get_variable('lvl2time');

    function callbacknumber($str, $starting_word, $ending_word)
{
    $subtring_start = strpos($str, $starting_word);
    //Adding the starting index of the starting word to its length would give its ending index
    $subtring_start += strlen($starting_word);
    //Length of our required sub string
    $size = strpos($str, $ending_word, $subtring_start) - $subtring_start;
    // Return the substring from the index substring_start of length size
    return substr($str, $subtring_start, $size);
}

$str = $cid;
$callerid = callbacknumber($str, '/', '@');

#echo $substring;
#DB connection parameters
$hostname = "localhost";
$username = "freepbx";
$password = "freepbx";
$dbName = "ivrdtmf";

#parse SQL calling data
$conn = new mysqli($hostname, $username, $password, $dbName);
# Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}

$sql = "INSERT INTO dtmfdata (`calldate`, `callerid`,`duration`, `billsec`,  `disposition`, `uniqueid`, `lvl1dtmfinput`, `lvl1dtmftime`, `lvl2dtmfinput`, `lvl2dtmftime`) VALUES ('$calldate', '$callerid', '$duration', '$billsec', '$disposition', '$uniqueid', '$lvl1dtmfinput', '$lvl1timestamp', '$lvl2dtmfinput', '$lvl2dtmftime');";

if ($conn->query($sql) === TRUE) {
    echo "IVR DTMF input saved to the database: $dtmfinput\n";
#    echo "lvl1dtmftime: $lvl1timestamp\n";
#    echo "lvl2dtmftime: $lvl2timestamp\n";
    echo "lvl1time: $lvl1time\n";
} else {
    echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
?>

agi debug trace

[2023-10-10 14:22:24] DTMF[1416][C-00000006]: channel.c:4001 __ast_read: DTMF begin '2' received on SIP/Dot62-00000004
[2023-10-10 14:22:24] DTMF[1416][C-00000006]: channel.c:4012 __ast_read: DTMF begin passthrough '2' on SIP/Dot62-00000004
[2023-10-10 14:22:24] DTMF[1359][C-00000007]: channel.c:4001 __ast_read: DTMF begin '2' received on Local/3403331927@from-internal-00000001;1
[2023-10-10 14:22:24] DTMF[1359][C-00000007]: channel.c:4005 __ast_read: DTMF begin ignored '2' on Local/3403331927@from-internal-00000001;1
[2023-10-10 14:22:24] DTMF[1416][C-00000006]: channel.c:3887 __ast_read: DTMF end '2' received on SIP/Dot62-00000004, duration 340 ms
[2023-10-10 14:22:24] DTMF[1416][C-00000006]: channel.c:3938 __ast_read: DTMF end accepted with begin '2' on SIP/Dot62-00000004
[2023-10-10 14:22:24] DTMF[1416][C-00000006]: channel.c:3976 __ast_read: DTMF end passthrough '2' on SIP/Dot62-00000004
[2023-10-10 14:22:24] DTMF[1359][C-00000007]: channel.c:3887 __ast_read: DTMF end '2' received on Local/3403331927@from-internal-00000001;1, duration 340 ms
[2023-10-10 14:22:24] DTMF[1359][C-00000007]: channel.c:3976 __ast_read: DTMF end passthrough '2' on Local/3403331927@from-internal-00000001;1
    -- User entered '2'
    -- Executing [s@dynroute-1:3] Set("Local/3403331927@from-internal-00000001;1", "__DYNROUTE_input_lvl1dtmf=2") in new stack
    -- Executing [s@dynroute-1:4] Set("Local/3403331927@from-internal-00000001;1", "dynroute=") in new stack
    -- Executing [s@dynroute-1:5] AGI("Local/3403331927@from-internal-00000001;1", "agi://127.0.0.1/var/lib/asterisk/agi-bin/lvl1time.php,2,2023-10-10 14:22:24") in new stack
AGI Tx >> agi_network: yes
AGI Tx >> agi_network_script: var/lib/asterisk/agi-bin/lvl1time.php
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_request: agi://127.0.0.1/var/lib/asterisk/agi-bin/lvl1time.php
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_channel: Local/3403331927@from-internal-00000001;1
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_language: en
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_type: Local
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_uniqueid: 1696929725.6
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_version: 20.4.0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_callerid: 2138654105
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_calleridname: unknown
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_callingpres: 0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_callingani2: 0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_callington: 0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_callingtns: 0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_dnid: unknown
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_rdnis: unknown
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_context: dynroute-1
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_extension: s
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_priority: 5
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_enhanced: 0.0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_accountcode:
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_threadid: 140245726897920
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_arg_1: 2
<Local/3403331927@from-internal-00000001;1>AGI Tx >> agi_arg_2: 2023-10-10 14:22:24
<Local/3403331927@from-internal-00000001;1>AGI Tx >>
    -- <Local/3403331927@from-internal-00000001;1>AGI Script agi://127.0.0.1/var/lib/asterisk/agi-bin/lvl1time.php completed, returning 0
<Local/3403331927@from-internal-00000001;1>AGI Tx >> HANGUP

What do you mean by timestamp? Are you talking about the time that the call arrived on the system? If so you can get that from the uniqueid, the non-decimal portion is the call time in unix epoch.

The time the dtmf was selected. If you check the asterisk trace, you can see that I am able to capture that time as agi_arg_2. However, I am unable to save it, either in db, or in a log file.

Does the asterisk user have the correct permissions for the files and DBs involved?

I asked myself the same thing and this is what I did to test.

Dynamic route

Custom destination

Custom dialplan

The data is written in log file as well the database. But if I try it to do the other way, it does not work.

Why not ivrdtmftime,s,1 ?

It works either way for the test setup. However, not working on the actual setup. In the actual setup, as described in the first post, I am calling the agi directly not not going to a custom destination.

tried both root and asterisk as owner and changed permissions to 777. No luck

I know I can write a custom dialplan for the whole thing. However, I am doing this for an educational NGO so just wanted to give them access so that they could manage it themselves if I can setup the whole thing using FreePBX UI.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.