Asterisk voicemail notifications with MP3

I found a lovely script for sending voicemail notifications in MP3 format instead of wav. It’s a bit of a hack, since Asterisk only provides you with an entire, MIME encoded email message as input. Anyway, I improved it somewhat and wanted to share. This version adds call info and an image to the MP3 file, and is more elegant IMHO – e.g. use of pushd/popd or mktemp.

#!/bin/bash
 
# mp3mail accepts a mail message via STDIN and converts an attached WAV file to MP3
# Based on a script by Nicolas Bernaerts (http://bernaerts.dyndns.org/linux/179-asterisk-voicemail-mp3)
# Rewritten to remove dependencies, reduce number of commands, and general cleanup by Michael Newton (mnewton@poptalk.ca)
 
# location of the lame binary
LAME=/usr/bin/lame
 
# Information for mp3 tags
MP3PUBLISHER=""
IMAGEPATH=/var/lib/asterisk/images/logo.png
 
# create a temporary directory and cd to it
TMPDIR=$(mktemp -d)
cd "$TMPDIR" || exit
 
# dump the stream to a temporary file
cat >> stream.org
 
# if we don't have lame, abort and send it normally
if [[ -z "$LAME" ]] || [[ ! -x "$LAME" ]]; then
	sendmail -t < stream.org
	rm -Rf "$TMPDIR"
	return 1
fi
 
# get the boundary
BOUNDARY=$(grep -Pom 1 '(?<=boundary=").+(?=")' stream.org)
 
# cut the file into parts
# stream.part - header before the boundary
# stream.part1 - header including the boundary and following lines
# 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
 
# cut the attachment into parts at the first empty line
# stream.part3.head - header of attachment
# stream.part3.wav.base64 - wav file of attachment (encoded base64)
sed '/^$/,$d' stream.part3 > stream.part3.wav.head
echo >> stream.part3.wav.head
sed '1,/^$/d' stream.part3 > stream.part3.wav.base64
 
# convert the base64 file to a wav file
base64 -di stream.part3.wav.base64 > stream.part3.wav
 
# Get information for the ID3 tags from the email body and headers
# The grep patterns depend on the content of your emails; the below patterns assume the default message
# Use like so: (?<=THE STUFF BEFORE)THE MATCH(?=THE STUFF AFTER)
MP3TEXT=$(cat stream.part2 stream.part1 stream.part)
# message number
MP3NUM=$(echo "$MP3TEXT" |  grep -Pom 1 '(?<=message \(number )\d+(?= \))')
# CID name; expects '"The name" <1234567890>' but won't match 'an unknown caller'
MP3CIDNAME=$(echo "$MP3TEXT" |  grep -Pom 1 '(?<=from ").+(?=")')
# CID number
MP3CIDNUM=$(echo "$MP3TEXT" |  grep -Pom 1 '(?<=\<)\d+(?=\>)')
 
# add an image if specified above
if [[ -z "$IMAGEPATH" ]]; then MP3IMAGE=""; else MP3IMAGE="--ti $IMAGEPATH"; fi
 
# convert wav file to mp3 file and add tags
$LAME --preset standard \
	--tt "Message $MP3NUM" \
	--tn "$MP3NUM" \
	--ta "$MP3CIDNAME" \
	--tl "$MP3CIDNUM" \
	--tg Speech \
	"$MP3IMAGE" \
	--tv TPUB="$MP3PUBLISHER" \
	--id3v2-only \
	stream.part3.wav stream.part3.mp3
 
# generate the new mp3 attachment header
# change Type: audio/x-wav to Type: audio/mpeg
# change name="msg----.wav" to name="msg----.mp3"
sed -e 's/x-wav/mpeg/g' -e 's/\.wav/.mp3/g' stream.part3.wav.head > stream.part3.mp3.head
 
# convert mp3 to base64
base64 stream.part3.mp3 > stream.part3.mp3.base64
 
# put it together to make the email
cat stream.part \
	stream.part1 \
	stream.part2 \
	stream.part3.mp3.head \
	stream.part3.mp3.base64 \
	stream.part4 \
	> stream.new
 
# ensure line endings are CRLF (per RFC) and feed to sendmail
sed 's/\r*$/\r/' stream.new | sendmail -t
 
# remove all temporary files and temporary directory
rm -Rf "$TMPDIR"

