Text to Speech Bash Script

For my home Asterisk Phone Server I wanted to create an extension which could dialed and get a random Chuck Norris fact recited to the caller.

At first I tried using tools like espeak (and others) but found that the output audio was not very desirable and difficult to understand. I then found several online text to speech services which provided pretty decent output. One of which was https://www.naturalreaders.com/online/. After examining the network traffic in Chrome Developer Tools I found that the online form is simply doing an HTTP Post to a specific address resulting in a file download containing an mp3 file of the spoken text.

I wrote a bash script to automate this, naturally.

The script dumps the downloaded mp3 data to the standard output. This is done so it can be easily piped to other programs to convert or do whatever with it. Here is an example usage:

echo "Hello World" | ./tts.sh > helloworld.mp3

Chuck Norris

With the site https://api.chucknorris.io/ it was really easy to generate random Chuck Norris Fact mp3’s.

curl -s "https://api.chucknorris.io/jokes/random" | jq -r '.value' | ./tts.sh > chuckfact.mp3

Integrating into Asterisk

Asterisk is able to playback an audio file but the audio format must be a gsm file. Luckily ffmpeg is able to do the conversion necessary.

curl -s "https://api.chucknorris.io/jokes/random" | jq -r '.value' | ./tts.sh | ffmpeg -loglevel quiet -i - -c:a libgsm -ar 8000 -ab 13000 -ac 1 -f gsm chuckfact.gsm

To get Asterisk to play a file it must be placed in the /var/lib/asterisk/sounds/en/ directory. So the above is modified to write to this file (overwriting if the file exists with the -y argument to ffmpeg).

curl -s "https://api.chucknorris.io/jokes/random" | jq -r '.value' | ./tts.sh | ffmpeg -loglevel quiet -i - -c:a libgsm -ar 8000 -ab 13000 -ac 1 -f gsm -y /var/lib/asterisk/sounds/en/chuckfact.gsm

Then modified the extensions.conf file to call the script by first definine a context.

[ChuckNorrisFact]
exten => s,1,System(/var/lib/asterisk/scripts/chuckfact.sh /var/lib/asterisk/sounds/en/chuckfact.gsm)
 same => n,Playback(chuckfact)
 same => n,Return

Then an extension needs to be configured to call the context. I used the number 24825 as that spells out CHUCK on the phone dialpad.

exten => 24825,1,Gosub(ChuckNorrisFact,s,1)