Sunday 3 February 2008

Roll your own VoIP Analysis, it's not that hard.

In the previous post, we were trying to debug a problem with our phones. Now, we're in education, and money's tight. IT systems purchasing goes like this:

Technical, management and sales agree on a service and a price. In this instance, it was a fully managed VoIP service, with training for our people, full redundancy, call reporting, the works.

Technical staff go back to work, leaving management and sales to iron out final details.

We end up with some boxes installed, no redundancy, no reporting or training, and call-center monkey support. 'Have you got QOS?'

So we sure as s**t can't afford call quality analysis software.

I'm rolling me own.

The basic Mitel system uses proprietary MiNET protocols to control stuff, but plain G711 over RTP for the audio. Wireshark can split this out and save audio streams, as well as doing jitter/latency analysis, but I needed something less manual.

tshark doesn't do this. But it's possible to script something similar.

######################## analyseCalls.sh ########################
#!/bin/sh
# tpcdump file as argument

## first, identify distinct RTP streams in input
for ff in $(tshark -r $1 "udp.port == 9000" -d "udp.port == 9000,rtp" -T fields -e "rtp.ssrc" 2>/dev/null | sort | uniq | cut -f1); do
## count the number of 'quiet' packets - this is, ahem, 'heuristic'
NSB=$(tshark -r $1 -d "udp.port==9000,rtp" "rtp.ssrc==${ff}" -T pdml 2>/dev/null | grep payload | cut -f10 -d'"' | sed -e 's/[d5][54761032]://g; s/[^:]//g' | wc -c)
NONSILENCE=$(echo "scale = 3; print $NSB / 160" | bc);
## suck out the audio payload
tshark -r $1 -d "udp.port==9000,rtp" "rtp.ssrc==${ff}" -T pdml 2>/dev/null | grep payload | cut -f10 -d'"' | grabAudio.pl > ${ff}.raw
## convert it to WAV
sox -c 1 -r 8000 -L -A -t raw ${ff}.raw ${ff}.wav
## Get a timestamp for the first packet
TD=$(tshark -r $1 -d "udp.port==9000,rtp" "rtp.ssrc==$ff" -tad | head -n1 | cut -f2,3 -d" ")
echo -n "$TD ${ff} $NONSILENCE "
## and do some call analysis
tshark -r $1 -d "udp.port==9000,rtp" "rtp.ssrc==$ff" -td 2>/dev/null | qual.pl;
done | sort -n

######################## grabAudio.pl ########################
#!/usr/bin/perl
## translate the ascii-hex payload from tshark to actual binary data
while(<>) {
$line = $_;
chop $line;
foreach $char ( split(/:/,$line)) {
print chr(hex($char));
}
}

######################## qual.pl #######################
#!/usr/bin/perl

while (<>) {
$line = $_;
## strip out unwanted spaces
$line =~ s/ / /g;
$line =~ s/^ //;
## separate the fields
( $pkt, $delta, $sip, $dummy, $dip, $dummy, $dummy, $dummy, $dummy, $dummy, $dummy, $ssrc, $dummy, $seq, $dummy, $time ) = split(/[ ,=]+/, $line);
## save the inter-packet arrival time in an array
push(@deltas,$delta);
## and keep the final RTP sequence number
$lastseq = $seq;
}
## compare number of packets seen to sequence number for loss..
$pkts = @deltas - 1;
$loss = $lastseq - $pkts;

## get the mean inter-packet gap
foreach $delta ( @deltas ) {
$dsum += $delta;
}
$dmean = $dsum / $pkts;

## and calculate the standard deviation for the whole set
## ( not sure if this is the right calculation )
foreach $delta ( @deltas ) {
$dsquared += ( $delta - $dmean ) * ( $delta - $dmean );
}
$jitter = sqrt($dsquared / $pkts);

print "$sip $dip $pkts $loss $dmean $jitter\n";

Now I'm not claiming that this is great. It'll do me for free, and it will make my VoIP guy a bit happier. Especially when I roll it into a nice mini-itx box that he can pop under a problem handset for a week, with a nice web interface, call playback, etc.

The point is, it ain't that hard.

2 comments:

Anonymous said...

Hi,
this sounds interesting.
Which version of thshark did you use for your scripts?

Kind regards.
SM

mawhin said...

Hi, er, SM.

It's the version included in ubuntu 7.10 server. 0.99.6rel-3ubuntu0.1.

earlier versions are missing important cmdline options - I think it's the -t fields stuff.

Let me know if you make something of this, please.

Mart