Last active
July 31, 2025 21:06
-
-
Save jtsage/f38151b43debb6bd90ebaa4f0ab2687f to your computer and use it in GitHub Desktop.
Asterisk Voicemail --> MP3 w/ IBM bluemix trasnscription
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Asterisk Voicemail -> MP3 And IBM Bluemix Transcription | |
| # Set CONFIG_DEBUG to 1 (not zero) to disable file deletion on completion. | |
| # Logs are written to mail.info (likely /var/log/mail.log) | |
| # Bluemix response will be in /tmp/astVM.XXXXXXXX/audio.txt | |
| CONFIG_DEBUG=0 | |
| CONFIG_API_PRIV_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | |
| CONFIG_API_INSTANCE="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | |
| CONFIG_API_MODEL="en-US_Telephony" | |
| CONFIG_API_HOST="us-east" # https://api.us-east.speech-to-text.watson.cloud.ibm.com | |
| # Brief Version History | |
| # 2010-11-22 - Creation by N. Bernaerts | |
| # 2012-05-08 - MP3 Compression Fixes by Luca Mancino | |
| # 2012-08-01 - PATH definition fix by Christopher Wolff | |
| # 2015-07-16 - Native GSM WAV by Michael Munger | |
| # 2015-08-17 - Work by Jason Klien | |
| # 2017-09-17 - Work by lqaetz | |
| # 2020-04-16 - API key work by JTSage | |
| # 2025-07-30 - FreeBSD17 updates, bash conversion, and logging by jtsage | |
| # | |
| # Usage: | |
| # 1.) copy this file to /usr/sbin/ and make it executable by asterisk (chmod 755) | |
| # 2.) In the [general] section of /etc/asterisk/voicemail.conf set mailcmd=/usr/sbin/sendmail.asterisk | |
| # - OR - | |
| # 2.) Set the mail command in Settings->Voicemail Admin->Settings->Email Config (last item) | |
| # | |
| # Permissions - More: Make sure the asterisk user can execute (and that they exist - fwiw, a new | |
| # install of FreePBX 17 circa July 2025, lame and sox existed): | |
| # * dos2unix [# apt install dos2unix] | |
| # * unix2dos | |
| # * sox | |
| # * lame | |
| # * jq [# apt install jq] | |
| # | |
| # set PATH | |
| PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" | |
| # Generate the bluemix URL | |
| API_URL="https://api.$CONFIG_API_HOST.speech-to-text.watson.cloud.ibm.com/instances/$CONFIG_API_INSTANCE/v1/recognize?model=$CONFIG_API_MODEL" | |
| exec 1> >(exec logger -p mail.info -t $(basename $0)) 2>&1 | |
| # save the current directory | |
| pushd . > /dev/null | |
| # Create temporary working directory | |
| TMPDIR=$(mktemp -d /tmp/astVM.XXXXXXXXXX) | |
| cd "$TMPDIR" | |
| # dump the stream to a temporary file | |
| cat >> stream.org | |
| # Extract MIME boundary | |
| BOUNDARY=$(grep "boundary=" stream.org | cut -d'"' -f 2) | |
| # cut the file into parts | |
| # stream.part - header before the boundary | |
| # stream.part1 - header after the boundary | |
| # stream.part2 - body of the message | |
| # stream.part3 - attachment in base64 (WAV file) | |
| # stream.part4 - footer of the message | |
| awk '/'$BOUNDARY'/{i++}{print > "stream.part"i}' stream.org | |
| # if mail is having no audio attachment (plain text) | |
| PLAINTEXT=$(cat stream.part1 | grep 'plain') | |
| if [ "$PLAINTEXT" != "" ] | |
| then | |
| # prepare to send the original stream | |
| echo "plain text e-mail found, bypassing" | |
| cp stream.org stream.new | |
| else | |
| echo "processing voicemail message" | |
| # cut the attachment into parts | |
| # stream.part3.head - header of attachment | |
| # stream.part3.wav.base64 - wav file of attachment (encoded base64) | |
| sed '7,$d' stream.part3 > stream.part3.wav.head | |
| sed '1,6d' stream.part3 > stream.part3.wav.base64 | |
| # convert the base64 file to a wav file | |
| dos2unix -o stream.part3.wav.base64 | |
| base64 -di stream.part3.wav.base64 > stream.part3.wav | |
| # Send WAV to Watson Speech to Text API. | |
| CURL_OPTS="" | |
| curl -s $CURL_OPTS -k -u "apikey:$CONFIG_API_PRIV_KEY" -X POST \ | |
| --show-error \ | |
| --limit-rate 40000 \ | |
| --header "Content-Type: audio/wav" \ | |
| --data-binary @stream.part3.wav \ | |
| "$API_URL" 1>audio.txt | |
| # Extract transcript results from JSON response | |
| TRANSCRIPT=`jq -er '.results[].alternatives[] | "[\(.confidence)] \(.transcript)"' audio.txt` | |
| # convert wave file (GSM encoded or not) to PCM wav file | |
| sox -V1 stream.part3.wav stream.part3-pcm.wav | |
| # convert PCM wav file to mp3 file | |
| # -b 24 is using CBR, giving better compatibility on smartphones (you can use -b 32 to increase quality) | |
| # -V 2 is using VBR, a good compromise between quality and size for voice audio files | |
| lame -S -m m -b 24 stream.part3-pcm.wav stream.part3.mp3 | |
| # convert back mp3 to base64 file | |
| base64 stream.part3.mp3 > stream.part3.mp3.base64 | |
| # generate the new mp3 attachment header | |
| # change Type: audio/x-wav or audio/x-WAV to Type: audio/mpeg | |
| # change name="msg----.wav" or name="msg----.WAV" to name="msg----.mp3" | |
| sed -E 's/x-[wW][aA][vV]/mpeg/g; s/\.[wW][aA][vV]/.mp3/g' stream.part3.wav.head > stream.part3.mp3.head | |
| # generate first part of mail body, converting it to LF only | |
| mv stream.part stream.new | |
| cat stream.part1 >> stream.new | |
| sed '$d' < stream.part2 >> stream.new | |
| # transcription section | |
| { | |
| echo -e "\n--- Automated transcription result ---\n" | |
| echo "$TRANSCRIPT" | |
| tail -1 stream.part2 | |
| cat stream.part3.mp3.head | |
| } >> stream.new | |
| dos2unix -o stream.new | |
| # append base64 mp3 to mail body, keeping CRLF | |
| unix2dos -o stream.part3.mp3.base64 | |
| cat stream.part3.mp3.base64 >> stream.new | |
| # append end of mail body, converting it to LF only | |
| { | |
| echo "" | |
| echo "" | |
| cat stream.part4 | |
| } > stream.tmp | |
| dos2unix -o stream.tmp | |
| cat stream.tmp >> stream.new | |
| fi | |
| # Send email | |
| sendmail -t < stream.new | |
| # Cleanup | |
| popd > /dev/null | |
| # remove all temporary files and temporary directory | |
| # if things are not working, this is a great place to | |
| # start. If, as in my experience, you can't find the | |
| # temp folder than, check your spelling that FreePBX | |
| # is trying to run the right script. | |
| if [ "$CONFIG_DEBUG" -eq 0 ]; then | |
| rm -Rf $TMPDIR | |
| fi |
Author
Author
- updated for FreePBX17 / new voice models.
- added syslog logging to mail.info (probably /var/log/mail.log)
- moved the config stuff closer to the top, added a DEBUG flag to toggle file removal
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Couple of things for debugging purposes that it took a while for me to notice:
1.) FreeBPX / Asterisk don't appear to tell you if it can't find the script (this was not the correct filename at that point)
2.) If you do turn off removal of the temp directory to pipe the steam file in again:
IT WILL NOT APPEAR. There is a message-ID header in there, duplicates are ignored, at least by gmail - change it a bit each time.
3.) Errors from IBM are accessible in the audio.txt file in the created temp directory