Wednesday 3 February 2016

Extracting Opus from a pcap file into an audible wav

From time to time I need to verify that the audio inside a trace is as expected. Not much in terms of quality, but more often content and duration.

A few years ago I wrote a small program to transform a pcap into a wav file - the codec in use was SILK.

These days I'm dealing with Opus, and I have to say things are greatly simplified, in particular if you consider opus-tools, a set of utilities to handle opus files and traces.

One of those tools, opusrtp, can do live captures and write the interpreted payload into a .opus file.
Still, what I needed was to achieve the same result but from a pcap already existing, i.e. "offline".

So I come up with a small - quite shamlessly copy&pasted - patch to opusrtc, which is now in this fork.
Once you have a pcap with an RTP stream with opus (say in input.pcap) you can retrieve the .opus equivalent (in rtpdump.opus) with:

./opusrtp --extract input.pcap

Then you can generate an audible wav file with:

./opusdec --rate 8000 rtpdump.opus output.wav

Happy decoding.

19 comments:

  1. Thanks Giacomo

    I found this tool very useful!

    In order to get it to work for me I had to make a couple of fixes. I was using a Linux cooked capture pcap file so I did not have the standard length ethernet packet header in the PCAP file. I worked around this by setting
    #define ETH_HEADER_LEN 20
    #define ETH_FILE_HEADER_LEN 20
    in opusrtp.c

    OPUS has a dynamically allocated payload type so the payload type can be between 96-127. Your code had a hard-coded value for the Opus payload type so I had to change this to get the decoding to work for me. To workaround this I just set
    #define OPUS_PAYLOAD_TYPE 117
    #define OPUS_FILE_PAYLOAD_TYPE 117

    ReplyDelete
  2. Thanks for your comment, and I'm glad you found that work useful.
    There are indeed a couple of hardcoded values, which possibly can be either managed as input arguments for the binary, or extracted somehow from the original pcap in a more dynamic fashion.

    ReplyDelete
  3. Hi Giacomo,

    thank you for your post, I'm using it. I just add an input argument to set the payload type. I use the binary in a bash script in conjunction with tshark. Tshark allows me to inspect the pcap file, extracting rtp infos from sdp messages if SIP signaling is present in pcap, and filtering opus packets before pass to opusrtp.

    Thanks a lot!

    ReplyDelete
  4. Good to hear it. Happy decoding ;)
    Any improvement you may want to suggest, please feel free to raise a Pull Request.

    ReplyDelete
  5. Thanks Giacomo for sharing this
    I m facing problems in running opusrtp

    When i ran the below command as you suggested
    ./opusrtp --extract input.pcap

    I got the below error
    Timestamp: 1466490413:383288
    eth 0x0800 00:07:7d:67:e1:bf -> 54:ee:75:65:3b:6a
    unhandled ip version 0
    error parsing ip header
    Got 127 byte packet (127 bytes captured)

    Though i am using ip version 4, it is displaying as version 0

    ReplyDelete
  6. Hi praveen,
    please take into account that I've just hardcoded the payload type:

    #define OPUS_FILE_PAYLOAD_TYPE 96

    and header lenght:

    #define ETH_FILE_HEADER_LEN 16

    You should in particular check the payload type. It would be great to make it dynamic or pass it as command argument.

    ReplyDelete
  7. Hello!

    Thank you for your code.
    Please help me to understand where is the problem?

    root@ip-10-23-254-74:/home/ubuntu# ./opusrtp --extract opus.pcap
    .....
    Got 120 byte packet (120 bytes captured)
    skipping packet: unrecognized linktype 12
    Got 146 byte packet (146 bytes captured)
    skipping packet: unrecognized linktype 12
    ...

    BR
    Denys

    ReplyDelete
    Replies
    1. I think this could be due to multiple streams in the packet capture, filter only one stream and then run with opusrto and hope it works , let me know if it works

      Thanks
      Praveen

      Delete
  8. Hi Denys, please upload your opus.pcap somewhere and let me know when I can download it. So I can take a look.
    Cheers,
    Giacomo

    ReplyDelete
  9. Hey!

    I have uploaded file to Google:
    https://drive.google.com/file/d/0B33gE9ddn6_4a0ltTVpRdG82S0U/view?usp=sharing

    This trace was from rtpengine:
    https://github.com/sipwise/rtpengine

    But as I see now eth header is empty, maybe that is the reason.

    Thank you for the help!

    BR,
    Denys

    ReplyDelete
  10. Hi Giacomo,

    I'm not yet able to test the script. I'm having some issues compiling the code ( https://github.com/gcp/opus-tools ) on Ubuntu Linux.

    I was wondering if you could provide me a quick step to follow to do the compilation, I usually get away with make install, but it's not working this time.

    Thanks

    ReplyDelete
  11. Hi Giacomo,

    I'm not yet able to test the script. I'm having issues while trying to compile the script (https://github.com/gcp/opus-tools )

    I usually get away with "make install" but it's not working this time. I was wondering if you could provide a quick info I can follow to compile the script.

    Thanks

    ReplyDelete
  12. Hi, thanks for your comment. I've never used that repo; instead I was referring to https://github.com/xiph/opus-tools

    In general though, I'd expect you to:

    ./autogen.sh
    ./configure --with-opus-includes=/usr/local/include/opus --without-flac
    make

    You don't even need 'make install' as long as you identify the location of opusrtp and opusdec binaries. Also please note that you need opus-dev installed.

    Good luck.

    ReplyDelete
  13. Hi Giacomo,

    When I run the command:
    ./opusrtp --extract input.pcap
    pcap support disabled, sorry.

    Could you help me?

    BR,
    Martín.

    ReplyDelete
    Replies
    1. I also encountered this problem, then I found the line 199 in configure.ac, which indicates "AC_DEFINE([HAVE_PCAP], 1, [Define if building with libpcap support])", so I installed the "libpcap" and solved the problem. I hope this solution will help anyone who encountered the same problem.

      Delete
  14. Thanks Giacomo,
    when I proceed as you suggested I get a rtpdump.opus of only 111bytes. Obviously opusrtp is skipping the packets.
    Wireshark suggests : payload type G.711 PCMU
    Anything needs to be adapted in the source code?
    Thx for help

    Got 105 byte packet (105 bytes captured)
    eth 0x0800 01:00:5e:05:06:08 -> b8:27:eb:74:bb:8c
    ipv4 protocol 17 192.168.2.254 -> 234.5.6.8 header 20 bytes
    udp 71 bytes 54840 -> 8000 crc 0xcfc4
    rtp 0x0cf157d0 0 43406 2062153920 v2 ... CC 0 51 bytes
    skipping non-opus packet

    ReplyDelete
    Replies
    1. Hi, to keep it simple I've hardcoded the payload type as 120, see:
      https://github.com/giavac/opus-tools/blob/master/src/opusrtp.c#L59

      #define OPUS_PAYLOAD_TYPE 120

      Check what's used in the actual negotiation (maybe it's 96 instead?). If it's different, change it, re-compile and try again.

      Delete
    2. Ah yes, thank you.
      I just read it in the original blog:
      https://www.giacomovacca.com/2017/01/analysing-opus-media-from-network-traces.html

      Delete

Wireshark setting to interpret UDP as RTP automatically

 Before I forget again, a Wireshark setting that can help saving time by trying to interpret any UDP as RTP, if possible: Analyze --> Ena...