Skip to content

Instantly share code, notes, and snippets.

@jayluxferro
Forked from avimar/pcap2wav
Created May 4, 2019 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jayluxferro/950f52f4fd8f9146020c74b18ef41ab1 to your computer and use it in GitHub Desktop.
Save jayluxferro/950f52f4fd8f9146020c74b18ef41ab1 to your computer and use it in GitHub Desktop.
Convert raw PCAP files into a .wav file
#!/bin/bash
#
# pcap2wav
# Original Author: Michael Collins <msc@freeswitch.org>
#Standard disclaimer: batteries not included, your mileage may vary...
# Updated by Avi Marcus <avi@bestfone.com>
#
# Accepts arg of pcap file w/only 2 RTP streams
# Creates a .<codec> file and a .wav file
# For codecs other than PCMA and PCMU the script calls fs_cli and does a little recording to create the wav file(s)
# Current codec support: g711a/u, GSM, G722, G729
# check for -h -help or --help
if [[ $1 == "-h" || $1 == "-help" || $1 == "--help" || $1 == "" ]]
then
cat <<EOF
pcap2wav is a simple utility to make it easier to extract the audio from a pcap
Dependencies:
apt-get install -y tshark sox
yum install wireshark sox
Usage:
pcap2wav [opts] filename.pcap [target filename]
Script attempts to create a few files: a .<codec> file and a .wav file for each RTP stream
It requires Tshark to be installed on the system. If a codec other than PCMA or PCMU
is used then the script will attempt to use fs_cli to decode and create a wav.
Supported codecs:
PCMU (G711 ulaw)
PCMA (G711 Alaw)
GSM
G722 (requires fs_encode)
G729 (requres fs_encode with mod_com_g729)
Supported options:
-z Perform "clean and zip" - After converting to wav files the program will "clean up"
by putting the wav files into a .tgz file and then removing
the .wav and .<codec> files from the disk.
EOF
exit
fi
if [[ $1 == "-z" ]]
then
CLEAN=true
CAPFILE=$2
TARGETFILE=$3
else
CLEAN=false
CAPFILE=$1
TARGETFILE=$2
fi
LOGDIR=/var/log
TSHARK=`which tshark`
SOX=`which sox`
FSENCODE=`which fs_encode`
if [[ $TSHARK == "" ]]
then
echo "Tshark not found. Please install Tshark and then re-run this script"
exit
fi
if [[ $SOX == "" ]]
then
echo "Sox not found. Please install Sox and then re-run this script"
exit
fi
# Make sure pcap exists
if [ -f $CAPFILE ]
then
echo "Found $CAPFILE, working..."
else
echo "$CAPFILE not found, exiting."
exit
fi
# Set target file names; default is "pcap2wav.<codec>" and "pcap2wav.wav"
if [[ $TARGETFILE == "" ]]
then
TARGETFILE="/tmp/pcap2wav"
else
echo "Using $TARGETFILE"
fi
echo "Checking $CAPFILE for RTP streams..."
# Locate RTP streams, put into temp file
tshark -n -r $CAPFILE -Y rtp -T fields -e rtp.ssrc -e udp.dstport -Eseparator=, | sort -u > /tmp/pcap2wav.tmp
# Count the RTP streams
num_streams=`grep -c "" /tmp/pcap2wav.tmp`
streams=( $(cat /tmp/pcap2wav.tmp) )
#Extract stream ssrc and port
for item in `seq 1 $num_streams`; do
index=$((item-1))
ssrc[$item]=`echo ${streams[$index]} | cut -d, -f1`
port[$item]=`echo ${streams[$index]} | cut -d, -f2`
done
payload_type=`tshark -n -r $CAPFILE -T fields -e rtp.p_type | grep -P '\d+' | head -n 1`
case $payload_type in
0) codec='PCMU'
for item in `seq 1 $num_streams`; do
convert[$item]="$SOX -t ul -r 8000 -c 1 ${TARGETFILE}_$item.$codec ${TARGETFILE}_$item.wav"
done
;;
3) codec='GSM'
for item in `seq 1 $num_streams`; do
convert[$item]="$SOX -t gsm -r 8000 -c 1 ${TARGETFILE}_$item.$codec ${TARGETFILE}_$item.wav"
done
;;
8) codec='PCMA'
for item in `seq 1 $num_streams`; do
convert[$item]="$SOX -t al -r 8000 -c 1 ${TARGETFILE}_$item.$codec ${TARGETFILE}_$item.wav"
done
;;
9) codec='G722'
for item in `seq 1 $num_streams`; do
convert[$item]="$FSENCODE ${TARGETFILE}_$item.$codec ${TARGETFILE}_$item.wav"
done
;;
18) codec='G729'
for item in `seq 1 $num_streams`; do
convert[$item]="$FSENCODE -l mod_com_g729 ${TARGETFILE}_$item.$codec ${TARGETFILE}_$item.wav"
done
;;
esac
if [ -z "$codec" ]; then
echo "Unable to determine codec from payload type: $payload_type"
exit
fi
echo "Target files to create:"
for item in `seq 1 $num_streams`; do
echo "${TARGETFILE}_$item.$codec and ${TARGETFILE}_$item.wav"
done
echo
for item in `seq 1 $num_streams`; do
echo "Stream $item ssrc / port: ${ssrc[$item]} / ${port[$item]}"
done
echo
for item in `seq 1 $num_streams`; do
echo "Extracting payloads $item from ${ssrc[$item]}..."
tshark -n -r $CAPFILE -Y "rtp.ssrc == ${ssrc[$item]}" -T fields -e rtp.payload > /tmp/pcap2wav.payloads${item} 2> /dev/null
for payload in `cat /tmp/pcap2wav.payloads${item}`;do IFS=:;for byte in $payload; do printf "\\x$byte" >> ${TARGETFILE}_$item.$codec; done; done
unset IFS
command="${convert[$item]}"
$command
done
# If two streams then assume they're a pair and combine them nicely
if [[ $num_streams == "2" ]]
then
echo "Combining 2 streams into a single wav file for convenience"
# Find shorter recording, calc time diff in samples
samples1=`soxi -s ${TARGETFILE}_1.wav`
samples2=`soxi -s ${TARGETFILE}_2.wav`
if [[ $samples1 -gt $samples2 ]]
then
longer="${TARGETFILE}_1.wav"
shorter="${TARGETFILE}_2.wav"
delay=`expr $samples1 - $samples2`
else
longer="${TARGETFILE}_2.wav"
shorter="${TARGETFILE}_1.wav"
delay=`expr $samples2 - $samples1`
fi
pad="${delay}s"
command="$SOX $shorter ${TARGETFILE}_tmp.wav pad $pad 0s"
$command
# Create "combined" file, padding beginning with silence
command="$SOX -m ${TARGETFILE}_tmp.wav $longer ${TARGETFILE}_mixed.wav"
$command
rm -fr ${TARGETFILE}_tmp.wav
fi
if [[ $CLEAN == "true" ]]
then
echo "Clean option"
ZIPFILE=${TARGETFILE}.tgz
rm -fr $ZIPFILE
/bin/tar czf $ZIPFILE ${TARGETFILE}*wav > /dev/null 2>& 1
for item in `seq 1 $num_streams`; do
rm -fr ${TARGETFILE}_$item.*
done
rm -fr $TARGETFILE.tmp
else
echo "No clean option specified - leaving .<codec> and .wav files on system."
fi
echo
echo "Operation complete"
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment