Read DTMF value from AGI or From Dialplan

Hi Guys,

I am using Freepbx distro with Asterisk 11.
I want to fetch these DTMFS and display their pattern to my queue agent before the calls connects to them.

[2020-10-13 20:28:46] DTMF[5155][C-000463e7]: channel.c:4170 __ast_read: DTMF begin '1' received on SIP/1004-0004fd97
[2020-10-13 20:28:46] DTMF[5155][C-000463e7]: channel.c:4181 __ast_read: DTMF begin passthrough '1' on SIP/1004-0004fd97
[2020-10-13 20:28:46] DTMF[5155][C-000463e7]: channel.c:4084 __ast_read: DTMF end '1' received on SIP/1004-0004fd97, duration 160 ms
[2020-10-13 20:28:46] DTMF[5155][C-000463e7]: channel.c:4125 __ast_read: DTMF end accepted with begin '1' on SIP/1004-0004fd97
[2020-10-13 20:28:46] DTMF[5155][C-000463e7]: channel.c:4154 __ast_read: DTMF end passthrough '1' on SIP/1004-0004fd97
[2020-10-13 20:28:46] DTMF[5190][C-000463e9]: channel.c:4170 __ast_read: DTMF begin '1' received on SIP/DIDFS2-0004fd9a
[2020-10-13 20:28:46] DTMF[5190][C-000463e9]: channel.c:4174 __ast_read: DTMF begin ignored '1' on SIP/DIDFS2-0004fd9a
[2020-10-13 20:28:46] DTMF[5190][C-000463e9]: channel.c:4084 __ast_read: DTMF end '1' received on SIP/DIDFS2-0004fd9a, duration 220 ms
[2020-10-13 20:28:46] DTMF[5190][C-000463e9]: channel.c:4154 __ast_read: DTMF end passthrough '1' on SIP/DIDFS2-0004fd9a

FreePBX in the Logs by default displaying DTMFs. but don’t know how and in which file code.

if you can see Freepbx by default giving these values. please check below:

__ast_read: DTMF end ‘1’ received on SIP/DIDFS2-0004fd9a, duration 220 ms

how can I get that output store in the database or where can I access that ?
I need these DTMF to print out and display to my queue agents.

where are these values stored in the database or in the system. How can I access this ?

not able to get any dtmf digits from the below code:

$result = $agi->get_data(${IVR_MSG}, 6000, 10);
$agi->verbose(“Result For DTMF is” .json_encode($result));
$agi->verbose(“Result is $result”);

OUTPUT:

pbx.c:     -- Executing [s@ivr-23:10] AGI("SIP/DIDFS1-00054bce", "get.dtmf.php") in new stack
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:     -- Launched AGI Script /var/lib/asterisk/agi-bin/get.dtmf.php
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:  get.dtmf.php: Faisal Testing CID Superfecta 
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:  get.dtmf.php: AGI is Running -------------------------- Connected
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:  get.dtmf.php: CID Testing: number passed from Asterisk is: 123456789
    /var/log/asterisk/full:[2020-10-15 14:32:24] WARNING[24709][C-00048c59] file.c: File 6000 does not exist in any format
    /var/log/asterisk/full:[2020-10-15 14:32:24] WARNING[24709][C-00048c59] file.c: Unable to open 6000 (format (ulaw)): No such file or directory
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:  get.dtmf.php: Result For DTMF is{code:200,result:-1,data:}
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:  get.dtmf.php: Result is Array
    /var/log/asterisk/full:[2020-10-15 14:32:24] VERBOSE[24709][C-00048c59] res_agi.c:     -- <SIP/DIDFS1-00054bce>AGI Script get.dtmf.php completed, returning 0

Although you haven’t said which class library you are using, and even if included with Asteirsk, the class libraries tend to third party, I can’t see an obvious reason why the timeout should be treated as though it were the first parameter.

Except that, I’m not convinced that ${name} is meaningful in PHP, and I think that the protocol arguments are space delimited, so an empty file name would not reserve a place for the file name and the timeout would be interpreted as the filename.

Asterisk doesn’t store DTMF digits anywhere. They are queued, in real time, in the same queue as media, and must be read at the time that they actually arrive.

Most here will have no idea of what priorities 1-9 of the s extension in the ivr-23 script do, or the context in which that extension is invoked, as we are Asterisk users, but not FreePBX users.

You may find it useful to enable AGI debugging ('agi set debug on') to see what is being sent to and from your AGI.

Try this
$result = $agi->get_data($IVR_MSG, 6000, 10);
also $result is an array you cant echo an array on php, instead you need print_r() which or loop beetwen array values

This is my modified code now:

$agi->verbose("Faisal Testing CID Superfecta ");
$agi->verbose("AGI is Running -------------------------- Connected");

$agi->verbose("CID Testing: number passed from Asterisk is: " . $agi->request['agi_callerid']);
$wait_ext = $agi->exec('WaitExten','3');

