StarTrinity.com

Measuring quality

Sample CallXML Scripts for StarTrinity SIP Tester

The scripts should be copied from this page into SIP Tester -> Outgoing calls simulation -> XML tab, into <callxml></callxml> root element, replacing previous code.

Generation of random outgoing calls

This is a script for stress testing call centers, PBX systems, outbound dialers with SIP Tester. It generates calls with specified prefix, random caller ID (A number) and called ID (B number). Destination SIP URI is localhost:5061, it has to be replaced with actual URI.

<assign var="to" value="sip:calledIdPrefix$rand(1000,9999);@localhost:5061" />
<!-- specify destination SIP URI: prefix with 4 random digits-->

<assign var="from" value="callerIdPrefix$rand(1000,9999);" /> <!-- specify caller ID-->
<log value="calling from $from; to $to;" />
<call value="$to;" callerId="$from;"/> <!-- make a call-->
<on event="answer">
<wait value="1000ms" /> <!-- wait 1000 milliseconds -->
<exit /> <!-- terminate a call -->
</on>

Registering range of IP PBX extensions and making calls between them
<assign var="numberOfExtensions" value="100" /> <!-- 100 extensions totally, you can change this number -->
<if test="$Id; &lt; $numberOfExtensions;">
 <assign var="extensionId" mathvalue="1000 + $Id;" /> <!-- register extensions 1000...1099 -->
 <log value="registering extension $extensionId;..." />
<!-- sending REGISTER, using same password for all extensions. please change the password and server host : SIP port -->
 <register value="sip:$extensionId;@startrinity.com:5070?user=$extensionId;&amp;password=123456" expires="36000" var="status" delayvar="delay" />
 <log value="registered extension $extensionId;. response code = $status;, delay = $delay;ms" />
</if>
<else>
 <assign var="srcExtensionId" mathvalue="1000 + $Id; % ($numberOfExtensions; / 2)" /> <!-- send calls from extension 1000...1049 -->
 <assign var="dstExtensionId" mathvalue="1000 + ($numberOfExtensions; / 2) + $Id; % ($numberOfExtensions; / 2)" /> <!-- send calls to extension 1050...1099 -->
  <log value="making call from extension $srcExtensionId; to $dstExtensionId;" />
<!-- sending INVITE, using same password for all extensions. please change the password and server host : SIP port -->
  <call value="sip:$dstExtensionId;@startrinity.com:5070?user=$srcExtensionId;&amp;password=123456" maxringtime="30s">
  <on event="answer">
   <log value="call from extension $srcExtensionId; to $dstExtensionId; got connected" />
   <playaudio value="music.wav" maxtime="60s" repeat="infinite" />
   <exit />
  </on>
 </call>
</else>

Reading IP PBX extensions, registering and making calls between them
<!-- CSV file format: [user];[password];[destination_user_number_to_make_calls]. example: (100 calls 110, 101 calls 111)
100,123456,110
101,123456,111
please check setting "CsvDelimiter" set to ";" or "," also change CSV file name -->

<readcsv value="c:\startrinity\extensions.csv" repeatCounterVar="csvRepeatCounter" var0="user" var1="password" var2="dst_user" repeat="infinite" />
<log value="read from CSV: user=$user; dst_user=$dst_user; csvRepeatCounter=$csvRepeatCounter;" />
<if test="$csvRepeatCounter; == 0">
 <log value="registering extension $user;..." />
<!-- sending REGISTER, using same server for all extensions. please change the server host : SIP port -->
 <register value="sip:$user;@startrinity.com:5070?user=$user;&amp;password=$password;" expires="36000" var="status" delayvar="delay" />
 <log value="registered extension $user;. response code = $status;, delay = $delay;ms" />
</if>
<else>
  <log value="making call from extension $user; to $dst_user;" />
<!-- sending INITE (making call), using same server for all extensions. please change the server host : SIP port -->
  <call value="sip:$dst_user;@startrinity.com:5070?user=$user;&amp;password=$password;" maxringtime="30s">
  <on event="answer">
   <log value="call from extension $user; to $dst_user; got connected" />
   <playaudio value="music.wav" maxtime="60s" repeat="infinite" />
   <exit />
  </on>
 </call>
</else>

Specifying custom SIP headers and SDP attributes

You can add custom SIP headers by setting attribute "headers", also add SDP attributes by setting attribute "sdpAttributes". This could be helpful for testing ED-137 SIP applications.

<!-- for outgoing calls: -->
<call value="sip:111@192.168.1.1" callerId="222"
    headers="Subject=radio|Priority=normal|WG67-Version=radio.01"
    sdpAttributes="R2S-KeepAlivePeriod:200|R2S-KeepAliveMultiplier:10|sigtime:1"
/>
<!-- for incoming calls: -->
<accept headers="WG67-Version=radio.01" sdpAttributes="R2S-KeepAlivePeriod:200|R2S-KeepAliveMultiplier:10|sigtime:1" />

Test IVR menu 1

The script reads caller ID, called ID and DTMF sequence from CSV file, creates a call and sends DTMF digits to destination.

<readcsv value="e:\list.csv" var0="destinationUri" var1="pincode" />
<!-- Read data from CSV file. The CSV file contains 2 columns: SIP URI for call and PIN code. -->
<log value="read next row from CSV and save it into variables: destinationUri = $destinationUri;, pincode=$pincode;" />
<log value="calling (sending INVITE to) $destinationUri;" />
<call maxringtime="10000ms" value="$destinationUri;" />
<on event="answer">
     <log value="destination answered (received 200 OK). making pause = 1 second (waiting for IVR message)" />
     <wait value="1000ms" />
     <log value="sending DTMF digit 1 (press 1 if you are existing customer)" />
     <playdtmf value="1" />
     <wait value="1000ms" />
    <log value="sending DTMF digits $pincode; (enter your pincode)" />
    <playdtmf value="$pincode;" />
    <wait value="3000ms" />

     <block probability="0.5" >
         <log value="50% of calls: sending additional DTMF '3'" />
         <playdtmf value="3" />
         <wait value="10000ms" />
         <log value="aborting call" />
         <exit />
     </block>

     <block probability="0.5" >
         <log value="25% of calls: sending additional DTMF '123'" />
         <playdtmf value="123" />
         <wait value="10000ms" />
         <log value="aborting call" />
         <exit />
     </block>

     <log value="25% of calls: sending additional DTMF '456'" />
     <playdtmf value="456" />
     <wait value="10000ms" />
     <log value="aborting call" />
     <exit />
</on>

Test IVR menu 2

Another script example simulates several DTMF keys and records audio into WAV file. Recording contains both debugging prompts with synthesised speech and audio from tested IVR.

<log value="calling..." />
<call value="sip:1001@192.168.56.1:5061?user=user1&password=pass1" /> <!-- make a call -->
<on event="answer"> <!-- handle 'answer' event (receiving of 200 OK) -->
<log value="answered" />
<recordcall value="100" /> <!-- record mix of RX and TX streams for verification of IVR announcements -->

<!-- we are in top-level menu -->
<wait value="$rand(3,6);s" /> <!-- make a random delay from 3 to 6 seconds -->
<assign var="dtmf" value="$rand(1,2);" /> <!-- declare variable 'dtmf' and set it to random number from 1 to 2 -->
<playdtmf value="$dtmf;" /> <!-- simulate DTMF using the variable -->
<log value="sent DTMF: $dtmf;" /> <!-- report it to log -->
<say voice="Microsoft Anna" value="pressed $dtmf;" /> <!-- report it to WAV file for further checking in recorded file -->
<wait value="$rand(10,20);s" /> <!-- make a random delay from 10 to 20 seconds -->

<block test="$dtmf;=1"> <!-- check if we have sent 1 -->
     <!-- we are in submenu for DTMF=1 -->
     <wait value="$rand(3,6);s" /> <!-- make a random delay from 3 to 6 seconds -->
     <assign var="dtmf" value="$rand(1,6);" /> <!-- set variable 'dtmf' to random number from 1 to 6 -->
     <playdtmf value="$dtmf;" /> <!-- simulate DTMF using the variable -->
     <log value="sent DTMF: $dtmf;" /> <!-- report it to log -->
     <say voice="Microsoft Anna" value="pressed $dtmf;" /> <!-- report it to WAV file for further checking in recorded file -->
     <wait value="$rand(10,20);s" /> <!-- make a random delay from 10 to 20 seconds -->
</block>