#!/bin/bash # mp3mail accepts a mail message via STDIN and converts an attached WAV file to MP3 # Based on a script by Nicolas Bernaerts (http://bernaerts.dyndns.org/linux/179-asterisk-voicemail-mp3) # Rewritten to remove dependencies, reduce number of commands, and general cleanup by Michael Newton (mnewton@poptalk.ca) # location of the lame binary LAME=/usr/bin/lame # Information for mp3 tags MP3PUBLISHER="" IMAGEPATH=/var/lib/asterisk/images/logo.png # create a temporary directory and cd to it TMPDIR=$(mktemp -d) cd "$TMPDIR" || exit # dump the stream to a temporary file cat >> stream.org # if we don't have lame, abort and send it normally if [[ -z "$LAME" ]] || [[ ! -x "$LAME" ]]; then sendmail -t < stream.org rm -Rf "$TMPDIR" return 1 fi # get the boundary BOUNDARY=$(grep -Pom 1 '(?<=boundary=").+(?=")' stream.org) # cut the file into parts # stream.part - header before the boundary # stream.part1 - header including the boundary and following lines # 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 # cut the attachment into parts at the first empty line # stream.part3.head - header of attachment # stream.part3.wav.base64 - wav file of attachment (encoded base64) sed '/^$/,$d' stream.part3 > stream.part3.wav.head echo >> stream.part3.wav.head sed '1,/^$/d' stream.part3 > stream.part3.wav.base64 # convert the base64 file to a wav file base64 -di stream.part3.wav.base64 > stream.part3.wav # Get information for the ID3 tags from the email body and headers # The grep patterns depend on the content of your emails; the below patterns assume the default message # Use like so: (?<=THE STUFF BEFORE)THE MATCH(?=THE STUFF AFTER) MP3TEXT=$(cat stream.part2 stream.part1 stream.part) # message number MP3NUM=$(echo "$MP3TEXT" | grep -Pom 1 '(?<=message \(number )\d+(?= \))') # CID name; expects '"The name" <1234567890>' but won't match 'an unknown caller' MP3CIDNAME=$(echo "$MP3TEXT" | grep -Pom 1 '(?<=from ").+(?=")') # CID number MP3CIDNUM=$(echo "$MP3TEXT" | grep -Pom 1 '(?<=\<)\d+(?=\>)') # add an image if specified above if [[ -z "$IMAGEPATH" ]]; then MP3IMAGE=""; else MP3IMAGE="--ti $IMAGEPATH"; fi # convert wav file to mp3 file and add tags $LAME --preset standard \ --tt "Message $MP3NUM" \ --tn "$MP3NUM" \ --ta "$MP3CIDNAME" \ --tl "$MP3CIDNUM" \ --tg Speech \ "$MP3IMAGE" \ --tv TPUB="$MP3PUBLISHER" \ --id3v2-only \ stream.part3.wav stream.part3.mp3 # generate the new mp3 attachment header # change Type: audio/x-wav to Type: audio/mpeg # change name="msg----.wav" to name="msg----.mp3" sed -e 's/x-wav/mpeg/g' -e 's/\.wav/.mp3/g' stream.part3.wav.head > stream.part3.mp3.head # convert mp3 to base64 base64 stream.part3.mp3 > stream.part3.mp3.base64 # put it together to make the email cat stream.part \ stream.part1 \ stream.part2 \ stream.part3.mp3.head \ stream.part3.mp3.base64 \ stream.part4 \ > stream.new # ensure line endings are CRLF (per RFC) and feed to sendmail sed 's/\r*$/\r/' stream.new | sendmail -t # remove all temporary files and temporary directory rm -Rf "$TMPDIR"

8 Replies to “Asterisk voicemail notifications with MP3”

  1. Threw this in my /usr/sbin folder, made it executable, and modified my voicemail.conf file to write to wav and to reference the script. I get the email, but all MP3’s are completely blank. I have verified Lame is installed. Thoughts?

    1. Terry:
      The LAME options above may not work for your installed version of LAME… You should run “lame –longhelp” and compare the settings available. It’s most likely the “–tv TPUB=”$MP3PUBLISHER”” option as that doesn’t appear to be available in LAME as far as I can tell. It’s possible that Michael meant that to be “–tc TPUB=”$MP3PUBLISHER”” (tc, not tv – just looking at the keyboard – tc is to add a comment, tv doesn’t appear to be a valid LAME option)…

  2. Just wanted to note that it looks like the “–tv” option is available on some builds of LAME… But, for most, if you’re ending up with the 0 byte MP3 files, it’s probably because of that option (it’ll be an invalid option and cause LAME to exit and not convert the WAV to MP3). Just delete the line completely from the script, and you’ll be good to go.

    1. The -tv flag has been available since the 3.98 b4 release in 2007 so I thought it was safe to assume it would be present for most people. I guess it’s always a good idea to check that stuff out though! Especially in the VoIP space, where a lot of old distros are still getting used.

  3. I notice an odd behaviour.

    If you do:
    MP3IMAGE=”–ti $IMAGEPATH”

    $LAME –preset standard \
    … other options …
    “$MP3IMAGE” \
    … etc …

    Lame 3.99 complains about –ti not being a valid option.

    HOWEVER, if you do this:

    $LAME –preset standard \
    … other options …
    –ti “$IMAGEPATH” \
    … etc …

    it works. I can’t explain, but I had to leave the image test out and hardcode the –ti to make it work.

    The funny thing is that lame complains about a valid syntax, –ti /path/to/image, and accepts the same sytax if the –ti switch is oustide the variable.

Comments are closed.