$agi->verbose("Result of wait extension === ".json_encode($wait_ext));

$result = $agi->get_data($IVR_MSG, 6000, 10);

$agi->verbose("Result For DTMF is" .json_encode($result));
			
$agi->verbose("Result is ".json_encode($result));

please find output of the above modification.

/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] pbx.c:     -- Executing [s@ivr-23:10] AGI("SIP/DIDFS2-000577c7", "get.dtmf.php") in new stack
/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] res_agi.c:     -- Launched AGI Script /var/lib/asterisk/agi-bin/get.dtmf.php
/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: Faisal Testing CID Superfecta 
/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: AGI is Running -------------------------- Connected
/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: CID Testing: number passed from Asterisk is: 123456789
/var/log/asterisk/full:[2020-10-16 14:56:56] VERBOSE[1555][C-0004a3af] res_agi.c:     -- AGI Script Executing Application: (WaitExten) Options: (3)
/var/log/asterisk/full:[2020-10-16 14:56:59] VERBOSE[1555][C-0004a3af] pbx.c:     -- Timeout on SIP/DIDFS2-000577c7, continuing...
/var/log/asterisk/full:[2020-10-16 14:56:59] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: Result of wait extension === {code:200,result:0,data:}
/var/log/asterisk/full:[2020-10-16 14:56:59] WARNING[1555][C-0004a3af] file.c: File 6000 does not exist in any format
/var/log/asterisk/full:[2020-10-16 14:56:59] WARNING[1555][C-0004a3af] file.c: Unable to open 6000 (format (ulaw)): No such file or directory
/var/log/asterisk/full:[2020-10-16 14:56:59] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: Result For DTMF is{code:200,result:-1,data:}
/var/log/asterisk/full:[2020-10-16 14:56:59] VERBOSE[1555][C-0004a3af] res_agi.c:  get.dtmf.php: Result is {code:200,result:-1,data:}
/var/log/asterisk/full:[2020-10-16 14:56:59] VERBOSE[1555][C-0004a3af] res_agi.c:     -- <SIP/DIDFS2-000577c7>AGI Script get.dtmf.php completed, returning 0

I am still unable to get any DTMFs

Asterisk side Dialplan code:

[ivr-23] ; Testing MP
include => ivr-23-custom
include => from-did-direct-ivr
exten => s,1,Set(TIMEOUT_LOOPCOUNT=0)
exten => s,n,Set(INVALID_LOOPCOUNT=0)
exten => s,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT})
exten => s,n,Set(_IVR_CONTEXT=${CONTEXT})
exten => s,n,Set(__IVR_RETVM=)
exten => s,n,GotoIf($["${CDR(disposition)}" = "ANSWERED"]?skip)
exten => s,n,Answer
exten => s,n,Wait(1)
exten => s,n(skip),Set(IVR_MSG=custom/Brooklyn)
exten => s,n,AGI(get.dtmf.php)
exten => s,n(start),Set(TIMEOUT(digit)=3)
exten => s,n,Noop(DTMF Pressed before ExecIf Background----- ${EXTEN})

exten => s,n,AGI(get.dtmf.php)
exten => s,n,ExecIf($["${IVR_MSG}" != ""]?Background(${IVR_MSG}))
exten => s,n,Noop(DTMF Pressed after Background----- ${EXTEN})
exten => s,n,WaitExten(10)
exten => s,n,AGI(get.dtmf.php)
exten => s,n,Noop(DTMF Pressed after WaitExten----- ${EXTEN})


exten => 1,1(ivrsel-1),Goto(ext-queues,3035,1)

exten => 2,1(ivrsel-2),Goto(ext-queues,3035,1)

exten => 3,1(ivrsel-3),Goto(ext-queues,3035,1)

exten => i,1,Set(INVALID_LOOPCOUNT=$[${INVALID_LOOPCOUNT}+1])
exten => i,n,GotoIf($[${INVALID_LOOPCOUNT} > 3]?final)
exten => i,n,Set(IVR_MSG=no-valid-responce-pls-try-again)
exten => i,n,Goto(s,start)
exten => i,n(final),Playback(no-valid-responce-transfering)
exten => i,n,Goto(ext-queues,3035,1)

exten => t,1,Set(TIMEOUT_LOOPCOUNT=$[${TIMEOUT_LOOPCOUNT}+1])
exten => t,n,GotoIf($[${TIMEOUT_LOOPCOUNT} > 3]?final)
exten => t,n,Set(IVR_MSG=no-valid-responce-pls-try-again)
exten => t,n,Goto(s,start)
exten => t,n(final),Playback(no-valid-responce-transfering)
exten => t,n,Goto(ext-queues,3035,1)

exten => return,1,Set(_IVR_CONTEXT=${CONTEXT})
exten => return,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT_${CONTEXT}})
exten => return,n,Set(IVR_MSG=custom/Brooklyn)
exten => return,n,Goto(s,start)

