Saving Voicemail on a non-Jailbroken iPhone

Nov 24th, 2009 by ericb in Tips & Tricks

A colleague of mine recently asked if I knew of any applications that would allow him to save and backup voicemail off his iPhone. He had found The Missing Sync, but frankly $40 is a bit steep just to save voicemail; he didn't need to do anything else.

A quick search turned up an article describing how to save voicemail from a jailbroken iPhone, but nothing so simple for a non-jailbroken phone. The article did, however, drop a clue: voicemails are stored in AMR format.

iPhone backup files are conveniently all stored in a directory named for the phone's ID in "~/Library/Application Support/MobileSync/Backup/". The files all have a .mddata or .mdinfo extension. Could any of them contain an AMR file? According to the AMR format RFC, plain, single-channel AMR files should start with the ASCII string "#!AMR\n". A simple grep revealed that several files in fact contained the AMR header. As it turns out, Apple has politely stored each voicemail in its own, separate file – no file carving is necessary to extract the voicemail.

It's so simple to find the voicemail in an iPhone backup, it can be done with a bash shell one-liner (credit to Seren in the comments for finding a slightly more compatible "find" syntax):

pushd ~/Library/Application\ Support/MobileSync/Backup ; for I in `find . -name *.mddata -exec grep -la '#\!AMR' {} \;` ; do cp $I $OLDPWD/`basename -s mddata $I`amr ; done ; popd

That'll copy all the voicemail for the current user's iPhone(s) to the current directory, named with a .amr extension. (Both QuickTime and iTunes can play .amr files.) Note that this can take a minute or two – so be patient for at least a couple minutes if it looks like nothing is happening.

For those less familiar with bash, I'll break down the one-liner a bit:

pushd ~/Library/Application\ Support/MobileSync/Backup ; \
for I in `find . -name *.mddata -exec grep -la '#\!AMR' {} \;` ; \
do cp $I $OLDPWD/`basename -s mddata $I`amr ; \
done ; \
popd

1. pushd changes the current directory and stores the previous current directory in the $OLDPWD environment variable. The "Application Support" directory has an unfortunate space in it, which makes it a bit tougher to throw around pathnames using it without getting the escaping just right – I didn't want to bother with it.
2. The find command looks for only those files that end in .mddata to save a small amount of time (there are no voicemails in .mdinfo files) and then passes each to grep. grep is used to look for files with the AMR header; the -la options are used to quit looking through a file after the first match (again, this is for a small speed improvement – the AMR header ends with a newline and must be the first thing in an AMR file, which means grep is able to move on quicker on the few files that match) and to treat files as text.
3. Use basename to strip off the .mddata filename extension so we can make a copy of the .mddata file with a .amr extension.
4. End of loop.
5. popd restores the current directory to the original working directory.

There are tons of different ways of doing the same thing; I tried for a little while to find one that was functionally equivalent (using xargs rather than a for-loop and bash substring manipulation rather than basename, etc.) but would fit in a Twitter update, but alas, I'm not a bash expert, and failed. If you can come up with a shorter one-liner, feel free to leave it in the comments. It needs to be general (it can't assume a specific iPhone ID, for example), and needs to assume a very large number of files in the backup directory (such that "grep '#\!AMR' *" would likely fail due to "*" being too long; that happens to be the case for me). Other than that, have fun.

8 Comments

  • I was having the same trouble, except it wasn't for an amr file. But why not use the "file" command instead? It gave something like ($1 is the argument)

    pushd "$1"
    for i in *mddata; do
    if [[ "`file "$i" |grep -i 'data$' |grep -v -i "image" |wc -l`" -gt 0 ]] ; then
    echo "$i"
    cp $i ../
    fi
    done
    popd

    In my case, I was looking for "data" file types, but not jpeg nor png images, which respond to file by "JPEG data image", so that's why I used a grep -v, to get rid of those files. I don't know if it's more efficient, but I wanted to share this one, in case anyone wanted to find other types of files stored on their iPhones. (Sadly, the files I was looking for were in /var/mobile/Media, which isn't backed up :( )

  • I had some problems with the script, due to the grep section.
    This didn't work:
    grep -la "#\!AMR" {} +
    This did however:
    grep -la '#!AMR' {} \;

    The working version is:

    pushd ~/Library/Application\ Support/MobileSync/Backup ; for I in `find . -name *.mddata -exec grep -la '#!AMR' {} \;` ; do cp $I $OLDPWD/`basename -s mddata $I`amr ; done ; popd

    • The "+" sign ending for the find command works for me (OS X 10.6), and does something slightly different, but the "\;" ending is probably more compatible with various versions of find, so I've updated the original post with your suggestion. Thanks!

  • ok, we need a windows version of this method

  • Justin Smith

    I have been using this little program from Decipher to save my voicemails as mp3s files. I'm on a mac though, so I'm not sure about whether it works for windows or not! ; ) Cheers and hope that might be useful.

    http://decipher-media.com/iphone-tools/

    • Looks like this might be a good choice for folks who are a bit gun-shy at the command-line – at 5 bucks, it's a lot more reasonable than The Missing Sync if all you need is voicemail.

  • [...] make sure to click through to Eric's original article. Thanks for the [...]