<block test="$dtmf;=2">
     <!-- we are in submenu for DTMF=2 -->
     <wait value="$rand(3,6);s" /> <!-- make a random delay from 3 to 6 seconds -->
     <assign var="dtmf" value="$rand(0,9);" /> <!-- set variable 'dtmf' to random number from 0 to 9 -->
     <playdtmf value="$dtmf;" /> <!-- simulate DTMF using the variable -->
     <log value="sent DTMF: $dtmf;" /> <!-- report it to log -->
     <say voice="Microsoft Anna" value="pressed $dtmf;" /> <!-- report it to WAV file for further checking in recorded file -->
     <wait value="$rand(10,20);s" /> <!-- make a random delay from 10 to 20 seconds -->
</block>

<wait value="5s" />
<log value="aborting call" />
<exit />
</on>

Test IVR menu 3 (dead air + recording)

The script makes call to a number, waits for IVR playback. If there is silence (dead air), it sends an alert email (settings MailSender***). Minimal interval between emails is 5 minutes (sending emails is limited to avoid too many emails). All calls are recorded to WAV files. The IVR playback delays are saved to CDR in a custom field

<call maxtime="10s" callerId="9995523212" value="sip:18557771333@207.70.137.4:5060"/>
<on event="answer">
 <recordcall value="100" />
 <waitforsignal signaldelayvar="ivrDelay" maxtime="10s"/>
 <writecdr header="IVR_delay" qualityIsAscending="false" value="$ivrDelay;" numeric="true" />
 <if test="$ivrDelay; &gt; 5000">
  <block minInterval="5m">
   <sendemail value="mailto:destinationemailuser@server.com?subject=IVR timeout: $ivrDelay; milliseconds&body=Timeout in IVR1. called id: $calledId;. caller ID: $callerId;. time now: $time();" />
  </block>
 </if>
 <wait value="2s" />
 <playdtmf value="9" />
 <wait value="5s" />
 <exit/>
</on>

Test audio quality (PESQ MOS) in a conference server

The conference server should be tested by 2 separate instances of SIP Tester. They can run on the same server on different SIP ports ("LocalSIPPort" setting). The first instance simulates call load of about 30 concurrent calls, it plays silence to the conference. The second instance generates pairs of calls, verifies audio signal and measures PESQ MOS. A pair of calls is generated if you set "number of calls to generate at a time" = "2"

<!-- script for 1st instance of sip tester which generates main call load and plays silence to the conference -->
<!-- dial number 123456, send a call to conference server -->
<call value="sip:123456@1.10.10.10:5060" codec="G711A" maxringtime="30s" />
<on event="answer">
  <waitforsignal value="-24dB" /> <!-- when answered, wait for IVR prompt -->
  <playdtmf value="1234#" /> <!-- enter PIN code to enter a conference room -->
  <wait value="60s" /> <!-- don't do anything, play silence during 60 seconds -->
  <exit /> <!-- abort call -->
</on>


<!-- script for 2nd instance of sip tester which plays audio and measures PESQ MOS -->
<!-- dial number 123456, send a call to conference server -->
<call value="sip:123456@1.10.10.10:5060" codec="G711A" maxringtime="30s" />
<on event="answer">
  <waitforsignal value="-24dB" /> <!-- when answered, wait for IVR prompt -->
  <playdtmf value="1234#" /> <!-- enter PIN code to enter a conference room -->
  <wait value="2s" /> <!-- wait for pin code recognition -->
  <playaudio value="speech.wav" dontwait="true" /> <!-- start playing audio to the conference -->

  <verifyaudio reference="speech.wav" maxtime="12s" mosvar="mos" recognizeddelayvar="delay" />
<!-- at the same time start audio verification of signal from another call which goes through conference -->

  <log value="measured PESQ MOS = $mos;, conference audio delay = $delay;ms" />
  <writecdr header="CONFERENCE_MOS" value="$mos;" numeric="true" qualityIsAscending="true" />
  <writecdr header="CONFERENCE_DELAY" value="$delay;" numeric="true" qualityIsAscending="false" />

  <exit /> <!-- abort call -->
</on>

Here is a script to simulate the conference in SIP Tester:

<accept/>
<inputdigits value="music.wav" var="roomNumber" maxsilence="10s" maxdigits="10" />
<log value="entering room number $roomNumber;" />
<conference value="$roomNumber;" />

Test audio quality (PESQ MOS) in a conference server (long-duration calls)

SIP Tester should be configured to make N calls in burst, and to limit number of concurrent calls to N. First call in burst plays audio to the conference, secondary calls listen to audio signal from the conference server and measure audio quality

<!-- dial number 123456, send a call to conference server -->
<call value="sip:123456@192.168.10.1:5060" codec="G711A" maxringtime="30s" />
<on event="answer">
 <log value="call is answered [callNumberInBurst = $callNumberInBurst;]" />
 <assign var="measurementsPerCall" value="20" /> <!-- test call contains multiple serial measurements of audio quality -->
 <if test="$callNumberInBurst; = 0"> <!-- first call in burst: play audio + silence in loop -->
  <wait value="5s" />
  <block repeat="$measurementsPerCall;">
   <log value="playing sound [callNumberInBurst = $callNumberInBurst;]" />
   <playaudio value="speech.wav" />
   <log value="playing silence [callNumberInBurst = $callNumberInBurst;]" />
   <wait value="10s" /><!-- pause needed to complete audio verification - calculate PESQ MOS -->
  </block>
 </if>
 <else> <!-- secondary calls in burst: recognize audio from the 1st call, measure audio quality -->
  <recordcall value="100" /> <!-- record audio into wav for further analysis -->
  <assign var="minMos" value="5" />
  <block repeat="$measurementsPerCall;" var="loopCounter" >
   <log value="waiting for signal [callNumberInBurst = $callNumberInBurst;]" />
   <waitforsignal />
   <log value="recognizing audio [callNumberInBurst = $callNumberInBurst;]" />
   <verifyaudio reference="speech.wav" maxtime="12s" mosvar="mos" recognizeddelayvar="delay" />
   <log value="measured PESQ MOS = $mos;, conference audio delay = $delay;ms [callNumberInBurst = $callNumberInBurst;]" />
   <if test="$loopCounter; != 0">
    <writecdr header="CONFERENCE_measurements_count" value="$loopCounter;" numeric="true" qualityIsAscending="true" />
    <if test="$mos; < $minMos;">
     <assign var="minMos" value="$mos;" />
     <writecdr header="CONFERENCE_min_MOS" value="$minMos;" numeric="true" qualityIsAscending="true" />
    </if>
   </if>
  </block>
 </else>
</on>

Here is a script to simulate the conference in SIP Tester:

<accept/>
<conference value="01" />

Test audio quality (PESQ MOS) and DTMF capability of a VoIP route (SIP trunk) in 2 directions

The 2 scripts (incoming and outgoing) are used to make test calls via a SIP route to check its audio quality and DTMF passability in 2 ways (from A to B and from B to A)

<!-- outgoing script (for call generator) -->
<!-- change destination number and IP address to what you need -->
<call value="sip:1234567890@12.34.56.78:5060" maxringtime="30s">
 <on event="answer">
  <playaudio value="speech.wav" repeat="infinite" maxtime="30s" />

  <wait value="1s" />
  <log value="(A, step 2) verifying audio" />
  <verifyaudio reference="speech.wav" maxtime="12s" mosvar="pesq_mos" />
  <writecdr header="PESQ_MOS_BtoA" value="$pesq_mos;" numeric="true" qualityIsAscending="true" />
  <waitforsilence />

  <log value="(A, step 3) receiving DTMF" />
  <inputdigits var="received_digits" maxdigits="10" maxsilence="15s" />
  <writecdr header="DTMF_BtoA" value="$received_digits;" />

  <wait value="10s" />
  <log value="(A, step 4) sending DTMF" />
  <playdtmf value="1234567890" />
  <wait value="10s" />

  <exit />
 </on>
</call>

<!-- incoming script (for call receiver) -->
<accept />
<verifyaudio reference="speech.wav" maxtime="12s" mosvar="pesq_mos" />
<writecdr header="PESQ_MOS_AtoB" value="$pesq_mos;" numeric="true" qualityIsAscending="true" />
<waitforsilence minTimeBelowLevel="1s" />

<log value="(B, step 2) got silence, playing audio" />
<playaudio value="speech.wav" repeat="infinite" maxtime="30s" />
<wait value="2s" />

<log value="(B, step 3) sending DTMF" />
<playdtmf value="1234567890" />
<wait value="10s" />

<log value="(B, step 4) receivingDTMF" />
<inputdigits var="received_digits" maxdigits="10" maxsilence="10s" />
<writecdr header="DTMF_AtoB" value="$received_digits;" />

<exit />

Test outbound dialer

