Skip to content

Compared with PJSIP

Same Asterisk, same captures, one after the other.

Sipral's headless agent and pjsua, PJSIP's own client, through the same scenarios: memory, CPU, the INVITE on the wire, a moved address, registration and calls, impaired links. Every time read off a packet capture, memory and CPU measured the same way for both.

The results

  • About 72 KB per call. Ten thousand concurrent calls with audio both ways, held in one process, set up at 499 a second.
  • Under a quarter of pjsua's memory. Registered and idle, 2.8 MB of private memory against 12.7 MB; with four calls up, 3.1 MB against 16.8 MB.
  • Under an eighth of the CPU. Four calls up: 2.3 % of a core against 20.15 %.
  • A smaller INVITE, never fragmented. 869 bytes against 1373; a request past 1300 bytes goes over TCP, as RFC 3261 §18.1.1 requires.
  • A call that follows its own address. Re-registered and re-offered from a new network with nobody telling it to.
Sipral pjsua 2.17 lower is better
  • Private memory, registered and idle

    2.8 MB
    12.7 MB
  • Private memory, four calls up

    3.1 MB
    16.8 MB
  • CPU, four calls up, share of one core

    2.3 %
    20.15 %
  • First INVITE on the wire, no ICE

    869 bytes
    1373 bytes

How this was measured

Ten thousand calls in one process

Two processes on one machine, every call G.711 over a UDP socket of its own with a tone both ways, placed at 500 a second and held sixty seconds. About 72 KB of memory and a thousandth of a core per call carrying audio, with more than half of the signalling thread's time still to spare at ten thousand calls.

This end, over the hold5 000 calls10 000 calls
Calls up 5 000 10 000
Setup rate 500 a second 499 a second
Setup, INVITE to 2xx: p50, p90 2.6 ms, 6.3 ms 7.5 ms, 95.6 ms
Processor 5.32 cores 8.48 cores
Resident memory, peak 363 MB 718 MB

How this was measured

Memory and CPU

Per call above idle, Sipral used 0.41 % of a core at four calls and 0.28 % at a hundred, and its memory grew by about 76 kB a call from ten to a hundred. The private column is the one to compare: it leaves out shared-library pages.

Calls up Sipral RSS / private Sipral CPU pjsua RSS / private pjsua CPU
idle 4.6 MB / 2.8 MB 0.65 % 13.3 MB / 12.7 MB 0.65 %
1 4.7 MB / 2.9 MB 1.40 % 14.2 MB / 13.7 MB 6.55 %
4 4.9 MB / 3.1 MB 2.30 % 17.3 MB / 16.8 MB 20.15 %
10 5.4 MB / 3.5 MB 4.35 % 4 up of 10: 17.4 MB / 16.9 MB 22.70 %
100 12.2 MB / 10.3 MB 28.65 % 4 up of 100: 17.3 MB / 16.7 MB 20.95 %

How this was measured

The INVITE on the wire

Sipral offers its default catalogue (Opus, G.722, G.711, telephone-event) and one ICE candidate per stream, with RTCP multiplexed on the RTP port. RFC 3261 §18.1.1 sends a request over 1300 bytes over a congestion-controlled transport when the path MTU is unknown; Sipral's core holds to that and asks the application for TCP, so its INVITE is never split into IP fragments that a NAT or firewall may drop.

OfferSipralpjsua
Every default codec, no ICE 869 bytes 1373 bytes
Every default codec, ICE 1034 bytes, 1 candidate; with credentials 1333 bytes, not sent over UDP 1570 bytes, 2 candidates, sent over UDP as two IP fragments; call set up in 6.1 ms
G.711 alone, ICE 954 bytes, 1 candidate; call set up in 9.2 ms 1164 bytes, 2 candidates; call set up in 4.1 ms

How this was measured

A moved address

One call up, then the client taken off the network and put back at a different address, as a laptop or a phone changes networks. Sipral notices the move itself: it binds its signalling to the new address, re-registers and offers every call again from there.

