apk update \
&& apk add git cmake g++ cmake make curl-dev alsa-lib-dev \
&& mkdir /git && cd /git && git clone https://github.com/jchavanton/voip_patrol.git \
&& cd voip_patrol && git checkout master \
&& git submodule update --init \
&& cp include/config_site.h pjproject/pjlib/include/pj/config_site.h \
&& cd pjproject && ./configure --disable-libwebrtc && make dep && make && make install \
&& cd .. && cmake CMakeLists.txt && mak
apt-get install build-essential libcurl4-openssl-dev cmake pkg-config libasound2-dev
TLS
apt-get install libssl-dev
git clone https://github.com/jchavanton/voip_patrol.git
cd voip_patrol && git submodule update --init
cp include/config_site.h pjproject/pjlib/include/pj/config_site.h # increase the max amount of account and calls
cd pjproject && ./configure --disable-libwebrtc
make dep && make && make install
cd ..
cmake CMakeLists.txt
make
./voip_patrol
-v --version voip_patrol version
--log-level-file <0-10> file log level
--log-level-console <0-10> console log level
-p --port <5060> local port
-c,--conf <conf.xml> XML scenario file
-l,--log <logfilename> voip_patrol log file name
-t, timer_ms <ms> pjsua timer_d for transaction default to 32s
-o,--output <result.json> json result file name
--tls-calist <path/file_name> TLS CA list (pem format)
--tls-privkey <path/file_name> TLS private key (pem format)
--tls-cert <path/file_name> TLS certificate (pem format)
--tls-verify-server TLS verify server certificate
--tls-verify-client TLS verify client certificate
--rewrite-ack-transport WIP first use case of rewriting messages before they are sent
--graceful-shutdown Wait a few seconds when shuting down
--tcp / --udp Only listen to TCP/UDP
<config>
<actions>
<action type="call" label="us-east-va"
transport="tls"
expected_cause_code="200"
caller="15147371787@noreply.com"
callee="12012665228@target.com"
to_uri="+12012665228@target.com"
max_duration="20" hangup="16"
username="VP_ENV_USERNAME"
password="VP_ENV_PASSWORD"
realm="target.com"
rtp_stats="true"
>
<x-header name="X-Foo" value="Bar"/>
</action>
<!-- note: param value starting with VP_ENV_ will be replaced by environment variables -->
<!-- note: rtp_stats will include RTP transmission statistics -->
<!-- note: x-header tag inside an action will append an header -->
<action type="wait" complete="true"/>
</actions>
</config>
{
"2": {
"label": "us-east-va",
"start": "17-07-2018 00:00:05",
"end": "17-07-2018 00:00:24",
"action": "call",
"from": "15147371787",
"to": "12012665228",
"result": "PASS",
"expected_cause_code": 200,
"cause_code": 200,
"reason": "Normal call clearing",
"callid": "7iYDFukJr-9BOLOmWg.7fZyHZeZUAwao",
"transport": "TLS",
"peer_socket": "34.226.136.32:5061",
"duration": 16,
"expected_duration": 0,
"max_duration": 20,
"hangup_duration": 16,
"rtp_stats_0": {
"rtt": 0,
"remote_rtp_socket": "10.250.7.88:4028",
"codec_name": "PCMU",
"clock_rate": "8000",
"Tx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 816,
"kbytes": 127,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
},
"Rx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 813,
"kbytes": 127,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
}
}
}
}
./voip_patrol \
--port 5060 \ # TLS port 5061 +1
--conf "xml/tls_server.xml" \
--tls-calist "tls/ca_list.pem" \
--tls-privkey "tls/key.pem" \
--tls-cert "tls/certificate.pem" \
--tls-verify-server \
<config>
<actions>
<!-- note: default is the "catch all" account,
else account as to match called number -->
<action type="accept"
account="default"
hangup="5"
play_dtmf="0123456789#*"
play="voice_ref_files/f.wav"
code="200" reason="YES"
ring_duration="5"
/>
<!-- DTMF will be sent using RFC2833 -->
<!-- note: wait for new incoming calls
forever and generate test results -->
<action type="wait" ms="-1"/>
</actions>
</config>
<config>
<actions>
<action type="accept"
account="default"
hangup="5"
code="200" reason="OK"
>
<check-header name="Min-SE"/>
<check-header name="X-Foo" value="Bar"/>
</action>
<action type="wait" ms="-1"/>
</actions>
</config>
<config>
<actions>
<action type="accept"
account="default"
hangup="5"
code="200" reason="OK"
>
<check-message method="INVITE" regex="m=audio(.*)RTP/AVP 0 8.*"/>
<!-- searching for pcmu pcma in the SDP -->
</action>
<action type="wait" ms="-1"/>
</actions>
</config>
Scenario execution is sequential and non-blocking. We can use “wait” command with previously set “wait_until” params to control parallel execution.
Call States
NULL : Before INVITE is sent or received
CALLING : After INVITE is sent
INCOMING : After INVITE is received.
EARLY : After response with To tag.
CONNECTING : After 2xx is sent/received.
CONFIRMED : After ACK is sent/received.
DISCONNECTED
<config>
<actions>
<action type="call" label="call#1"
transport="udp"
wait_until="CONFIRMED"
expected_cause_code="200"
caller="15148888888@noreply.com"
callee="12011111111@target.com"
/>
<!-- note: will wait until all tests pass wait_until state -->
<action type="wait"/>
<action type="call" label="call#2"
transport="udp"
wait_until="CONFIRMED"
expected_cause_code="200"
caller="15147777777@noreply.com"
callee="12012222222@target.com"
/>
<action type="wait" complete="true"/>
</actions>
</config>
<config>
<actions>
<!-- note: proxy param to send to a proxy -->
<action type="register" label="register target.com"
transport="udp"
account="VP_ENV_USERNAME"
username="VP_ENV_USERNAME"
password="VP_ENV_PASSWORD"
proxy="172.16.7.1"
realm="target.com"
registrar="target.com"
expected_cause_code="200"
/>
<action type="wait" complete="true"/>
</actions>
</config>
<config>
<action>
<action type="codec" disable="all"/>
<action type="codec" enable="pcma" priority="250"/>
<action type="codec" enable="pcmu" priority="248"/>
<!-- call that will last 12 seconds and re-invite every 2 seconds -->
<action type="call"
wait_until="CONFIRMED"
expected_cause_code="200"
caller="16364990640@125.22.198.115"
callee="12349099229@sip.mydomain.com"
max_duration="55" hangup="12"
username="65454659288" password="adaadzWidD7T"
realm="sip.mydomain.com"
re_invite_interval="2"
rtp_stats="true"
/>
<action type="wait"/> <!-- this will wait until the call is confirmed -->
<action type="codec" disable="pcma"/>
<!-- re-invite will now use pcmu forcing a new session -->
<action type="wait" ms="3000"/> <!-- this will wait 3 seconds -->
<action type="codec" enable="pcma" priority="250"/>
<!-- re-invite will now use pcma forcing a new session -->
<action type="wait" complete="true"> <!-- Wait until the calls are disconnected -->
<actions/>
<config/>
{
"rtp_stats_0": {
"rtt": 0,
"remote_rtp_socket": "10.250.7.88:4028",
"codec_name": "PCMA",
"clock_rate": "8000",
"Tx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 105,
"kbytes": 16,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
},
"Rx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 104,
"kbytes": 16,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
}
},
"rtp_stats_1": {
"rtt": 0,
"remote_rtp_socket": "10.250.7.89:40230",
"codec_name": "PCMU",
"clock_rate": "8000",
"Tx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 501,
"kbytes": 78,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
},
"Rx": {
"jitter_avg": 0,
"jitter_max": 0,
"pkt": 501,
"kbytes": 78,
"loss": 0,
"discard": 0,
"mos_lq": 4.5
}
}
}
<config>
<actions>
<action type="alert"
email="jchavanton+vp@gmail.com"
email_from="test@voip-patrol.org"
smtp_host="smtp://gmail-smtp-in.l.google.com:25"
/>
<!-- add more test actions here ... -->
<action type="wait" complete="true"/>
</actions>
</config>
<<<<<<< HEAD
<config>
<actions>
<action type="accept" label="CALLEE recieves call and blind transfer"
account="VP_ENV_CALLEE_USERNAME"
wait_until="DISCONNECTED"
play="../voice_ref_files/reference_8000.wav"
code="200" reason="OK"
ring_duration="5"
rtp_stats
/>
<!-- note: call ends once transfer is complete -->
<action type="transfer" blind to_uri="VPN_ENV_TRANSFER_TARGET@VPN_ENV_PROXY"/>
</action>
</config>
<config>
<actions>
<!-- note: default is the "catch all" account,
else account as to match called number -->
<action type="accept" label="CALLEE recieves call and blind transfer"
account="VP_ENV_CALLEE_USERNAME"
wait_until="DISCONNECTED"
play="../voice_ref_files/reference_8000.wav"
code="200" reason="OK"
ring_duration="5"
rtp_stats
/>
<!-- note: attended_transfer inherit variables from initial call -->
<action type="transfer" attended to_uri="12012665228@target.com"/>
</actions>
</config>
voip_patrol.env
:
VP_ENV_DOMAIN=sip.example.com
VP_ENV_PROXY=192.168.0.1:5060
VP_ENV_CALLEE_EXTENSION=1000
VP_ENV_CALLEE_USERNAME=1000
VP_ENV_CALLEE_PASSWORD=password
VP_ENV_TRANSFER_TARGET=15557776666
export $(xargs <voip_patrol.env)
=======
f1a7b646e10d1df447b8bf04cd28e928c3cc6b58
Name | Type | Description |
---|---|---|
ringing_duration | int | ringing duration in seconds |
early_media | bool | if "true" 183 with SDP and early media is used |
timer | string | control SIP session timers, possible values are : inactive, optional, required or always |
code | int | SIP cause code to return must be >100 and <700 |
account | string | Account will be used if it matches the user part of an incoming call RURI or "default" will catch all |
response_delay | int | ms delay before reponse is sent, useful to test timeouts and race conditions |
call_count | int | The amount of calls to receive to consider the command completed, default -1 (considered completed) |
transport | string | Force a specific transport for all messages on accepted calls, default to all transport available |
re_invite_interval | int | Interval in seconds at which a re-invite with SDP will be sent |
rtp_stats | bool | if "true" the json report will include a report on RTP transmission |
Name | Type | Description |
---|---|---|
timer | string | control SIP session timers, possible values are : inactive, optional, required or always |
proxy | string | ip/hostname of a proxy where to send the call |
caller | string | From header user@host, only used if from it not specified |
from | string | From header complete ""Display Name" <sip:test at 127.0.0.1>" |
callee | string | request URI user@host (also used in the To header unless to_uri is specified) |
to_uri | string | used@host part of the URI in the To header |
transport | string | force a specific transport <tcp,udp,tls> |
re_invite_interval | int | Interval in seconds at which a re-invite with SDP will be sent |
rtp_stats | bool | if "true" the json report will include a report on RTP transmission |
late_start | bool | if "true" no SDP will be included in the INVITE and will result in a late offer in 200 OK/ACK |
Name | Type | Description |
---|---|---|
proxy | string | ip/hostname of a proxy where to send the register |
username | string | authentication username, account name, From/To/Contact header user part |
account | string | if not specified username is used, this is the the account name and From/To/Contact header user part |
registrar | string | SIP UAS handling registration where the messages will be sent |
transport | string | force a specific transport <tcp,udp,tls> |
realm | string | realm use for authentication |
unregister | bool | unregister the account <usename@registrar;transport=x> |
Name | Type | Description |
---|---|---|
complete | bool | if "true" wait for all the test to complete (or reach their wait_until state) before executing next action or disconnecting calls and exiting, needed in most cases |
ms | int | the amount of milliseconds to wait before executing next action or disconnecting calls and exiting, if -1 wait forever |
<config>
<actions>
<action type="codec" disable="all"/>
<action type="codec" enable="pcmu" priority="250"/>
<!-- more actions ... -->
<action type="wait" complete/>
</actions>
</config>
Name | Type | Description |
---|---|---|
priority | int | 0-255, where zero means to disable the codec |
enable | string | Codec payload type ID, ex. "g722", "pcma", "opus" or "all" |
disable | string | Codec payload type ID, ex. "g722", "pcma", "opus" or "all" |
Any value starting with VP_ENV
will be replaced by the envrironment variable of the same name.
Example : username="VP_ENV_USERNAME"
export VP_ENV_PASSWORD=????????
export VP_ENV_USERNAME=username
voip_patrol/docker$ tree
.
├── build.sh # docker build command example
├── Dockerfile # docker build file for Linux Alpine
└── voip_patrol.sh # docker run example starting
PJSUA2 : A C++ High Level Softphone API : built on top of PJSIP and PJMEDIA http://www.pjsip.org http://www.pjsip.org/docs/book-latest/PJSUA2Doc.pdf
P.862 : Perceptual evaluation of speech quality (PESQ): An objective method for end-to-end speech quality assessment of narrow-band telephone networks and speech codecs http://www.itu.int/rec/T-REC-P.862
./run_pesq +16000 voice_files/reference.wav voice_files/recording.wav