The script processes incoming calls which are generated by dialer. It makes random delays, accepts or rejects call.

<log value="received call from '$callerId;'" />
<block probability="0.05" > <!-- executes code inside this block with probability = 0.05 (for 5% of incoming calls) -->
     <log value="rejecting with 500 after delay" />
     <wait value="$rand(100000);ms" /> <!-- For 5% of calls: make random delay, 100 seconds in average -->
     <reject value="500" /> <!-- reject call with SIP status = 500 (Internal Server Error) -->
     <exit />
</block>

<!-- For remaining 95% of calls: make random delay (1 second in average) before sending 183 Session Progress with early media --> <wait value="$rand(1000);ms" />
<accept value="183" />
<log value="sent 183" />

<on event="hangup">
 <log value="call is disposed by remote side" />
</<on>

<!-- 5% of remaining calls: reject with 486 (Busy Here) -->
<block probability="0.05" >
     <log value="rejecting with 486 after pause" />
     <wait value="$rand(1000);ms" />
     <reject value="486" />
     <exit />
</block>

<!-- 5% of remaining calls: play busy tone from file for 30 seconds and reject with 486 (Busy Here) -->
<block probability="0.05" >
     <log value="rejecting with 486 after busy tone" />
     <playaudio value="busytone.wav" maxtime="30s" /> <!-- plays tone from file (please download it into your program's folder) -->
     <reject value="486" />
</block>

<accept /> send 200 OK response
<log value="sent 200" />

<block probability="0.5" > <!-- answer machine -->
     <log value="simulating answer machine" />
     <say voice="Microsoft Anna" value="Hello, please enter extension number" maxsilence="30s" />
     <inputdigits var="enteredExtension" maxdigits="4" />
     <block test="$enteredExtension; != 1234"><!-- verify entered extension -->
         <log value="ERROR: expected extension '1234' but received '$enteredExtension;'" />
         <say voice="Microsoft Anna" value="extension $enteredExtension; is not valid" />
         <exit />
     </block>
     <say voice="Microsoft Anna" value="connecting to extension $enteredExtension;" />
     <wait value="$rand(10000);ms" />
     <exit />
</block>

<!-- real live call -->
<log value="simulating live call" />
<playaudio value="music" maxtime="100s" />

Text-to-speech IVR with MSSQL request
<accept /> <!-- Accept incoming call: send 200 OK to SIP-UAC -->
<say voice="Microsoft Anna" value="This is text-to-speech announcement. Please enter some number and press pound key." />
<!-- Play text message using default text-to-speech SAPI5 engine -->
<inputdigits var="enteredNumber" maxsilence="20s" maxdigits="10" />
<!-- Collect DTMF digits from user, store in variable "enteredNumber" -->
<say voice="Microsoft Anna" value="You have entered $enteredNumber;" />

<requestdb command="select InfoMessage from Table1 where PinCode = '$enteredNumber;'"
    connection="Data Source=(local)\SQLEXPRESS;User ID=sa;Password=123;Initial Catalog=DtmfTest;Asynchronous Processing=true"
    var0="infoMessage" /> <!-- Request table from MSSQL database and store a column in variable "enteredNumber" -->
<say voice="Microsoft Anna" value="$infoMessage;" /><!-- Speak message from database -->

Sending custom SIP request after provisional response for outgoing calls
<call callerId="" value="sip:100@localhost"/> <!-- Make outgoing SIP call to 100@localhost -->
<on event="pr"> <!-- Handler for provisional responses (180, 183) -->
<sendsiprequest>
<!-- Send custom SIP request (NOTIFY) within same INVITE session. Headers like Call-ID and request URI will be overridden, content length will be calculated automatically -->
<![CDATA[
NOTIFY sip:xx.yy.zz SIP/2.0
User-Agent: XYZ
Event: message-summary
Content-Type: application/simple-message-summary

Messages-Waiting: no
Message-Account: sip:*97@10.10.10.10
Voice-Message: 0/0 (0/0)
]]>
</sendsiprequest >
</on>
<on event="answer"> <!-- Handler for final response (200 OK) -->
<playaudio value="music" repeat="10000" maxtime="10000ms" />
<exit />
</on>
custom NOTIFY request generated by <sendsiprequest> element in CallXML

Sending different SDPs in 183 and 200 response for incoming calls

The script could be used to check whether SIP caller is able to adjust RTP stream according to changed SDP response in 200 OK

<sendsipmessage>
<![CDATA[SIP/2.0 180 Ringing
Via: $sipHeaderVia;
Call-ID: $sipCallId;
From: $sipHeaderFrom;
To: $sipHeaderTo; ;tag=b6a1c0b8e8334ef4b89f6a4d6154bbe1
CSeq: $sipHeaderCSeq;
Contact: <sip:192.168.0.13:5070>
Allow: INFO, PRACK, SUBSCRIBE, NOTIFY, REFER, INVITE, ACK, BYE, CANCEL, UPDATE
Server: StarTrinity.SIP 2014-04-28 20:20 UTC
Content-Type: application/sdp
Content-Length: 252

v=0
o=- 3607723560 3607723560 IN IP4 192.168.0.66
s=i14.proxy.stream0
t=0 0
m=audio 6666 RTP/AVP 8 101
c=IN IP4 192.168.0.66
a=rtcp:6667 IN IP4 192.168.0.66
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
]]>
</sendsipmessage>

<!-- at this time caller should send RTP to 192.168.0.66 -->
<wait value="3s" />

<sendsipmessage>
<![CDATA[SIP/2.0 200 OK
Via: $sipHeaderVia;
Call-ID: $sipCallId;
From: $sipHeaderFrom;
To: $sipHeaderTo; ;tag=b6a1c0b8e8334ef4b89f6a4d6154bbe1
CSeq: $sipHeaderCSeq;
Contact: <sip:192.168.0.13:5070>
Allow: INFO, PRACK, SUBSCRIBE, NOTIFY, REFER, INVITE, ACK, BYE, CANCEL, UPDATE
Server: StarTrinity.SIP 2014-04-28 20:20 UTC
Content-Type: application/sdp
Content-Length: 252

v=0
o=- 3607723560 3607723560 IN IP4 192.168.0.77
s=i14.proxy.stream0
t=0 0
m=audio 7777 RTP/AVP 8 101
c=IN IP4 192.168.0.77
a=rtcp:7778 IN IP4 192.168.0.77
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
]]>
</sendsipmessage>

<!-- after this 200 OK response caller should send RTP to 192.168.0.77 -->
<wait value="100s" />
<exit/>

Sending custom SIP INVITE without initial SDP

The script sends custom SIP message to server without creating call (only for testing SIP stack). The message is specified by 'CDATA' content of XML element. Call-ID header is generated from CallXML session ID.

<sendsipmessage>
<![CDATA[INVITE sip:192.168.206.197:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.206.197:5060;branch=z9hG4bK18171d2b3f11
From: "2000" <sip:2000@192.168.206.197>;tag=104574~6a5c17ac-9109-44e8-b315-975d70cd1b5d-22861245
To: <sip:1000@192.168.206.197>
Date: Mon, 29 Jul 2013 20:55:20 GMT
Call-ID: SipTester$Id;
Supported: timer,resource-priority,replaces
Min-SE: 1800
User-Agent: Cisco-CUCM8.6
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Allow-Events: presence
Send-Info: conference, x-cisco-conference
Alert-Info: <file://Bellcore-dr1/>
Contact: <sip:2000@192.168.206.197:5060>
Remote-Party-ID: "2000" <sip:2000@192.168.206.197;x-cisco-callback-number=2000>;party=calling;screen=yes;privacy=off
Max-Forwards: 69

]]>
</sendsipmessage>

Sending custom SIP INVITE with 2 media streams in SDP

The script sends custom SIP message to server without creating call (only for testing SIP stack). The message is specified by 'CDATA' content of XML element. SIP Tester automatically calculates 'Content-Length' header, so only 'Content-Type' header is needed. Call-ID header is generated from CallXML session ID.

<sendsipmessage>
<![CDATA[INVITE sip:192.168.206.197:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.206.197:5060;branch=z9hG4bK18171d2b3f11
From: "2000" <sip:2000@192.168.206.197>;tag=104574~6a5c17ac-9109-44e8-b315-975d70cd1b5d-22861245
To: <sip:1000@192.168.206.197>
Call-ID: SipTester$Id;
Supported: timer,resource-priority,replaces
User-Agent: StarTrinity SIP Tester
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Contact: <sip:2000@192.168.206.191:5060>
Max-Forwards: 69
Content-Type: application/sdp

v=0
o=root 342983111 342983111 IN IP4 192.168.1.188
s=Asterisk PBX 1.6.2.15
c=IN IP4 192.168.1.188
t=0 0
m=audio 11568 RTP/AVP 18 8 0
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=ptime:20
a=sendrecv
m=image 4488 udptl t38
a=T38FaxVersion:0
a=T38MaxBitRate:14400
a=T38FaxRateManagement:transferredTCF
a=T38FaxMaxDatagram:397
a=T38FaxUdpEC:t38UDPRedundancy
]]>
</sendsipmessage>

Monitoring SIP server with email notifications

This script makes a call to a SIP server and sends email alarms on success and failure. The SIP Tester Tool could be configured execute script periodically. Note that interval between calls has to be large enough to avoid anti-spam protection at mail server. The sendemail element uses settings "MailSenderUserName", "MailSenderPassword", "MailSenderServer", "MailSenderFrom", they are configured in SIP Tester on settings screen.

<call callerId="123456" value="sip:7890123@192.168.1.57:5060" /> <!-- send INVITE to destination SIP server and check its availability -->
<on event="answer"> <!-- handle 'answer' event which means receiving 200 OK from destination -->
  <assign globalvar="recurringFailuresCount" value="0" />
  <block test="$global.available; != true"> <!-- don't send same email twice -->
   <assign globalvar="available" value="true" />
   <sendemail value="mailto:username@gmail.com?subject=sip testing - OK&amp;body=received 200 OK response from server" />
  </block>
  <exit />
</on>
<on event="callfailure"> <!-- handle 'callfailure' event which means receiving error response from server or not receiving response on timeout -->
  <assign globalvar="recurringFailuresCount" mathvalue="$global.recurringFailuresCount; + 1" />
 <block test="$global.recurringFailuresCount; > 3 and $global.available; != false"> <!-- alert only after 3 repetitive failures; don't send same email twice -->
  <assign globalvar="available" value="false" />
  <sendemail value="mailto:username@gmail.com?subject=sip testing - call failed with status $eventSubType;&amp;body=call failed with status $eventSubType;"/>
 </block>
 <exit/>
</on>

Simulating RE-INVITE (put SIP call on hold)

Script for call generator:

<call value="sip:2222@server.com:5060"/>
<on event="answer">
 <playaudio value="music" maxtime="5s" />
 <reinvite direction="SendOnly" />
 <playaudio value="music" maxtime="5s" />
 <reinvite direction="ReceiveOnly" />
 <playaudio value="music" maxtime="5s" />
 <reinvite direction="None" />
 <playaudio value="music" maxtime="5s" />
 <reinvite direction="Both" />
 <playaudio value="music" maxtime="5s" />
 <exit />
</on>

Script for call receiver:

<accept />
<playaudio value="music" />
<!-- at this time SIP Tester responds 200 OK to incoming RE-INVITEs and automatically adjusts media direction -->

Simulating REFER (call transfer)

Script for call generator:

<call value="sip:2222@server.com:5060"/>
<on event="answer">
 <wait value="100s" />
<!-- at this time SIP Tester receives REFER and automatically makes transfer -->
 <exit />
</on>

Script for call receiver:

<accept />
<wait value="5s" />
<block test="$calledId; != redirected">
 <transfer value="sip:redirected@server.com:5060" mode="blind" /> <!-- send REFER -->
</block>
<exit />

Identification of IVR messages

This script recognizes audio signal in RTP stream, compares it with list of predefined WAV/MP3 files. The resuts are saved into variables and to CDR report. Audio verification is used to test IVR menus and check performance of IVR servers.

<playdtmf value="1" /> <!-- simulate DTMF key "1" -->
<verifyaudio reference="c:\ivr2.wav;c:\ivr3.wav" maxtime="10s" recognizeddelayvar="delay" recognizedreferencevar="ref" confidencevar="conf" />
<!-- verify audio signal in RTP stream during 10 seconds, identify which IVR message is played (one of reference files ivr3.wav or ivr2.wav). reference files have to be in WAV or MP3 format. they should contain original IVR messages which are played by server
results are saved to variables:
recognizeddelayvar="delay" - delay in milliseconds between start of verification and start of identified IVR message
                                        - IVR server's response time to DTMF event
recognizedreferencevar="ref" - name of identified reference file
confidencevar="conf" - confidence rate of identification, from 0 to 100 -->

<log value="delay = $delay;ms, reference file = $ref;, confidence = $conf;" /> <!-- show results in "Log" tab -->
<writecdr header="IVR" value="$ref;" /> <!-- save results to CDR report -->
<writecdr header="IVRCONF" value="$conf;" />

PESQ MOS (mean opinion score) audio quality measurement

This script measures audio quality of IVR message which is played by destination server

<verifyaudio reference="speech.wav" maxtime="10s" mosvar="mos" />
<!-- verify audio signal in RTP stream during 10 seconds, measure MOS.
reference file has to be in WAV or MP3 format. it should contain original IVR message which is played by server
result is saved to 'mos' variable -->

<log value="MOS = $mos;" /> <!-- show result in "Log" tab -->
<writecdr header="MOS" value="$mos;" numeric="true" qualityIsAscending="true" /> <!-- save result to CDR report, analyze it as numeric performance indicator -->

Client-server-client audio path verification
If SIP Tester is installed on both server side and on client side, it could be configured to test IP network for ability to pass RTP audio correctly.
  • Client-side SIP Tester generates SIP calls, transmits RTP audio to the server-side SIP Tester
  • Server-side SIP Tester accepts SIP calls, receives RTP audio and plays exactly same audio back to client (creates loopback connection)
    <accept />
    <loopbackaudio />
    If there is a NAT, you should set settings "SymmetricSIP" = "1" and "SymmetricRTP" = "1" on server-side SIP Tester
  • Client-side SIP Tester verifies the received audio if it equals to what it transmitted
    <call value="sip:test@server.com" maxringtime="60s" />
    <on event="answer">
      <playaudio value="speech.wav" dontwait="true" />
      <verifyaudio reference="speech.wav" maxtime="15s" confidencevar="confidence" />
         <writecdr header="CONFIDENCE" value="$confidence;" numeric="true" qualityIsAscending="true" />
      <exit/>
    </on>

Checking availability of SIP server using command line interface (CLI)

This script makes SIP call to a server and returns SIP status code into .bat file.

CallXML file (c:\srcipt.xml)
<callxml>
<log value="calling SIP server: $serverUri;" /> <!-- writes to command line output stream -->
<call value="$serverUri;" /> <!-- get command line parameter 'serverUri' and make outgoing call to server -->
<on event="answer">
    <log value="SIP server has answered to call"/>
    <playaudio value="music" repeat="10000" maxtime="20s" />
    <setexitcode value="200"/> <!-- save result to exit code of process -->
    <exit />
</on>
<on event="callfailure">
    <log value="call failed with status = $eventSubType;" />
    <setexitcode value="$eventSubType;" /> <!-- save result to exit code of process -->
</on>
</callxml>
test.bat file launches SIP Tester via CLI, passes server SIP URI as parameter, makes 2 calls to the server and reports status of last SIP call.
StarTrinity.SIPTester.CLI.exe TotalCalls 2 serverUri sip:100@192.168.1.1:5060 OutgoingCallXmlFile "c:\script.xml"
echo SIP status code is %ERRORLEVEL%

Verifying list of accounts using SIP REGISTER

The script is used by VoIP resellers to verify millions of SIP accounts to determine which are valid and which are not. Users and passwords are read from CSV file c:\siptester_files\users.csv. Results of testing are saved to users_suceeded.csv and users_failed.csv files. You can change file names and format of files by editing the script.

For current date, SIP Tester is able to verify about 500-1000 users per second on an average i3 desktop PC.

<readcsv value="c:\siptester_files\users.csv" var0="user" var1="password" /> <!-- read a line from CSV file into 'user' and 'password' variables -->
<register value="sip:sipserver.com:5060?user=$user;&amp;password=$password;" var="result" delayvar="delay" />
<!-- send REGISTER to a server to check account credentials. save SIP result code to a variable -->
<report value="$delay;" name="REGISTER response delay" qualityIsAscending="false" />
<!-- save measured response delay to SIP Tester GUI and HTML report -->
<report value="$result;" name="REGISTER result" qualityIsAscending="false" />
<block test="$result; = 200"> <!-- check if result of registration is successful -->
    <writefile fileName="c:\siptester_files\users_suceeded.csv" newLine="true" value="$user;;$password;" />
    <!-- save user and password to CSV file -->
    <exit/>
</block>
<writefile fileName="c:\siptester_files\users_failed.csv" newLine="true" value="$user;;$password;;$result;" />
<!-- save user, password, result code to CSV file -->

Verifying list of accounts using SIP INVITE

The script reads SIP URIs line by line from a text file C:\siptester_files\sipUris.txt and sends SIP INVITE messages (generates test calls) to check accounts on one or multiple servers. Results are saved to 2 separate files for suceeded and failed calls. SIP tester is able to generate about 200-500 calls per second on an average desktop i3 PC

<readcsv value="C:\siptester_files\sipUris.txt" var0="sipUri" />
<call value="$sipUri;" sendSdpInInitialInvite="false" />
<on event="answer">
    <writefile newLine="true" fileName="C:\siptester_files\suceeded.txt" value="$sipUri;" />
    <exit />
</on>

Playing random WAV file for incoming calls
<wait value="$rand(9,50);s" /> <!-- wait random time from 9 to 50 seconds before answering to call -->
<assign var="fn" value="$rand_from_options;"> <!-- initialize variable 'fn' with one of random options -->
    <option value="wav\incoming01.wav" />
    <option value="wav\incoming02.wav" />
    <option value="wav\incoming03.wav" />
</assign>
<accept /> <!-- answer to incoming call -->
<playaudio value="$fn;" /> <!-- play audio message until end of file -->
<exit />

Writing custom CDR files for incoming calls using <writefile />
<assign var="aNumber" value="$callerId;" />
<assign var="bNumber" value="$calledId;" />
<assign var="redirectedNumber" value="$redirectedNumber;" /><!-- get redirected number from SIP Diversion header -->
<assign var="callStart" value="$time();" />

<block probability="0.2"><!-- answer to 20% of calls -->
 <accept />
 <assign var="callEnd" value="$time();" />
 <disconnect />
<!-- save record to CDR file, split the file every 10 minutes -->
 <writefile newLine="true" fileName="F:\ftproot\ACCEPTED.txt" splitInterval="10m"
   value="$callStart;;$callEnd;;$aNumber;;$bNumber;;$redirectedNumber;" />
<exit/>
</block>

<reject value="503"/><!-- reject 80% of calls with status = 503 (Service Unavailable) -->
<assign var="callEnd" value="$time();" />
<writefile newLine="true" fileName="F:\ftproot\REJECTED.txt" splitInterval="10m"
  value="$callStart;;$callEnd;;$aNumber;;$bNumber;;$redirectedNumber;" />
<exit/>

Calling list of B numbers from CSV file with regular expression filter

The script is used to verify connectivity and billing in a customer's VoIP system. A and B numbers are read from custom CSV files: a_numbers.csv - one column with A numbers; b_numbers.csv - 1st column with B numbers, 2nd column with number of call attempts for each B number. CDR reports are saved into folder F:\ftproot in custom format. The CDRs files are separate for suceeded and failed SIP calls. Additionally, SIP Tester splits the files every 10 minutes.

<readcsv value="a_numbers.csv" var0="numA" mode="random" /><!-- read A number into variable -->
<block test="$numA; matches ^509.+" >
 <log value="skipping this number because it matches pattern 509xxx" />
 <exit />
</block>
<block test="$numA; matches ^00509.+" >
 <log value="skipping this number because it matches pattern 00509xxxx" />
 <exit />
</block>

<readcsv value="b_numbers.csv" var0="numB" countsColumnIndex="1" repeat="1" mode="random" />
<!-- read B number into variable -->

<log value="calling from $numA; to $numB;" />
<call value="sip:$numB;@10.10.1.50" callerId="$numA;" maxringtime="60s" /><!-- make outgoing call using A and B variables -->

<on event="answer">
 <log value="call answered from $numA; to $numB;" />
 <wait value="$rand(1000,3000);ms" /><!-- wait random time interval from 1 to 3 seconds -->
 <assign var="callEnd" value="$time();" />

<!-- save record into CSV CDR file with custom format. -->
 <writefile newLine="true" fileName="F:\ftproot\SUCEEDED.txt" splitInterval="10m" value="$callStart;;$callEnd;;$numA;;$numB;" />
 <on event="hangup"> <!-- call is aborted by called party -->
  <assign var="callEnd" value="$time();" />
  <writefile newLine="true" fileName="ftproot\SUCEEDED.txt" splitInterval="10m" value="$callStart;;$callEnd;;$numA;;$numB;" />
 </on>
 <exit /><!-- abort outgoing call -->
</on>
<on event="callfailure"><!-- call failed: received error response from destination server -->
 <log value="call failed from $numA; to $numB;" />
 <assign var="callEnd" value="$time();" />
 <writefile newLine="true" fileName="F:\ftproot\FAILED.txt" splitInterval="10m" value="$callStart;;$callEnd;;$numA;;$numB;" />
</on>
<on event="maxringtime"><!-- call is not answered in maxtime=60sec -->
 <log value="call timed out from $numA; to $numB;" />
 <assign var="callEnd" value="$time();" />
 <writefile newLine="true" fileName="F:\ftproot\FAILED.txt" splitInterval="10m" value="$callStart;;$callEnd;;$numA;;$numB;" />
</on>

Calling list of A and B numbers from 2 CSV file (2 countries) via 2 servers

The script is used to generate test VoIP traffic to multiple countries via multiple servers (your softswitches), reading A and B numbers from separate CSV files (one CSV file per country). CSV files contain 2 columns: B number (called ID) in 1st column and A number (caller ID) in 2nd column. The scripts limits number of concurrent calls (channels) per country. When call is answered, a random audio is played from directory with wav files

<readcsv value="C:\StarTrinity\CSV\Morocco160125.csv" var0="f0_1" var1="f1_1" repeat="infinite"/>
<readcsv value="C:\StarTrinity\CSV\Lybia160125.csv" var0="f0_2" var1="f1_2" repeat="infinite"/>
<call maxringtime="35000ms" value="$rand_from_options;" codec="G729" >
 <option value="sip:$f0_1;@[ip1]?callerId=$f1_1;" maxCallsPerDestinationResource="100" destinationResourceId="server1" />
 <option value="sip:$f0_2;@[ip2]?callerId=$f1_2;" maxCallsPerDestinationResource="200" destinationResourceId="server2" />
</call>
<on event="answer">
 <playaudio value="$randfile(C:\StarTrinity\Wav Files\*.wav);" repeat="infinite" maxtime="$rand(670000);ms" />
 <exit />
</on>

Generating DTMF tones for incoming calls

The script answers to incoming calls and generates a DTMF tone signals

<accept />
<playdtmf value="1" />
<!-- sends DTMF digit using SIP INFO or RTP stream. Alternatively you can play DTMF tone from audio file using "playaudio" -->
<wait value="500ms" />
<playdtmf value="2" />
<wait value="500ms" />
<playdtmf value="3" />
<wait value="500ms" />
<exit />

Playing different IVR messages for incoming calls based on Called ID
<accept />
<if test="$calledId; startswith 44">
 <log value="Called number starts with 44" />
 <playaudio value="IVR1.wav" />
 <exit />
</if>
<if test="$calledId; startswith 1">
 <log value="Called number starts with 1" />
 <playaudio value="IVR2.wav" />
 <exit />
</if>
<playaudio value="IVR3.wav" />
<exit />

Randomly simulate T.38 fax CED tone to test auto-dialer fax machine detector
<log value="received incoming call" />
<accept />
<wait value="3s" />
<block probability="0.1">
 <log value="simulating fax for this call" />
 <writecdr header="simulated_fax" value="1" />
 <receivefax />
 <exit/>
</block>

<log value="playing audio for this call" />
<writecdr header="simulated_fax" value="0" />
<playaudio value="music.wav" maxtime="$rand(100);s" />
<exit/>

Specifying RTP port numbers explicitly for incoming and outgoing calls
<!-- script for outgoing calls: port numbers 7000..7990 -->
<assign globalvar="portCounter1" mathvalue="$global.portCounter1; + 2" />
<if test="$global.portCounter1; > 990"> <assign globalvar="portCounter1" value="0"/> </if>
<assign var="port" mathvalue="$global.portCounter1; + 7000" />
<log value="using RTP port $port; for outgoing call" />
<call value="sip:111@10.10.10.1:5060" callerId="1111" localRtpPort="$port;" />
<on event="answer"> 
 <playaudio value="music.wav" maxtime="50s" />
</on>


<!-- script for incoming calls: port numbers 8000..8990 -->
<assign globalvar="portCounter2" mathvalue="$global.portCounter2; + 2" />
<if test="$global.portCounter2; > 990"> <assign globalvar="portCounter2" value="0"/> </if>
<assign var="port" mathvalue="$global.portCounter2; + 8000" />
<log value="using RTP port $port; for incoming call" />
<accept localRtpPort="$port;" />
<playaudio value="music2.wav" repeat="infinite" maxtime="20000ms" />
<exit />

Making a pause in test if destination server fails
<movingAverageGet id="callSetupRatio" var="csr" />
<log value="current call setup ratio MA100 = $csr;" />
<if test="$csr; < 0.6">
 <log value="CSR is less than threshold (0.6): stopping call generator, waiting 20 seconds" />
 <stopcallgenerator />
 <wait value="20s" />
 <log value="starting call generator after a pause" />
 <movingAverageReset id="callSetupRatio" />
 <startcallgenerator />
 <exit />
</if>

<call value="sip:test@10.10.10.1:5060" />
<on event="answer">
 <movingAveragePut id="callSetupRatio" size="100" value="1" />
 <wait value="1s" />
 <exit />
</on>
<on event="callfailure">
 <movingAveragePut id="callSetupRatio" size="100" value="0" />
</on>

Simulating sinusoid-type variable call load
<assign var="numberOfConcurrentCalls" mathvalue="120 + 100 * sin(($timeOfDayInHours(); - 10) / 24 * 360)" />
<!-- 360 – 360 degrees in a cycle -->
<!-- 24 – 24 hours in day interval -->
<!-- 10 – 10 hours AM is 0-degree point in sinusoid -->
<!-- 120 – average channels count -->
<!-- 100 – amplitude of change for channels count -->

<setcallgeneratorparams maxconcurrentcalls="$numberOfConcurrentCalls;" />

<call value="sip:test@10.10.10.1:5060" />
<on event="answer">
 <wait value="100s" />
 <exit />
</on>

Combining SUBSCRIBE, PUBLISH, INVITE tests in a single CallXML script
<!-- example of combining 3 test cases in a single CallXML script:
send SUBSCRIBE 7 times per second (use data from CSV file)
send PUBLISH 1 time per second
send INVITE (make a SIP call) 5 times per second
total rate of CallXML sessions per second must be greater than 13 CallXML sessions per second (configured in outgoing calls - interval between calls)
-->

<block minInterval="142ms"> <!-- executes internal sub-test (sending SUBSCRIBE) 7 times per second -->
 <readcsv value=".\SubscribeList.csv" var0="Device" var1="DevName" repeat="infinite" />
 <sendsipmessage>
<![CDATA[SUBSCRIBE sip:$Device;@sip.domain.com:5060 SIP/2.0
Via: SIP/2.0/UDP 1.2.3.4:5060;branch=z9hG4bK13054182
From: $DevName; <sip:$Device;@sip.domain.com:5060>;tag=1641318497
To: <sip:$Device;@sip.domain.com:5060>
Call-ID: 0_2505407707@1.2.3.4
CSeq: 1 SUBSCRIBE
Contact: <sip:$Device;@1.2.3.4:5060>
Accept: application/reginfo+xml
Max-Forwards: 70
User-Agent: Yealink SIP-T21P_E2 52.80.0.95
Expires: 3630
Event: dialog
Content-Length: 0
]]>
 </sendsipmessage>
 <exit/>
</block>
<block minInterval="1000ms">
 <readcsv value=".\PublishList.csv" var0="PubDevice" var1="PubDevName" repeat="infinite" />
 <sendsipmessage>
<![CDATA[PUBLISH sip:$PubDevice;@sip.domain.com SIP/2.0
Via: SIP/2.0/UDP 1.2.3.4:5060;branch=z9hG4bK03a3d1e310f928d0
From: $PubDevName; <sip:$PubDevice;@sip.domain.com>;tag=6e52f3725c8bd4bb
To: <sip:$PubDevice;@sip.domain.com>
Supported: path
Call-ID: f477f1f9e55aa8fc@1.2.3.4
CSeq: 1 PUBLISH
User-Agent: Grandstream GXP2000 1.2.5.3
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE,UPDATE,PRACK,MESSAGE
Expires: 300
Event: presence
SIP-If-Match: iK0rghih
Content-Length: 0
]]>
 </sendsipmessage>
 <exit/>
</block>
<block minInterval="200ms">
 <readcsv value=".\InviteList.csv" var0="callerIdFromCsv" var1="calledIdFromCsv" mode="random" repeat="infinite" />
 <call value="sip:$calledIdFromCsv;@sip.domain.com" callerId="$callerIdFromCsv;" />
 <exit/>
</block>

Combining INVITE and REGISTER tests in a single CallXML script (#1)
<!-- example of combining INVITE and REGISTER in a single CallXML script:
send INVITE (make a SIP call) 10 times per second
send REGISTER 5 times per second
total rate of CallXML sessions per second must be greater than 15 CallXML sessions per second (configured in outgoing calls - interval between calls)
-->


<assign var="destinationHost" value="192.168.0.216" />
<assign var="password" value="test1234" />
<assign var="extensionsCount" value="100" />
<assign var="baseExtensionId" value="3010" />
<assign var="extensionId" mathvalue="$baseExtensionId; + ($Id; % $extensionsCount;)" />
<log value="testing extension $extensionId;" />
<block minInterval="100ms"> <!-- executes internal sub-test (sending INVITE) 10 times per second -->
 <call value="sip:07042643699@$destinationHost;?user=$extensionId;&amp;password=$password;">
  <on event="answer" > <playaudio value="music.wav" repeat="10000" maxtime="$rand(20000);ms" /> </on>
 </call>
</block>
<block minInterval="200ms"> <!-- executes internal sub-test (sending INVITE) 5 times per second -->
 <register value="sip:$extensionId;@$destinationHost;?user=$extensionId;&amp;password=$password;" expires="3600" var="status" delayvar="delay" />
 <log value="REGISTER: received response code = $status;, delay = $delay;ms" />
</block>

Combining INVITE and REGISTER tests in a single CallXML script (#2)
<!-- read 2 rows from CSV file, read user IDs (accounts) -->
<readcsv value="userIds.csv" var0="userId1" repeat="infinite" repeatCounterVar="repeatCounter1" />
<readcsv value="userIds.csv" var0="userId2" repeat="infinite" repeatCounterVar="repeatCounter2" />
<log value="userId1=$userId1; repeatCounter1=$repeatCounter1; userId2=$userId2; repeatCounter2=$repeatCounter2; " />
<!-- send REGISTER or INVITE -->
<assign var="repeatCounter1mod5" mathvalue="$repeatCounter1; % 5" />
<if test="$repeatCounter1mod5; == 0">
<!-- 1st pass of CSV file: send 2 register's to user1 and user2 -->
  <register value="sip:$userId1;@192.168.10.4:5090?user=$userId1;&amp;password=123456" expires="3600" var="status" delayvar="delay" />
  <log value="user1 ($userId1;) REGISTER response code = $status;, delay = $delay;ms" />
  <register value="sip:$userId2;@192.168.10.4:5090?user=$userId2;&amp;password=123456" expires="3600" var="status" delayvar="delay" />
  <log value="user2 ($userId2;) REGISTER response code = $status;, delay = $delay;ms" />
</if>
<else>
<!-- 2+ pass of CSV file: call goes from CallerID = userId1 to CalledId = userId2 -->
 <call value="sip:$userId2;@192.168.10.4:5090?user=$userId1;&amp;password=123456" />
 <on event="answer">
   <playaudio value="music.wav" />
   <exit />
 </on>
</else>

Generating and receiving video+audio SIP calls
Generate call:
<!-- make call with audio+video streams. play music.wav and sample_H264.pcap (files from default SIP Tester installation: sample_H264.pcap/sample_H263.pcap/sample_VP8.pcap) -->
<call maxringtime="30s" value="sip:13108790819@192.168.10.5:5070" videoRtpmapEncodingName ="H264" videoPcapFileName ="sample_H264.pcap" videoSdpLines="a=fmtp:99 profile-level-id=42e00a; packetization-mode=1; max-br=452; max-mbps=11880" >
 <on event="answer">
   <playaudio value="music.wav" repeat="infinite" maxtime="30s" />
   <exit />
 </on>
</call>
Receive call:
<!-- accept call with audio+video streams. play music.wav and sample_H264.pcap (files from default SIP Tester installation: sample_H264.pcap/sample_H263.pcap/sample_VP8.pcap) -->
<accept value="200" videoRtpmapEncodingName ="H264" videoPcapFileName ="sample_H264.pcap" videoSdpLines="a=fmtp:99 profile-level-id=42e00a; packetization-mode=1; max-br=452; max-mbps=11880" />
<playaudio value="music.wav" repeat="infinite" maxtime="30s" />
<exit />
Generate call with custom video RTP payload type:
<!-- make call with audio+video streams. play music.wav and sample_H264.pcap (files from default SIP Tester installation: sample_H264.pcap/sample_H263.pcap/sample_VP8.pcap) -->
<setsetting name="VideoSdpPayloadType" value="126" />
<call maxringtime="30s" value="sip:13108790819@192.168.10.5:5070"
      videoRtpmapEncodingName ="H264"
      videoPcapFileName ="sample_H264.pcap"
      videoSdpLines="a=fmtp:99 profile-level-id=42e00a; packetization-mode=1; max-br=452; max-mbps=11880" >
 <on event="answer">
   <playaudio value="music.wav" repeat="infinite" maxtime="30s" />
   <exit />
 </on>
</call>
Receive call with custom video RTP payload type:
<!-- accept call with audio+video streams. play music.wav and sample_H264.pcap (files from default SIP Tester installation: sample_H264.pcap/sample_H263.pcap/sample_VP8.pcap) -->
<setsetting name="VideoSdpPayloadType" value="126" />
<accept value="200" videoRtpmapEncodingName ="H264" videoPcapFileName ="sample_H264.pcap"
      videoSdpLines="a=fmtp:99 profile-level-id=42e00a; packetization-mode=1; max-br=452; max-mbps=11880" />
<playaudio value="music.wav" repeat="infinite" maxtime="30s" />
<exit />

Generating and receifing audio SIP calls with custom audio codec, with playback from .pcap file
Generate call (in this example OPUS audio codec is used):
<call maxtime="10000ms" callerId="" value="sip:13108790819@192.168.10.5:5070" sdpAttributes="rtpmap:99 opus/48000" codec="99" />
 <on event="answer">
  <playaudio value="sample_opus_48000.pcap" repeat="10000" maxtime="20000ms" />
  <exit />
 </on>
Receive call (in this example OPUS audio codec is used):
<accept sdpAttributes="rtpmap:99 opus/48000" codec="99" />
<playaudio value="sample_opus_48000.pcap" repeat="infinite" maxtime="20000ms" />
<exit />

Using a custom formula to measure MOS score (different from G.107)
Please use following CallXML scripts at call generator and receiver running at 2 different servers at 2 locations, to test quality of IP network between the servers. Script for call generator side: please change "192.168.10.50" to IP address of call receiver server. "10m" means max duration of call = 10 minutes.
<callxml>
 <call value="sip:100@192.168.10.50:5070" codec="G711U">
  <on event="answer">
  <playaudio value="music.wav" maxtime="10m" />
  <getrtpmeasurements />
  <log value="MOS calculation inputs: RTT: $RTCP_RTT_Mean;ms mean jitter: $RTP_Called_MeanRfc3550Jitter;ms packet loss: $RTP_Called_LostPackets;%" />
  <assign var="effectiveLatency" mathvalue="$RTCP_RTT_Mean; + $RTP_Called_MeanRfc3550Jitter; * 2 + 10" />
  <if test="$effectiveLatency; &lt; 160"> <assign var="R" mathvalue="93.2 - ($effectiveLatency; / 40)" /> </if>
  <else> <assign var="R" mathvalue="93.2 - (($effectiveLatency; - 120) / 10)" /> </else>
  <assign var="R" mathvalue="$R; - (2.5 * $RTP_Called_LostPackets;)" />
  <assign var="MOS" mathvalue="1 + 0.035 * $R; + (0.000007) * $R; * ($R; - 60) * (100 - $R;)" />
  <log value="MOS calculation results: effectiveLatency=$effectiveLatency; R=$R; MOS=$MOS;" />
  <writecdr header="MOS" value="$MOS;" numeric="true" qualityIsAscending="true" />
  <exit />
  </on>
 </call>
</callxml>
Script for call receiver:
<callxml>
 <accept >
 <playaudio value="music.wav" maxtime="10m" />
 <getrtpmeasurements />
 <log value="MOS calculation inputs: RTT: $RTCP_RTT_Mean;ms mean jitter: $RTP_Caller_MeanRfc3550Jitter;ms packet loss: $RTP_Caller_LostPackets;%" />
 <assign var="effectiveLatency" mathvalue="$RTCP_RTT_Mean; + $RTP_Caller_MeanRfc3550Jitter; * 2 + 10" />
 <if test="$effectiveLatency; &lt; 160"> <assign var="R" mathvalue="93.2 - ($effectiveLatency; / 40)" /> </if>
 <else> <assign var="R" mathvalue="93.2 - (($effectiveLatency; - 120) / 10)" /> </else>
 <assign var="R" mathvalue="$R; - (2.5 * $RTP_Caller_LostPackets;)" />
 <assign var="MOS" mathvalue="1 + 0.035 * $R; + (0.000007) * $R; * ($R; - 60) * (100 - $R;)" />
 <log value="MOS calculation results: effectiveLatency=$effectiveLatency; R=$R; MOS=$MOS;" />
 <writecdr header="MOS" value="$MOS;" numeric="true" qualityIsAscending="true" />
 <exit />
</callxml>

SIPREC: generate SIP calls with 2 RTP streams and play stereo WAV file
The SIP Tester software simulates a SIPREC session recording client (SRC) and generates SIP calls to a session recording server (SRS), plays RTP streams from stereo WAV file. INVITE contains a mumtipart/mixed body with SDP and "recording-session" XML. The "recording-session" XML is configured in script.
<callxml>
 <call maxringtime="30s" value="sip:test@your_ip:5080?transport=tcp" callerId="acmeSrc" mode="siprec" headers="Require=siprec" direction="SendOnly" sdpAttributes="label:218110433" sdpAttributes2="label:218110434">
   <on event="answer">
    <playaudio value="C:\your_stereo_file_8khz_16bit.wav" mode="siprec" maxtime="50s" />
    <playaudio value="C:\your_mono_file_for_RTP_stream_1.wav" mode="" maxtime="10s" />
    <playaudio value="C:\your_mono_file_for_RTP_stream_2.wav" mode="siprec2" maxtime="10s" />
    <exit />
   </on>
   <additionalMultipartContent lineBreak="\n">
<![CDATA[Content-Type: application/rs-metadata+xml
Content-Disposition: recording-session

<?xml version='1.0' encoding='UTF-8'?>
<recording xmlns='urn:ietf:params:xml:ns:recording'>
      <datamode>complete</datamode>
      <session id="x">
      <associate-time>2021-08-10T05:33:55</associate-time>
      <extensiondata xmlns:apkt=http://acmepacket.com/siprec/extensiondata>
      <apkt:ucid>x3;encoding=hex</apkt:ucid>
      <apkt:callerOrig>true</apkt:callerOrig>
      </extensiondata>
      </session>
      <participant id="x" session="x">
      <nameID aor=sip:x@3.3.3.3>
      <name>x</name>
      </nameID>
      <send>x</send>
      <associate-time>2021-08-10T05:33:55</associate-time>
      <extensiondata xmlns:apkt=http://acmepacket.com/siprec/extensiondata>
      <apkt:callingParty>true</apkt:callingParty>
      <apkt:request-uri>sip:x@4.4.4.4:5060</apkt:request-uri>
      <apkt:realm>x</apkt:realm>
      <apkt:header label="Session-ID">
      <value>x;remote=00000000000000000000000000000000</value>
      </apkt:header>
      </extensiondata>
      </participant>
      <participant id="y" session="y">
      <nameID aor=sip:y@4.4.4.4>
      <name>y</name>
      </nameID>
      <send>y</send>
      <associate-time>2021-08-10T05:33:55</associate-time>
      <extensiondata xmlns:apkt=http://acmepacket.com/siprec/extensiondata>
      <apkt:callingParty>false</apkt:callingParty>
      </extensiondata>
      </participant>
      <stream id="z" session="z">
      <label>218110433</label>
      <mode>separate</mode>
      <associate-time>2021-08-10T05:33:55</associate-time>
      </stream>
      <stream id="FamKUgaTRE9xYVrZsj5GWQ==" session="z">
      <label>218110434</label>
      <mode>separate</mode>
      <associate-time>2021-08-10T05:33:56</associate-time>
      </stream>
</recording>
]]>
   </additionalMultipartContent>
 </call>
</callxml>

Check if numbers from list are dialable (ringing) or not and save report to file
Reads some specific list of numbers, check the number is dialable or not. Save report to file. If call is answered, drop the call immediately. Also drop the call when got "ringing" signal.
<callxml>
 <readcsv value="c:\numbers.txt" repeat="1" skipHeaders="false" var0="numB"/>
 <call maxringtime="10000ms" callerId="" value="sip:$numB;@mehedi1-5121-dev.sip.us1.twilio.com:5060">
 </call>
 <on event="pr:180;pr:183;answer">
  <writefile newLine="true" fileName="c:\numbers_good.txt" value="$numB;" />
  <exit />
 </on>
</callxml>

OTT bypass, other international bypass fraud detection
Looped traffic generation

Sample CallXML Scripts for StarTrinity Softswitch

Simple IVR-based filter
Play IVR files 0.wav, 2.wav, ... 99.wav sequentially, in loop
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script).
Accept the call (send 200 OK) immediately, play 100 files (the number 100 is configurable in script) sequentially from folder C:\WAV\. For every new call the counter is incremented and next audio file is played.
<callxml type="custom" >
 <accept/>
 <if test="'$global.originator1_counter;' == ''">
  <assign globalvar="originator1_counter" value="0" />
 </if>
 <else>
  <assign globalvar="originator1_counter" mathvalue="($global.originator1_counter;+1)%100" />
 </else>
 <playaudio value="C:\WAV\$global.originator1_counter;.wav" repeat="infinite" />
 <exit/>
</callxml>
Record the call (B side) for 20 seconds, end call leg B in 60 seconds, infinitely play recording
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script).
<!-- record the first 20 sec and after 60 sec cut the call from B side and play back the 20 sec the recording infinitely -->
<assign var="recordedFileName" value="C:\Recordings\$time(yyyyMMdd);\$time(HH_mm_ss_fff);_$calledId;.wav" />
<recordcall value="100" mode="tx" uri="$recordedFileName;" />
<settimeout value="20s"> <recordcall value="0" /> </settimeout>
<transfer terminators="terminator1" maxansweredtime="60s" />
<on event="maxansweredtime">
  <playaudio value="$recordedFileName;" repeat="infinite" />
  <exit />
</on>

Send DTMF digit some time after connection
Script for user of multi-tenant softswitch. Note that you need to set field "CallXML variables" to "send_dtmf=true" for originators where you want to enable this feature.
<callxml>
 <transfer terminators="routed">
  <on event="answer">
   <if test="$send_dtmf;" >
    <wait value="15s" />
    <playdtmf value="5" />
   </if>
  </on>
 </transfer>
 <exit/>
</callxml>

Blacklist caller RTP IP addresses that do not send RTP, to increase ACD of dialer traffic
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script).
<callxml type="custom">
<!-- this is custom callxml script for originator in StarTrinity Softswitch.
  the script analyses number of RTP packets from caller side and adds bad RTP IP addresses into blacklist -->

 <getrtpinfo />
 <dynamicblacklist id="$originatorId;_rtpip" value="$RTP_Remote_IP;" var="badCallsCountFromThisRtpIp" add="false" maxtime="1h" />
 <log value="[$calledId;] RTP IP = $RTP_Remote_IP;: bad calls count = $badCallsCountFromThisRtpIp;" />
 <if test="$badCallsCountFromThisRtpIp; &gt; 0">
  <log value="[$calledId;] rejected call with RTP from $RTP_Remote_IP;" />
  <reject value="503" />
  <exit />
 </if>
 <transfer terminators="routed" />
 <on event="hangup;localHangup">
  <getrtpinfo />
  <if test="$RTP_ExpectedDuration_ms; &gt; 500 and $RTP_AfterJbDuration_ms; &lt; 200">
   <log value="[$calledId;] added $RTP_Remote_IP; to blacklist: RTP_ExpectedDuration=$RTP_ExpectedDuration_ms;ms, RTP_AfterJbDuration=$RTP_AfterJbDuration_ms;ms" />
   <dynamicblacklist id="$originatorId;_rtpip" value="$RTP_Remote_IP;" />
  </if>
 </on>
