AMI Script // Text-to-speech help

I have created a simple test script that will dial an extension and deliver a message. Its working fine. It dials an extension and plays an audio file.

Can someone point me to a guide or commands which will dial an extension and instead of playing an audio file, it will read out a message using TTS – something like “Extension 1001 is not reachable”. I need something basic, nothing fancy. This is for notifications & alerts.

My current script is as below.

<?php
//https://wiki.asterisk.org/wiki/display/AST/Asterisk+16+AMI+Events

$socket = fsockopen("127.0.0.1","5038", $errno, $errstr, 10);
if (!$socket)
{
	echo "$errstr ($errno)\n";
}
else
{
	fputs($socket, "action: login\r\n");
	fputs($socket, "username: admin\r\n");
	fputs($socket, "secret: xxxxxxxxxxxxx\r\n\r\n");

	fputs($socket, "Action: Originate\r\n");
	fputs($socket, "Channel: PJSIP/1022\r\n");
	fputs($socket, "Application: Playback\r\n");
	fputs($socket, "Data: silence/1&tt-weasels\r\n\r\n");

	$wrets = fgets($socket,128);

	fputs($socket, "Action: Logoff\r\n\r\n");
}

Thanks!!

Some barebones dialplan:

[custom-ext-not-reachable]
exten => _.,1,Noop(Entering user defined context custom-ext-not-reachable in extensions_custom.conf)
exten => _.,n,flite(Extension ${EXTEN} is not reachable)
exten => _.,n,Hangup()

Then originate the call to
Application: Extension
context: custom-ext-not-reachable
exten: 1001
priority: 1

Hi @lgaetz Thanks for sharing the details but Extension not reachable was just an example.

I want to be able to TTS any message, even something like “Reminder - PTM Meeting in school at 11am today:wink:

Sorry, if I was not clear. If you can suggest what should the AMI script be like it would be of great help!!

Thanks

I’m on mobile, but you can look up how to set a channel var in the script with the content of the TTS message, and then reference that var in the dialplan.

Thanks again. From what I read on multiple forums, the approach is:

(1) Setup TTS in FreePBX.
I think I’ve done this. Settings > TTS Engine > Flite > Path = /usr/bin/flite

(2) In AMI Script create a variable with the message
Thats should be simple:
$myMessage = “Reminder, PTM at 10:00 AM today”;

(3) Parse this variable to FLITE and get an audio file converted

(4) use this audio file in the AMI Script here:
fputs($socket, “Data: silence/1&tt-weasels\r\n\r\n”);
replace “silence/1&tt-weasels” with result from (3)

I’m unable to get (3) to work. I guess once I resolve (3) I’ll be good to go.

Thanks again!!

Include a variable line in your Originate:

