Kurz-Howto: Anrufbeantworter-Nachrichten in Asterisk als MP3 versenden

(2010-07-25)

Auf meiner Asterisk-Telefonanlage läuft natürlich auch ein Anrufbeantworter. Damit ich diesen nicht immer nur abfragen kann, wenn ich gerade einen E-Mail-Client vor mir habe (sup unterstützt leider noch keine verteilten Setups), sondern auch, wenn ich gerade nur mein Telefon greifbar habe, habe ich meine Konfiguration etwas geändert.

Zunächst möchte ich natürlich die Nachricht sowohl in meinem eigentlichen E-Mail-Client archiviert haben als auch auf mein Telefon (für das ich ein separates Konto auf meinem Mailserver habe) bekommen. Normalerweise benutze ich als mailcmd in der /etc/asterisk/voicemail.conf direkt /usr/lib/dovecot/deliver -d michael -m daemons. Damit die E-Mails an beide Nutzer ausgeliefert werden richtet man sich ein kleines Script ein, welches man im Asterisk als mailcmd konfiguriert:

#!/bin/sh

TMPFILE=$(mktemp)
cat > $TMPFILE
cat $TMPFILE | /usr/lib/dovecot/deliver -d michael -m daemons
cat $TMPFILE | /usr/lib/dovecot/deliver -d pbx -m INBOX
rm $TMPFILE

Die E-Mails werden nun auf meinem Telefon (Nokia N900) passend angezeigt und auch die automatische Benachrichtigung bei neuen Mails funktioniert. Einzig mit dem Attachment (das eigentlich wichtige neben der Rufnummer des Anrufers und der Uhrzeit) kann der mitgelieferte Mediaplayer nichts anfangen – kein Wunder, denn Asterisk kodiert standardmäßig mit dem gsm-codec (abspielen kann man diese Dateien zum Beispiel mit MPlayer). Wenn man sich die passende Dokumentation zur format-Einstellung von asterisk ansieht, stellt man fest, dass das Alternativformat unkomprimiertes WAV ist, was bei einigen Nachrichten schnell in den Megabyte-Bereich wächst. Sofern man nur über UMTS online ist, will man große Datenmengen natürlich vermeiden, weswegen eine Umkodierung nach MP3 naheliegt. Das erledige ich mit folgendem Script:

#!/usr/bin/env perl
# vim:ts=4:sw=4:expandtab
# © 2010 Michael Stapelberg, public domain

use strict;
use warnings;
use MIME::Parser;
use IPC::Run qw(run);
use File::Temp qw(tempdir);

# Replaces wav with mp3 and fixes MIME type in headers
sub replace_header {
    my ($head, $field) = @_;

    $_ = $head->get($field);
    s/x-wav/mpeg/ig;
    s/wav/mp3/ig;
    $head->replace($field => $_);
}

# Parse the input file
my $parser = MIME::Parser->new();
$parser->output_under(tempdir(CLEANUP => 1));
my $entity = $parser->parse(\*STDIN) or die "failed";

# Re-encode the audio part
for my $part ($entity->parts) {
    my $body = $part->bodyhandle;
    my $head = $part->head;
    next unless $head->get('Content-Type') =~ /wav/;

    # Feed the attachment's body to ffmpeg(1) and save the MP3 output
    my $mp3;
    my @cmd = qw(ffmpeg -i - -ar 16000 -ab 128000 -f mp3 -);
    run \@cmd, '<', \$body->as_string, '>', \$mp3, '2>', '/dev/null';
    $part->bodyhandle(MIME::Body::Scalar->new($mp3));

    replace_header($head, 'Content-Type');
    replace_header($head, 'Content-Disposition');
}
$entity->print(\*STDOUT);

(Direkter Download: recode-voicemail.pl)

Damit das Script funktioniert muss man unter Debian-Systemen die Pakete libmime-tools-perl, libipc-run-perl und ffmpeg installieren. ffmpeg sollte man sich hierbei entweder aus debian-multimedia installieren oder selbst kompilieren, denn die Version in debian hat keine Unterstützung für den MP3-Codec. Einen Testlauf kann man z.B. folgendermaßen durchführen: ffmpeg -i /var/spool/asterisk/voicemail/default/1/INBOX/msg0001.wav -ar 16000 -ab 128000 -f mp3 /tmp/out.mp3. Anschließend sollte man eine abspielbare MP3-Datei in /tmp/out.mp3 haben, sonst stimmt etwas mit der ffmpeg-Installation nicht.

Das Script zum Re-encodieren kann man nun in das obige Script zum Zustellen der Mail an beide Accounts einbinden:

#!/bin/sh

TMPFILE=$(mktemp)
/etc/asterisk/recode-voicemail.pl > $TMPFILE
cat $TMPFILE | /usr/lib/dovecot/deliver -d michael -m daemons
cat $TMPFILE | /usr/lib/dovecot/deliver -d pbx -m INBOX
rm $TMPFILE