</callxml>

Overwrite B numbers and make sure that number B is unique
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script). The number lists can be uploaded via HTTP POST API method "UploadNumberList".
<callxml type="custom">
 <assign var="c" value="0" />
<!-- read B number from number list "01.txt" -->
 <readnumberlist value="01.txt" var0="b" mode="random" label="retry"/>

<!-- make sure that there is no other call to the B number at this time -->
 <ifcallexists calledId="$b;">
  <assign var="c" mathvalue="$c; + 1" />
  <if test="$c; &gt; 5"> <reject value="503" /> </if>
  <goto value="retry" />
 </ifcallexists>

<!-- transfer cal lto terminator with overwritten number B (CLD) -->
 <transfer value="$b;" terminators="routed" />
</callxml>

Play ringback tone immediately when received a call, don't wait for call leg B (using "183 Session Progress" early media)
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script). Answer with "183 session progress" ("alerting") to call leg A after some random waiting time (1..3 seconds) and play a ringback tone from wav file in a loop. Also, make call to terminators according to routing configuration.
<callxml type="custom">
<!-- a CallXML script is set in softswitch menu - configuration - originators - originator details - callxml script type = custom -->
 <settimeout value="$rand(2000,4000);ms">
  <accept value="180" />
  <wait value="$rand(20,50);ms" />
  <accept value="183" />
  <wait value="50ms" />