fputs($socket, “Variable: myMessage=Reminder PTM at 10:00 AM today\r\n");

And then ref that variable in the dialplan:

[custom-ext-not-reachable]
exten => _.,1,Noop(Entering user defined context custom-ext-not-reachable in extensions_custom.conf)
exten => _.,n,flite(${myMessage})
exten => _.,n,Hangup()

Thanks for sharing the code.

  1. I copied exactly as you mentioned in /etc/asterisk/extensions_custom.conf
  2. Reloaded the dialplan: rasterisk -x “dialplan reload”
  3. Asterisk console “asterisk -rvvvvvv” reported a ton of WARNINGS. Some of them are as below

[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-announcement-5’ tries to include nonexistent context ‘app-announcement-5-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-announcement-4’ tries to include nonexistent context ‘app-announcement-4-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-announcement-3’ tries to include nonexistent context ‘app-announcement-3-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-announcement-2’ tries to include nonexistent context ‘app-announcement-2-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-announcement-1’ tries to include nonexistent context ‘app-announcement-1-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-dnd-toggle’ tries to include nonexistent context ‘app-dnd-toggle-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-dnd-on’ tries to include nonexistent context ‘app-dnd-on-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-dnd-off’ tries to include nonexistent context ‘app-dnd-off-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-cf-on’ tries to include nonexistent context ‘app-cf-on-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-cf-off’ tries to include nonexistent context ‘app-cf-off-custom’
[2020-05-06 05:35:07] WARNING[2082]: pbx.c:8732 ast_context_verify_includes: Context ‘app-cf-toggle’ tries to include nonexistent context ‘app-cf-toggle-custom’

  1. I modified my PHP script. added

fputs($socket, “Variable: myMessage=Reminder PTM at 10:00 AM today\r\n”);

  1. Executed the php script, I received a blank call.

Did I miss something which was expected from me outside of your instructions?

Vai

I did some experimenting…
from extensions_custom.conf, I commented the last line:
exten => _.,n,Hangup()
Reloaded the dial plan and executed the PHP script & I got the following on the console.

Asterisk 16.6.2, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <[email protected]>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
    Connected to Asterisk 16.6.2 currently running on ast (pid = 2447)
        -- Called 1020
      == Using SIP RTP Audio TOS bits 184
      == Using SIP RTP Audio TOS bits 184 in TCLASS field.
      == Using SIP RTP Audio CoS mark 5
        -- PJSIP/1020-00000adc is ringing
        -- PJSIP/1020-00000adc is ringing
           > 0x7f86003972a0 -- Strict RTP learning after remote address set to: 10.9.169.200:4004
        -- PJSIP/1020-00000adc answered
           > Launching Playback() on PJSIP/1020-00000adc
    [2020-05-06 07:17:05] WARNING[26941]: app_playback.c:452 playback_exec: Playback requires an argument (filename)

Does this help in anyway to debug the issue?

Thanks

You’re still doing the Originte with Application, you need to use extension like I said in my first post above:

Below works without dialplan here, but really needs a wait before playback.

fputs ($socket, "Action: Originate\r\n");
fputs ($socket, "Channel: Local/$exten\r\n");
fputs ($socket, "Exten: $exten\r\n");
fputs ($socket, "Application: flite\r\n");
fputs ($socket, "Data: \"This is a test, this is only a test...\"\r\n");
fputs ($socket, "\r\n");

or:

fputs ($socket, "Application: playback\r\n");
fputs ($socket, "Data: tt-monkeys\r\n");

or even:

fputs ($socket, "Application: agi\r\n");
fputs ($socket, "Data: googletts.agi,\"This is a test, this is only a test...\"\r\n");

Thanks @jerrm This is exactly what I needed. But did not work, I think my flite is not working or something…

$socket = fsockopen("127.0.0.1","5038", $errno, $errstr, 10);
if (!$socket)
{
	echo "$errstr ($errno)\n";
}
else
{
	fputs($socket, "action: login\r\n");
	fputs($socket, "username: admin\r\n");
	fputs($socket, "secret: xxxxxxxx\r\n\r\n");

	fputs($socket, "Action: Originate\r\n");
	fputs($socket, "Channel: PJSIP/1020\r\n");						
	fputs($socket, "Exten: 1020\r\n");
	fputs($socket, "Timeout: 30000\r\n");							
	fputs($socket, "Async: true\r\n");								// for faster dialout
	fputs($socket, "Application: flite\r\n");
	fputs($socket, "Data: Welcome to hello world\r\n");	//
	fputs($socket, "\r\n");

	$wrets = fgets($socket,128);

	fputs($socket, "Action: Logoff\r\n\r\n");
}

A call is received on 1020 but disconnects immediately upon answer.

Can’t speak for why app_flite might not be working. Does flite work from the bash cli?

Does the same AMI code work if you use playback instead?

Does the same AMI code work if you use playback instead?

yes. I’m able to play audio files.

Can’t speak for why app_flite might not be working. Does flite work from the bash cli?

Can you help me with the CLI bash command to test please.

Thanks

flite "Hello World" hello.wav

@jerrm
Yes. The above command created a wav file with the audio “hello world”.
A ray of hope while still in the tunnel :wink:

What next?

I tried the below code again.
I get a call from extn 1022 to extn 1020. As soon as I answer, the call disconnects.
I’m hoping / expecting it to be a minor issue, not sure what.

$socket = fsockopen("127.0.0.1","5038", $errno, $errstr, 10);
if (!$socket)
{
	echo "$errstr ($errno)\n";
}
else
{
	fputs($socket, "action: login\r\n");
	fputs($socket, "username: admin\r\n");
	fputs($socket, "secret: xxxxxxxx\r\n\r\n");

	fputs($socket, "Action: Originate\r\n");
	fputs($socket, "Channel: PJSIP/1020\r\n");						// Extension or Number to DIAL
	fputs($socket, "Exten: 1022\r\n");
	fputs($socket, "Timeout: 30000\r\n");							// (30 sec) in msec
	fputs($socket, "Async: true\r\n");								// for faster dialout
	fputs($socket, "CallerID: 1022 <1022>\r\n");			// No space in callerID name
	fputs($socket, "Application: flite\r\n");
	fputs($socket, "Data: Welcome to hello world\r\n");
	fputs($socket, "\r\n");
	
	$wrets = fgets($socket,128);

	fputs($socket, "Action: Logoff\r\n\r\n");
}

If your OK with flite’s quality, then yum update; fwconsole restart as suggested in the other thread.

Otherwise you can use the command line flite to generate a wav file and convert it for use in playback. Googling “asterisk play wav file” should give you the needed info.

I tried your 2nd suggestion & it works well.

command line flite to generate a wav file and convert it for use in playback

A bit of a longer route but I can live with it.

About flite’s quality, it’s not easy to understand. I was actually googling for a simple CLI based TTS. Until then I’ll go ahead with flite via CLI.

Thanks a ton for your continued support!!
Cheers

Not much to pick from in the distro repo’s. I don’t think the distro flite includes any additional voices. Festival does (slt is probably the best voice). All the tts versions in the repo are outdated.

The clearest command line tts is picotts IMO. Some of the better(newer than the distro) espeak voices are arguably a little less “electronic” but muddy/slurry/drunk sounding in comparison IMO. I don’t know of a centos based picotts package(haven’t looked very hard), but you can get the debian binaries running under the distro.

People ask why some of us don’t use the distro. This is a small example.

If you go the commercial route, there are some other options like Cepstral, but skip those and go with a web api provider.

The better Google/IBM/MS/Amazon voices can be hard to recognize as artificial, but require respective accounts (free or almost free for lite usage).

1 Like

I totally get it now. Slightly off topic, is there a tool to migrate all FreePBX & Asterisk settings from one server to another?

I’ll check this out, my requirement is just about 2-3 TTS per month. I’m sure I’ll be covered with a free account. I’m sorted if these big boys offer CLI.

@jerrm Thanks once again man!!