Thursday, March 30, 2023

Peer-to-peer voice over IP call with pjsua

I was recently playing around with some voice over IP (VoIP) applications. SIP is a beast of a complex protocol, and I found surprisingly little good simple information on the web.

I found the pjsua CLI app to be the least bad SIP client that works on Linux. Unfortunately a prebuilt version isn't available in Ubuntu's repos as of writing. Luckily, it's pretty easy to compile pjsua:

# A few deps off the top of my head, but your configure run may reveal you need more...
sudo apt install build-essential libasound2-dev libssl-dev

git clone --depth 1 --branch 2.13 https://github.com/pjsip/pjproject.git
cd pjproject
./configure
make dep -j8
make -j8

# Copy the binary to a convenient location of your choice.
cp pjsip-apps/bin/pjsua-x86_64-unknown-linux-gnu ~/bin/pjsua

For fun, I wanted to make a secure peer-to-peer call between two machines, without any external registration server involved. Here's how I finally managed to do so:

# Listen for peer-to-peer calls on local ports UDP 5060, TCP 5060, TLS 5061.
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=server" -x509 -days 3650 -out server.crt
pjsua \
  --use-tls \
  --tls-ca-file=server.crt \
  --tls-cert-file=server.crt \
  --tls-privkey-file=server.key \
  --use-srtp=2

# Usage within the CLI app:
    # "Half-answer" call (let the other side know that it's ringing "beep... beep...").
    a
    180

    # Answer call (can be either done directly, or after a 180).
    a
    200

    # Hang up.
    h

    # Show main menu at any time.
    <enter>

    # Dump status.
    d

    # Outgoing call to SIP address.
    m
    sip:1234@sip.example.com


# Connect peer-to-peer call with SIP meta data secure via TLS, and voice RTP stream secure via SRTP.
pjsua \
  --use-tls \
  --use-srtp=0 \
  --id sip:a \
  --outbound="sips:192.168.1.123:5061;transport=tls" \
  sip:b

Some key parameters worth noting are:

  • Enable support for TLS in the process. Without this you can neither initiate outgoing SIP over TLS connections, nor receive incomming SIP over TLS connection:
    --use-tls
  • Secure the actual audio stream via SRTP (0=off, 1=optional, 2=required):
    --use-srtp=2
  • For playing around in Wireshark use the simplest possible codec:
    --dis-codec="*" --add-codec=pcm

If you are not trying to do a peer-to-peer call, but want to connecto to an actual SIP provider such as antisip.com, then you are probably looking for something like the following:

pjsua \
  --use-tls \
  --use-srtp=2 \
  --id sip:somebody@sip.antisip.com \
  --registrar "sip:sip.antisip.com:9091;transport=tls" \
  --realm sip.antisip.com \
  --username somebody \
  --password somepassword

# See "Usage within the CLI app" above.