<!-- play a random wav file with ringback tone -->
  <playaudio value="rbt$rand(1,3);.wav" dontwait="true" repeat="infinite" leg="A" />
<!-- note: you should upload wav files rbt1.wav, rbt2.wav, rbt3.wav with ringback tone in switch menu - configuration - audio files -->
 </settimeout>
 <transfer terminators="routed" proxyPR="false" proxyRingbacktone="false"/>
 <on event="answer">
  <stopaudio />
 </on>
</callxml>

Play ringback tone immediately when received a call, don't wait for call leg B (using "180 Ringing")
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script). Answer with "180 Ringing" to call leg A after some random waiting time (1..3 seconds). Then make call to terminators according to routing configuration.
<callxml type="custom">
<wait value="$rand(1000,3000);ms" />
<accept value="180" />
<transfer terminators="routed" />
</callxml>

Request HLR to filter VoIP traffic (reduce SIM blocking)
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script). Make API requests to hlrlookup.com: 1) validate caller number (A, CLI) 2) check status of destination number (B, CLD). Reject call with 503 if HLR request fails. Note: please put valid API key and password from hlrlookup.com
<callxml type="custom">
 <accept value="180" />

 <sendhttprequest value="https://www.hlrlookup.com/api/validate/?apikey=aaaaaaa&amp;password=bbbbbb&amp;msisdn=$callerId;" statusvar="status1" contentvar="result1" />
 <log value="api request#1 (validation) for msisdn=$callerId;: status=$status1; result=$result1;" />
 <if test="($result1; contains &quot;Status&quot;:&quot;Valid&quot;) == false" >
  <log value="rejecting call: number $callerId; is not valid" />
  <reject value="503" />
  <exit/>
 </if>

 <substring var="calledId2" value="$calledId;" startIndex="2" />