From the moment the new address existed Sipral pjsua, left alone pjsua, told
First SIP from the new address 394 ms, a REGISTER never 123 ms, a re-INVITE
First audio sent from there 3 ms 17 ms 1 ms
First audio received there again 417 ms never 126 ms
Call still up after 20 s yes yes, one way yes

How this was measured

Registering and calling

From the first request to the 200 that accepted it, each client challenged once by Asterisk.

MeasuredSipralpjsua
Registration, first REGISTER to its 200 7.7 ms 10.3 ms
Outgoing call to Asterisk echo, first INVITE to its 200 10.8 ms 4.6 ms
Incoming call from Asterisk, INVITE to the client 200 9.5 ms 4.2 ms
First INVITE, no ICE, size on the wire 869 bytes 1373 bytes

How this was measured

A bad link

One call held 30 seconds over each impairment profile, applied both ways with tc netem. Each end's view of the audio it received, every row rated by the same E-model (ITU-T G.107, G.711 with loss concealment). Under the same loss, Asterisk rated what the two clients sent alike.

Profile Measured at Received Loss Jitter RTT R MOS
lossy Asterisk, from Sipral 1402 7.09 % 9.0 ms 73 ms 70.5 3.62
lossy Sipral 1395 8.40 % 10.4 ms 103 ms 67.2 3.46
lossy Asterisk, from pjsua 1410 7.18 % 9.0 ms 85 ms 70.1 3.60
lossy pjsua 1.4K 7.2 % 8.9 ms 87 ms 70.1 3.60
mobile Asterisk, from Sipral 1442 4.50 % 35.0 ms 119 ms 75.2 3.83
mobile Sipral 1455 4.34 % 52.6 ms 154 ms 71.6 3.67
mobile Asterisk, from pjsua 1465 3.04 % 22.0 ms 126 ms 79.9 4.02
mobile pjsua 1.5K 3.5 % 18.7 ms 99 ms 79.0 3.99
satellite Asterisk, from Sipral 1521 0.46 % 13.0 ms 505 ms 71.0 3.64
satellite Sipral 1553 0.64 % 15.3 ms 504 ms 69.8 3.59
satellite Asterisk, from pjsua 1550 0.58 % 10.0 ms 488 ms 72.5 3.71
satellite pjsua 1.6K 0.4 % 8.8 ms 485 ms 73.7 3.76
Profilenetem, both directions
lossy delay 40ms 15ms loss gemodel 4% 40% 60% 2% reorder 1% 30%
mobile delay 60ms 30ms distribution normal loss gemodel 2% 40% 60% 1%
satellite delay 250ms 10ms distribution normal loss 0.5%

How this was measured

Methodology

Date
29 September 2026
Host
Debian 13, Linux 6.12.95, 32 cores, x86-64, a virtual machine doing other work at the same time
PBX
Asterisk 22.10.1, one account, G.711 only, one contact at a time
Sipral
The headless agent example, release build, Rust 1.95.0, in debian:trixie-slim
PJSIP
pjsua 2.17 from Alpine 3.24 (package pjsua-2.17-r0), run as shipped
Timing
read off a packet capture taken in each client's own network namespace
Memory, CPU
resident and private memory from smaps_rollup, user plus system time over 20 seconds, the same /proc files for both
Calls
originated by Asterisk to a cadenced tone, G.711 both ways, echoed back
Impairment
tc netem in both directions; every row rated by one reduced ITU-T G.107 E-model
Settings
pjsua run with --max-calls=4, the limit its packaged build was compiled with; the Sipral agent with --invite-burst 200, its scanner guard raised for a PBX that offers a hundred calls within a second
Scale run
Intel Xeon E5-2698 v4 at 2.2 GHz, 32 vCPUs, Debian 13, kernel 6.12; 29 September 2026

The whole comparison is one script in the Sipral source tree, published together with the source, so anyone can run it again and compare their own numbers.

Sipral is built to replace PJSIP in products that cannot take on the GPL: it contains no GPL or LGPL code, and its documentation maps each pjsua concept to its equivalent. For a closed-source product, see licensing.

Ship SIP in a closed app, without the GPL.

One price per company, perpetual for the versions delivered during maintenance, app stores allowed. Ask privately.

Request a quote