exten => h,1,Hangup

exten => hang,1,Playback(vm-goodbye)
exten => hang,n,Hangup

;--== end of [ivr-23] ==--;

For Testing purpose I have placed the agi code in 3 different locations to read the value of DTMFs.

In the first version of my response, I said the log didn’t match the script. I erroneously edited that out. You still haven’t provided the complete script. Assuming that says you are using PHPAGI, as your class library, you need to get support from https://sourceforge.net/p/phpagi/discussion/366892 as you seem to be having problems with the class library, rather than with Asterisk.

You are still passing an empty first argument get AGI GET DATA. Assuming PHPAGI, and that the behaviour is consistent with version 2.2 of that, Asterisk variables are passed as an associative array, $request, not as individual PHP variables. That makes a lot of sense, as it avoids clashes.

WaitExten will read out the DTMF digits, As well as that, if it matches an extension, it will cause a transfer of control. In the case of the one in the dialplan, that will prevent the AGI call ever being reached, and, although there are no warnings about doing so, I wouldn’t expect predictable behaviour as the result of invoking an application that causes a permanent transfer of control, using AGI EXEC. It is possible that the transfer won’t take effect until the AGI script completes.

In addition to what david551 says…

  1. I still think this has value for you.

  2. The PHPAGI class methods return an associative array containing 3 members: code, result, and data.

  3. waitexten is probably not what you want in an AGI. It appears that it only allows a single digit to be entered and it does not interact with the current context’s dialplan as expected. Even ‘i’ and ‘t’ do not execute as expected.

  4. Keep in mind, an AGI is a separate process. An Asterisk channel variable is not a PHP variable and vice-versa.

It did not in my tests and the documentation makes no mention of this.

Ok let’s leave AGI.

Another idea to get DTMFs is from WaitExten(10) or from here
exten => s,n(start),Set(TIMEOUT(digit)=3)

how can I store the values of WaitExtensio(10) or exten => s,n(start),Set(TIMEOUT(digit)=3)`
in a variable in Asterisk Dialplan not in AGI and print it like Noop(DTMF Pressed – $WaitExten)

I hope this will give me the DTMF values passed by.

I think you are barking up the wrong tree.

I think 'waitexten' is the wrong approach. The purpose of 'waitexten' is to match an extension in the current context, not generically enter digits.

Let’s not give up on AGI yet. The AGI 'get data' will do what I think you want. Or if you want to bail and read digits in 'dialplan', take a look at 'read()' and other dialplan applications.

The description say it waits for extension to be entered. and once an extension has been entered those digits will no longer be accessible to alternative ways of reading DTMF. It says an extension, not a single digit extension.

Looking at how it works, there is no way that it would work properly when EXECed, whether from AGI or from dialplan, as it relies on the dialplan interpreter treating non-zero return codes that match the character forms of valid DTMF digits being handled specially as current dialplan execution sequence is abandoned. In doing so, it has still been absorbed from the internal queue, so will not be returned by GET DATA,

A non-zero return code always causes termination of dialplan execution (“spawn extension exited non-zero”, in the logs), but if I read it correctly, if auto fallthrough is not set it loops back to read a complete new number, and, if it is a valid digit, it loops back trying to read a valid number, but using the digit from WaitExten as the first digit, even if auto fallthrough is set.

I’d assumed it worked as a sort of Goto that read the target extension, but it is more drastic than that, and, presumably, wipes the Gosub stack.

(If it times out and the AGI is the last priority, it will force a Goto to t or e extrensions, rather than allowing a fallthrough, but that won’t happen until the AGI returns, and returns zero. The reason it mustn’t be used in macros is because this part of the processing assumes that it is not in a macro.)

Actually what I want is to read the dtmf extensions like I have a multiple menu IVR and I want the options selected by the caller to reach the queue agent. What I want is to display those options of the IVR to the agent so that he knows what the caller is looking for.

I think this will help elaborating my scenario and may be I am doing it wrong to get this information… I don’t want anyother information from caller. Just want to read the options selected by the caller by presseng dtmfs like option 1 and then option 2 and then option 3 to reach the queue agent. I want 1,2,3 to display it to the Agent before he connects with the caller.

I’d suggest, in dialplan, appending the digits to a channel variable, at the start of the IVR action, and use that variable when actually calling the agent.

The OP is json encoding this arrray, which is serialising the structure, and that is working, as can be seen in the logs.

#!/usr/bin/php -q
<?php
error_reporting(E_ALL);
set_time_limit(30);
require_once('/root/phpagi-svn/phpagi.php');
$agi = new AGI();
$agi->answer();
$result = $agi->get_data('welcome',8000 ,3);

$keys = $result['result'];
$agi->verbose(" Testing $keys",1);
$agi->say_digits($keys);

exit();
?>