<!-- remove first 3 digits (tech prefix) in B number before making the HLR API request -->
 <sendhttprequest value="https://www.hlrlookup.com/api/hlr/?apikey=aaaaaaaa&amp;password=bbbbb&amp;msisdn=$calledId2;" statusvar="status2" contentvar="result2" />
 <log value="api request#2 (HLR status) for msisdn=$calledId;: status=$status2; result=$result2;" />
 <if test="($result2; contains &quot;error_text&quot;:&quot;Live&quot;) == false" >
  <log value="rejecting call: number $calledId; is not live (HLR)" />
  <reject value="503" />
  <exit/>
 </if>

 <transfer terminators="routed" />

</callxml>

Caller early media filter for VoIP traffic (reduce SIM blocking)
CallXML script for originator in StarTrinity softswitch (menu - configuration - originators - originator details - set "callxml script type" = "custom" - enter the script). Note: you should upload an audio file "rbt.wav" into softswitch menu - configuration - audio files.
<callxml type="custom">
 <accept value="183" />
 <playaudio value="rbt.wav" repeat="100" dontwait="true" />
 <wait value="500ms" />
 <waitforsignal signaldelayvar="d" level="-45" maxtime="3000ms" minTimeAboveLevel="10ms" />
 <if test="$d; &gt;= 3000"> <reject value="503" /> </if>
 <transfer terminators="routed">
    <on event="pr:183">
      <waitforsignal callLeg="B" maxtime="50s" />
      <stopaudio />
     </on>
     <on event="answer"> <stopaudio />
    </on>
 </transfer>
</callxml> </callxml>

Copyright 2011-2024 StarTrinity.com | Blog | Contact lead developer via LinkedIn |