StarTrinity.com

Measuring quality

CallXML documentation

Logic of processing SIP calls in StarTrinity VoIP software is defined by scripts written in high-level scripting programming language "CallXML". Incoming and outgoing SIP calls are processed by an engine which reads and executes CallXML elements in sequence. The CallXML elements define basic operations with the SIP call.

CallXML elements: description, attributes, examples of usage

accept Sends "200 OK" or "1xx" provisional response to incoming SIP call. Is not applicable for outgoing calls.
Sends a "488 Not Acceptable Here" response if codec negotiation failed. May contain inner "additionalMultipartContent" XML element and attribute "multipartBoundary" to send "multipart/mixed" content body (see example for "call"). The "additionalMultipartContent" element may contain XML attribute "lineBreak": "\r\n" or "\n". Attributes:
value (optional, default = "200") - SIP status code for the response. Note: "100 Trying" response is always sent, regardless of CallXML script
headers (optional) - list of custom SIP headers to be included into the response. The separator "|" is escaped by "\0x7C".
Example1: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
Example2: Header1Name=Header1\0x7CValue|Header2Name=Header2\0x7CValue
sdpAttributes (optional) - list of custom SDP attributes to be included into the response.
Example: Attr1Name:Attr1Value|Attr2Name:Attr2Value|Attr3Name:Attr3Value
localRtpPort (optional) - explicitly set local RTP UDP port number. If empty or zero, a socket from RTP transport pool is used (see settings "MediaTransportPoolMinPort", "MediaTransportPoolMaxSocketsCountPerInterface")
localRtpAddress (optional) - explicitly set local RTP IP address, is used to select network interface. If empty, the network interface is selected by remote IP address using system routing table (WinAPI function GetBestInterface())
fakeSdp (optional, "true" or "false", default is "false") - if set to "true", the software does not create RTP stream (does not take system resurces for media), and creates fake SDP instead, with optional parameters "localRtpAddress" and "localRtpPort". Is used when you need to run a high-CPS test via a SIP proxy (e.g. kamailio)
noRtpIfNoOffer (optional, "true" or "false", default is "false") - if set to "true", the software does not create RTP stream and does not send SDP in "200 OK", if initial INVITE did not contain SDP offer
codec (optional) - when sending 200 OK, selects audio codec
disableRtp (optional, "true" or "false", default is "false") - disables RTP stream for the SIP call. Is used to save CPU resources by enabling RTP only for some part of generated SIP calls
rtpDscp (optional, default is "0") - sets IP ToS (DSCP) field for transmitted RTP packets. Note: this parameter turns on "WinPCAP RTP sender" operation mode for the SIP call, in this mode you can only play one WAV audio file in loop. Example: "46"
debugMediaRx (optional, "true" or "false", default is "system settings") - enables recording of received (RX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
debugMediaTx (optional, "true" or "false", default is "system settings") - enables recording of transmitted (TX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
debugMediaMixed (optional, "true" or "false", default is "system settings") - enables recording of mixed (received+transmitted, RX+TX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
videoPcapFileName (optional) - specifies pcap file to be played in loop mode for audio+video SIP calls. Any video codec is supported
videoRtpmapEncodingName (optional) - specifies video encoding name in SDP for audio+video SIP calls. Example: "H263-1998", "H264", "VP8"
videoSdpLines (optional) - additional SDP lines for video stream in SDP. Example: "b=TIAS:1920000|a=fmtp:99 profile-level-id=64001F; sar=13; packetization-mode=1"
testId (optional) - Test ID to be passed into "Test ID" CDR column
<accept value="200" /> <!-- answer to SIP call -->
<accept value="183" /> <!-- send "183 Session Progress" response -->
<accept headers="WG67-Version=radio.01" sdpAttributes="R2S-KeepAlivePeriod:200|R2S-KeepAliveMultiplier:10|sigtime:1" />
<accept value="200" headers="History-Info: <SIP URL>;index=1|History-Info: <SIP URL>; index=1.1|Diversion=<sip:1111@1.1.1.1>;abc|Diversion=<sip:2222@2.2.2.2>;def" />

addsipmalformer Adds SIP malformer (SIP fuzzer) into current CallXML session, before "call" and "accept" elements. Both fixed and random fuzzers are available
The element allows VoIP hacking, it is a part of SIP security testing suite Attributes:
type (required) - type of malforming/fuzzing:
  • repeat
  • modifysinglebytes
  • genericbufferoverflow
  • replaceline
  • removeline
  • duplicateline
  • recommendedHardcoded - randomly uses information about one or multiple known exploits which are integrated into our software
probability (required) - probability to turn off this particular malformer
filterFirstBytes (optional) - is used when you need to apply the malformer only to particular SIP packets (e.g. only to ACK's)
various attributes - specific to every particular type of malformer
<callxml>
<!-- fuzzed SIP messages when receiving a SIP call flag enabled=false turns off specific malformers -->
<setrtpmalformer enabled="false" duplicateCount="1000" malformBitProbability="0.05" minDestinationRtpPort="9390" maxDestinationRtpPort="9490" />
  <addsipmalformer enabled="false" type="repeat" probability="0.5" packetsCount="40" wait10msPacketsCount="1000" />
  <addsipmalformer enabled="false" type="repeat" probability="0.1" packetsCount="10000" filterFirstBytes="ACK" />
  
  <addsipmalformer type="recommendedHardcoded" probability="0.2" />
  <addsipmalformer type="genericBufferOverflow" probability="0.15" />
  <addsipmalformer type="digits" probability="0.15" />
  <addsipmalformer type="genericBufferOverflow" probability="0.2" />
  <addsipmalformer type="digits" probability="0.2" />

  <addsipmalformer type="modifySingleBytes" probability="0.03" filterFirstBytes="ACK" probabilityToMalformNextByte="0.5" />
  <addsipmalformer type="modifySingleBytes" probability="0.03" probabilityToMalformNextByte="0.5" />
  <addsipmalformer type="modifySingleBytes" probability="0.01" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" />
  <addsipmalformer type="modifySingleBytes" probability="0.005" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="34" /> <!-- quotes -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="39" /> <!-- single quotes -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="32" /> <!-- space -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="37" /> <!-- %-->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="43" /> <!-- +-->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="58" /> <!-- : -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="59;61" /> <!-- ;= -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="60;62" /> <!-- lt gt -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="123;125" /> <!--{} -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="91;93" /> <!-- [] -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="13;10" /> <!-- cr lf -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="46" /> <!-- . -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="42" /> <!-- * -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="36" /> <!-- $ -->
  <addsipmalformer type="modifySingleBytes" probability="0.002" probabilityToMalformNextByte="0.5" nextByteMaxDistance="20" byteDecimalValues="0" /> <!-- null character -->

  <addsipmalformer enabled="false" type="replaceLine" filterFirstBytes="SIP/2.0 200 OK" filterLineFirstBytes="Contact:" value="Contact: &lt;sip:12183456789@192.T68.10.4:5090&gt;" />
  <accept fakeSdp="true" />
<!-- in this test we don't test RTP, so no need to put real SDP and create real RTP stream, in this way we reduce CPU load -->
  <wait value="2s" />
  <exit />

</callxml>

assign Sets new value to a variable. Variables are used to store intermediate data and to build complex logic in CallXML scripts. Variables can be accessed later in script using substitutions.
Valiables in CallXML are not typed, more specifically all have type "string" and are parsed dynamically if needed Attributes:
var (optional) - name of the variable. Variables are separated for different SIP calls
globalvar (optional) - name of the global variable. Global variables are shared between different SIP calls
value (optional) - new value for the variable. If it equals to "$rand_from_options;", the value is randomly selected from one of child XML elements (see example)
pattern (optional) - one or multiple patterns for the variable. Character "?" means a random digit. Examples: "18???????", "18???????&#10;19???????", "20:18???????&#10;80:19???????"
values (optional) - list of sequential values, separated by ";" (see example)
mathvalue (optional) - mathematical expression (see example). Supported operators are: ( ) * + - / ^ %. Functions: sin(x), cos(x), tg(x), ctg(x), sh(x), ch(x), th(x), sqrt(x), exp(x), (a)log(b), ln(x), abs(x), floor(x), ceil(x), round(x)
<assign var="fileName" value="$rand_from_options;">
 <option value="wav\01.wav" />
 <option value="wav\02.wav" />
 <option value="wav\03.wav" />
</assign>
<playaudio value="$fileName;"/>
<assign var="phone" values="101;102;103" /> <!-- call numbers 101, 102, or 103 sequentially in loop -->
<call value="sip:$phone;@server.com" />
<assign var="y" value="4" />
<assign var="x" mathvalue="-(5+5*5)/$y;+sqrt(4000000)" />
<log value="x=$x;" />

block Groups CallXML elements into single block. Is used for many purposes: "if" statements, matching strings with regular expressions, loops, simulation of random behaviour.
Attributes:
test (optional) - boolean expression, specifies condition of executing internal CallXML elements
repeat (optional, default is "1") - number of times to execute nested CallXML elements. If equals to "infinite", it will run until SIP call is destroyed. The "repeat" and "minInterval" parameters can not be set at the same time.
var (optional) - name of variable to receive iteration counter value
probability (optional, default is "1") - propability of executing nested CallXML elements
minInterval (optional) - minimal interval between executions of the block. If time since last execution of the block is smaller than the "minInterval", the block is not executed. The "minInterval" is useful when you want to do something not for every call, but for single call every minute. The "repeat" and "minInterval" parameters can not be set at the same time
<block test="$callerId;=100"> <!-- check if caller ID equals to "100" -->
 <reject value="486"> <!-- reject call with "486 Busy Here" if caller ID is "100" -->
</block>
<block probability="0.5">
 <log value="this is executed with probability 0.5" />
</block>
<log value="this is executed with probability 1" />
<block test="abc = abc">
  <log value="abc = abc - it is true" />
</block>
<block test="abc = def">
  <log value="abc = def - it is not true" />
</block>
<log value="making call to the server. it should be configured to answer to 'test' number with no delay" />
<call value="sip:test@localhost:5060" maxtime="5s" />
<on event="answer">
 <log value="call answered. aborting call" />
 <exit />
</on>
<on event="maxringtime;callfailure">
 <log value="call failed (5-sec timeout or error response). restarting server if did not restart already 3 minutes ago" />
 <block minInterval="3m">
  <sendemail value="mailto:email@gmail.com?subject=call to server failed. restarting the server" />
  <log value="restarting SIP server" />
   <!-- here you should set path to your SIP server -->
  <restartprocess value="C:\Users\User\AppData\Roaming\StarTrinity SipTester\StarTrinity.SIPTester.exe" />
 </block>
 <exit />
</on>
<log value="reporting global variables: total: $global.totalcounter;, block1 (probability 0.5): $global.block1counter;, block2 (probability 0.5*(1-0.5) = 0.25): $global.block2counter;" />
<assign globalvar="totalcounter" mathvalue="$global.totalcounter;+1" />
<block probability="0.5">
<assign globalvar="block1counter" mathvalue="$global.block1counter;+1" />
<exit />
</block>
<block probability="0.5">
<assign globalvar="block2counter" mathvalue="$global.block2counter;+1" />
<exit/>
</block>
<getstringlength var="calledIdLength" value="$calledId;" />
<block repeat="$calledIdLength;" var="i">
 <substring value="$calledId;" startIndex="$i;" length="1" var="digit" />
 <log value="extracted called ID digit #$i;: $digit;" />
 <playaudio value="C:\startrinity_siptester_latest\Wav\digit;.wav"/>
</block>

call Initiates new outgoing call (SIP UAC session) to specified destination; optionally aborts call on time out
Raises "answer", "maxringtime", "hangup", "localHangup", "pr", "audioSignal", "reinvite", "transferred", "idleMedia" and "callfailure" events. On "callfailure" sets variable "lastError" to SIP status code. On "transferred" event you should use "playaudio" element to send RTP to new call leg B. Executes next CallXML element if call was aborted. Handles "3xx (Moved Temporarily)" responses and makes another call to new destination. Saves remote SIP headers into CallXML variables with prefix "sipHeader", when received provisional response on answer from destination; saves remote SDP attributes into CallXML variables with prefix "sdpAttribute". May contain inner "additionalMultipartContent" XML element and attribute "multipartBoundary" to send "multipart/mixed" content body (see example). The "additionalMultipartContent" element may contain XML attribute "lineBreak": "\r\n" or "\n".
Note: one CallXML session should execute only one "call" element. If you want to make multiple calls with different parameters, you can use element "switch", or read the parameters from a CSV file, or you can put multiple "run" elements with 1 "call" element inside every "run" element. Attributes:
value (required) - specifies SIP URI of destination. Destination host can be specified as IP address (e.g. 192.168.10.1), DNS A-record name (e.g. sip-anycast-1.voice.google.com), DNS SRV-record name (e.g. _sip._udp.sip.voice.google.com). The SIP URI may contain following query parameters:
  • "transport" - "udp"/"tcp"/"tls", "udp" is default
  • "user", "password" - credentials for authentication
  • "proxyAddress", "proxyPort" - address of proxy server
  • "localSipPort" - local SIP UDP port to use for the call
  • "callerId" - user ID in 'From' header
Example values:
  • sip:12345@server.com
  • sip:12345@server.com:5060
  • sip:12345@1.2.3.4:5060
  • sip:12345@1.2.3.4:5060?user=AuthUser&amp;password=AuthPassword (here &amp; is XML escaping syntax)
  • sip:111111111;rn=D1234;npdi@1.2.3.4:5060?user=AuthUser&amp;password=AuthPassword
If value equals to "$rand_from_options;" - call is made to one of randomly selected destinations in "option" children XML elements (see example), and it sets CallXML variable "destinationResourceId". It is possible to limit number of concurrent calls per each "option" in list ("destination resource") and to build different call scenarios for different "destination resource".
If value equals to "$seq_sip_uri_from_csv(CSV_file_name[, optional csvLineStartIndex]);" - destination is read from CSV file, starting from specified zero-based line index (zero line index by default).
If value equals to "$random_least_busy_uac_registration();" - call is made using UAC registrations (used when simulating calls via extensions of tested IP PBX). If value equals to "$ext(100);" - call is made to a registered extension (UAS registration) with SIP ID = "100".
to (optional) - "To" header for SIP INVITE message. If "to" is not set, it is taken from "value" SIP URI
callerId (optional, default is "unknown") -"From" header or "SIP ID" for "From" header in INVITE message. Example: "123456", "sip:123456@domain.com"
sipCallId (optional) - SIP "Call-ID" header in INVITE message. Example: "StarTrinity$id;@yourdomain.com"
fromTag (optional) - unique "tag" parameter for "From" header in INVITE message
sendSdpInInitialInvite (optional, "true" or "false", default is "true") - specifies whether to send SDP in SIP INVITE message. If no SDP is sent in request, and if destination also does not send SDP in response, the SIP call will be established without RTP media. If the destination sends late SDP offer in 200 OK, the caller will respond with SDP answer in ACK.
disableRtp (optional, "true" or "false", default is "false") - disables RTP stream for the SIP call. Is used to save CPU resources by enabling RTP only for some part of generated SIP calls
rtpDscp (optional, default is "0") - sets IP ToS (DSCP) field for transmitted RTP packets. Note: this parameter turns on "WinPCAP RTP sender" operation mode for the SIP call, in this mode you can only play one WAV audio file in loop. Example: "46"
debugMediaRx (optional, "true" or "false", default is "system settings") - enables recording of received (RX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
debugMediaTx (optional, "true" or "false", default is "system settings") - enables recording of transmitted (TX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
debugMediaMixed (optional, "true" or "false", default is "system settings") - enables recording of mixed (received+transmitted, RX+TX) RTP audio stream to WAV file, directory path is configured by system settings "DebugMediaPath", "DebugMediaFileNamePattern"
direction (optional, "SendOnly"/"ReceiveOnly"/"None"/"Both", default is "Both") - RTP media direction to be declared in SDP
maxringtime (optional, default is "no timeout") - timeout of waiting for call answer in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "maxringtime" expires, call is aborted with CANCEL SIP message. It is max time to wait for answer, not max call duration
maxansweredtime (optional, default is "no timeout") - max call duration after answering in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "maxansweredtime" expires, "maxansweredtime" event is raised. If no event handler for "maxansweredtime" exists, the call is aborted with BYE SIP message
headers (optional) - list of custom SIP headers to be included into the INVITE message. The separator "|" is escaped by "\0x7C".
Example1: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
Example2: Header1Name=Header1\0x7CValue|Header2Name=Header2\0x7CValue
sdpAttributes (optional) - list of custom SDP attributes to be included into the INVITE message.
Example: Attr1Name:Attr1Value|Attr2Name:Attr2Value|Attr3Name:Attr3Value
sdpAttributes2 (optional) - custom SDP attributes for 2nd RTP stream for SIPREC testing. see sample CallXML script
codec (optional, "G711A"/"G711U"/"G723"/"G729", default is "any of supported") - RTP media codec (SDP media stream payload type) to be used for the SIP call
localRtpPort (optional) - explicitly set local RTP UDP port number. If empty or zero, a socket from RTP transport pool is used (see settings "MediaTransportPoolMinPort", "MediaTransportPoolMaxSocketsCountPerInterface")
localRtpAddress (optional) - explicitly set local RTP IP address, is used to select network interface. If empty, the network interface is selected by remote IP address using system routing table (WinAPI function GetBestInterface())
fakeSdp (optional, "true" or "false", default is "false") - if set to "true", the software does not create RTP stream (does not take system resurces for media), and creates fake SDP instead, with optional parameters "localRtpAddress" and "localRtpPort". Is used when you need to run a high-CPS test via a SIP proxy (e.g. kamailio)
localSipPort (optional) - explicitly set local SIP/UDP transport port. Is used with global settings "LocalSipPort", "LocalSipPortRange"
localSipAddress (optional) - explicitly set local SIP IP address, is used to select network interface. Is used with global setting "LocalSipAddresses"
var (optional) - name of variable where to save SIP status code of the call
testId (optional) - Test ID to be passed into "Test ID" CDR column
terminatorId (optional) - ID of terminator to associate with the new call. Is used for complex scripts in the softswitch to manipulate A and B call legs. If "terminatorId" is set, attribute "value" means called number (CLD)
videoPcapFileName (optional) - specifies pcap file to be played in loop mode for audio+video SIP calls. Any video codec is supported
videoRtpmapEncodingName (optional) - specifies video encoding name in SDP for audio+video SIP calls. Example: "H263-1998", "H264", "VP8"
videoSdpLines (optional) - additional SDP lines for video stream in SDP. Example: "b=TIAS:1920000|a=fmtp:99 profile-level-id=64001F; sar=13; packetization-mode=1". Node: video RTP stream payload type is configured by setting "VideoSdpPayloadType"
sentContactHeaderVar (optional) - name of CallXML variable to save value of sent Contact header (from the sent SIP INVITE packet)
cseq (optional) - initial sequence number for CSeq SIP header, non-zero value
mode (optional) - if set to "siprec", the SIP call will create 2 RTP streams for SIPREC testing. see sample CallXML script
<call maxringtime="10s" callerId="101" value="sip:100@localhost:5070" headers="Diversion=TestD|Header2=HeaderValue2" />
<call maxringtime="10000ms" callerId="$Id;" value="sip:100@localhost:5070"
  headers="Diversion=&lt;sip:+1234567890@BC05.MSCTG01;user=phone&gt;;reason=unknown" />
<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" />
<call value="sip:test@localhost" multipartBoundary="-----border----">
<additionalMultipartContent lineBreak="\r\n">
<![CDATA[
Content-ID: $id;@ng123.com
Content-Type: application/pidf+xml
Content-Transfer-Encoding: 8bit

<?xml version="1.0" encoding="ISO-8859-1"?>
<presence xmlns="urn:ietf:params:xml:ns:pidf"
xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"
xmlns:cl=" urn:ietf:params:xml:ns:pidf:geopriv10:civicLoc"
xmlns:gml="urn:opengis:specification:gml:schema-xsd:feature:v3.0"
entity="sip:caller1@ngsos.com">
<tuple id="id56345">
<status>
<gp:geopriv>
<gp:location-info>
<gml:location>
<gml:Point>
<gml:pos>$rand(30,40);.$rand(1,99999); -$rand(67,78);.$rand(1,99999);</gml:pos>
</gml:Point>
</gml:location>
</gp:location-info>
<gp:method>Manual</gp:method>
</gp:geopriv>
</status>
<contact priority="0.8">sip:abcd@4.5.6.7:5060</contact>
<timestamp>$time();</timestamp>
</tuple>
</presence>
]]>
</additionalMultipartContent>
</call>
<on event="answer">
 <playaudio value="music.wav" maxtime="10s" />
 <exit />
</on>
<call value="$rand_from_options;" callerId="sipTester" maxringtime="$rand(5000);ms" sendSdpInInitialInvite="true">
  <option value="sip:test@10.10.10.1:5060?transport=tcp" maxCallsPerDestinationResource="100"
    destinationResourceId="server1" />
  <option value="sip:test@10.10.10.2:5060?transport=tcp" maxCallsPerDestinationResource="200"
    destinationResourceId="server2" />
</call>
<on event="answer">
 <log value="call answered. resource ID = $destinationResourceId;" />
 <wait value="5s" />
 <exit />
</on>
<call maxringtime="30s" callerId="sip:test@192.168.1.10" value="sip:100@192.168.1.9:5060" />
<call callerId="&quot;AAA&quot; &lt;sip:TEST@192.168.1.10&gt;" value="sip:444@192.168.1.10:5060" />
<call maxringtime="10000ms" callerId="" value="sip:100@localhost:5070" sendSdpInInitialInvite="true"
headers="History-Info: <SIP URL>;index=1|History-Info: <SIP URL>; index=1.1|H1=<sip:1111@1.1.1.1>;abc|H1=<sip:2222@2.2.2.2>;def" />
<!-- make a SIP call with custom Contact header -->
<call value="sip:test@ims.mnc222.mcc302.abc.org" headers="Contact=sip:4087890001@ims.mnc222.mcc302.abc.org;q=0.5;+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg"|P-Asserted-Service=urn:urn-7:3gpp-service.ims.icsi.abc.cpm.largemsg|Accept-Contact=+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.abc.cpm.largemsg"" />
<call value="sip:11111@23.34.45.56" callerId="&quot;from display name&quot; &lt;sip:2222@23.34.45.56&gt;" to="&quot;to display name&quot; &lt;sip:11111@23.34.45.56&gt;" maxringtime="30s" />
<call value="sip:11111@23.34.45.56" callerId="55555" maxringtime="30s" headers="P-Charging-Vector=icid-value=1234bc9876e;icid-generated-at=192.0.6.8;orig-ioi=home1.net" />
<call value="sip:592111@startrinity.com:6060" callerId="19056089570" maxringtime="3s" var="r" codec="G711A">
 <on event="callfailure">
   <log value="call failed with status $eventSubType;. header WWW-Authenticate is: $sipHeaderWWW-Authenticate;"/>
 </on>
</call>

callgroup Initiates call to group of SIP phones. "parallel", "sequential", "queue" modes of calling phones are available.
Attributes:
value (required) - name of call group
ringbacktone (optional) - audio file name which is played to caller until call is answered
<callgroup value="worktime" ringbacktone="C:\wav\please_wait_for_answer.wav" />
<exit/>
<callgroups>
 <callgroup name="worktime" userName="" mode="parallel" >
  <callgroupitem value="sip:100@10.10.10.1" maxringtime="30s" />
  <callgroupitem value="sip:101@10.10.10.1" maxringtime="30s" />
  <callgroupitem value="sip:102@10.10.10.1" maxringtime="30s" />
 </callgroup>
</callgroups>

case Is used within "switch". Defines an option which can be executed
See also: "switch", "default" Attributes:
equals (optional) - specifies a value to check equality
startswith (optional) - specifies prefix
from (optional) - specifies lower inclusive bound for the value
to (optional) - specifies upper inclusive bound for the value
probability (optional) - specifies probability for the case. Sum of "probabily" values for all "case" elements in "switch" is normalized

checktime Checks current time, raises event if it matches to some schedule, or puts a value to a variable
Parameters of schedule are set by "span" XML elements (see example). "daystart" and "daystop" of the spans can be within same day or over midnight. Attributes:
var (optional) - name of variable where to save "value" attribute of selected time span (see example). if not set, the "checktime" raises "time_matches" event
<checktime>
 <span weekdays="mon,tue,wed,thu,fri" daystart="09:00" daystop="13:00" /> <!-- work days, 9AM ... 1PM -->
 <span weekdays="mon,tue,wed,thu,fri" daystart="14:00" daystop="18:00" > <!-- work days, 2PM ... 6PM -->
  <span daystart="15:10" daystop="15:20" value="false" /> <!-- except 3:10PM ... 3:20PM -->
 </span>
 <span date="2015.01.01" value="false" priority="1" /> <!-- except January 1, 2015 -->
</checktime>
<on event="time_matches" >
<!-- accept the call if the schedule worked -->
 <playaudio value="wav\welcome.wav" />
 <transfer value="techSupport" />
 <exit />
</on>
<playaudio value="wav\out_of_schedule.wav" />
<exit />
<assign var="ncalls" value="100" />
<checktime var="ncalls">
 <span weekdays="mon,tue,wed,thu,fri" daystart="09:00" daystop="13:00" value="150" />
 <span weekdays="mon,tue,wed,thu,fri" daystart="14:00" daystop="18:00" value="200" />
 <span date="2015.11.01" value="300" />
 <span date="2015.11.07" value="355" />
</checktime>
<log value="setting max concurrent calls = $ncalls;" />
<setcallgeneratorparams maxconcurrentcalls="$ncalls;" />

conference Connects a call with other calls in conference room
Raises "callsJoinedInConference", "maxTimeToWaitForOtherCallsInConference", "callsLeftConference" events. See also "ifconferenceexists" Attributes:
value (required) - ID of conference
direction (optional, "SendOnly"/"ReceiveOnly"/"None"/"Both", default is "Both") - audio direction between SIP call and conference room.
syncDestroy (optional, "true"/"false", default is "false") - specifies whether to destroy all other calls in conference when current call is destroyed
syncDestroyDelay (optional, default is "0ms") - specifies delay before destroying other calls in conference if "syncDestroy" is "true"
maxTimeToWaitForOtherCalls (optional, default is "infinite") - specifies a timeout of waiting for other calls to join the conference. If calls are joined, a "callsJoinedInConference" event is raised. If the timeout expires, "maxTimeToWaitForOtherCallsInConference" event is raised. The attribute and events are used to build a logic of billing calls only when there are 2 or more calls in conference (see example script).
<conference value="01" />
<assign var="ParentSessionID" value="$id;"/>
<assign var="NumToCall" value="sip:152@192.168.0.56" />
<run var="secondarySessionId" >
  <call value="$NumToCall;" to="$NumToCall;" callerId="123" maxringtime="100s" />
  <on event="answer" >
    <sendevent value="answer" session="$parentSessionId;" />
    <conference value="$Id;" />
  </on>
  <on event="callfailure">
   <log value="call failed with status $lastError;" />
   <sendevent value="callfailure" session="$parentSessionId;" />
  </on>
</run>
<playaudio value="ringbacktone.wav" />
<on event="externalevent:answer" >
 <accept />
 <conference value="$eventsenderId;" />
</on>
<on event="externalevent:callfailure" >
 <exit />
</on>
<accept value="183"/>
<log value="sent 183 session progress for incoming call. playing ringback tone" />
<playaudio value="music.wav" dontwait="true" />
<log value="adding to conference, setting a timer of 10 seconds to wait for other calls to join the conference" />
<conference value="conference01" maxTimeToWaitForOtherCalls="10s" />
<on event="maxTimeToWaitForOtherCallsInConference">
 <log value="wait timer expired. rejecting with 503" />
 <reject value="503" />
</on>
<on event="callsJoinedInConference">
 <log value="2 or more calls joined in conference. sending 200 OK to start billing" />
 <stopaudio />
 <accept value="200" />
</on>
<conference value="01"/>
<on event="dtmf:1">
 <playaudio value="you_pressed_1.wav" />
</on>
<on event="dtmf:2">
 <disconnect /> <!-- this aborts the call -->
</on>

controlaudio Controls currently played audio: moves position (forward/back), makes pause/resume
See also: playaudio Attributes:
action (required) - one of following:
  • pauseResume - puts played audio on pause or continues playing if paused
  • seekRelative - move (seek) forward or back to N milliseconds, where N is specified by "value" attribute. Negative "value" means going back (rewind), positive "value" means going fast forward
value (optional, default is "0") - depends on "action"
<playaudio value="music.wav">
  <on event="dtmf:1"> <!-- pause -->
   <controlaudio action="pauseResume" />
  </on>
  <on event="dtmf:2"> <!-- fast forward 30 seconds = 30000 milliseconds -->
   <controlaudio action="seekRelative" value="30000" />
  </on>
  <on event="dtmf:3"> <!-- rewind 40 seconds = 40000 milliseconds -->
   <controlaudio action="seekRelative" value="-40000" />
  </on>
</playaudio>

default Is used within "switch". Defines an option which is executed when no matching "case" element is found
See also: "switch", "case" Attributes:
[None]

dequeue Gets an element from a global queue and saves it to variables. If no element is found, empty values are saved
An "element" in the global queue is a raw array of values, 0..N. Attributes:
queueId (optional) - idenfier of the global queue
var0, var1, ... (multiple) - variables where to save dequeued element's values
exceptValue0, exceptValue1, ... (multiple) - filter for dequeued element's values
onlyValue0, onlyValue1, ... (multiple) - filter for dequeued element's values
<accept value="200" />
<enqueue value0="$sipCallId;" value1="$id;" />

<dequeue label="dequeue" var0="peerCallId" var1="peerSessionId" exceptValue0="$sipCallId;" />
<if test="'$peerCallId;' = ''">
  <wait value="3s" />
  <if test="$movedConferenceByPeerCall; = 1"> <log value="don't dequeue: already moved to conference" /> <wait /> </if>
  <goto value="dequeue" />
</if>

<dequeue onlyValue0="$sipCallId;" />
<assign var="conferenceId" value="$sipCallId;" />
<log value="connecting 2 calls: this call $sipCallId; peer call $peerCallId; session $peerSessionId;. conference ID = $conferenceId;" />

<sendevent session="$peerSessionId;" value="conference" />
<conference value="$sipCallId;" />
<on event="externalevent:conference">
  <assign var="movedConferenceByPeerCall" value="1" />
  <log value="joining to conference $conferenceId;" />
  <conference value="$conferenceId;" />
</on>

disableuacregistration Disables UAC registration for a specified period of time, so it will not be used for calls
Attributes:
value - SIP user ID of the UAC registration
maxtime - period to disable the item
<call value="$random_least_busy_uac_registration();" >
 <on event="callfailure" >
  <log value="call failed with status = $eventSubType;. temporarily disabling extension $callerId;" />
  <disableuacregistration value="$callerId;" maxtime="30m" />
 </on>
</call>

disconnect Terminates SIP call if it is created and not terminated yet. Sends BYE or CANCEL SIP message.
Does not terminate execution of CallXML script.
Note: callxml element after the "disconnect" element MAY not be executed, when the SIP call is physically destroyed, so if you need additinonal processing, please do it in a new CallXML session with "run" element (see example) Attributes:
headers (optional) - list of custom SIP headers to be included into BYE SIP message. The separator "|" is escaped by "\0x7C".
Example1: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
Example2: Reason=Q.850;cause=16;text=&quot;Normal call clearing&quot;
leg (optional, "A"/"B"/"both", default is "both") - specifies call leg for disconnection: A=origination side or B=termination side
<disconnect />
<disconnect />
<run >
<wait value="5s" >
<log value="5 seconds after disconnection" >
</run >

disconnectcalls Terminates all SIP calls, similar to "Abort all calls" button
Attributes:
<disconnectcalls />

dynamicblacklist Adds the specified number into RAM-based blacklist, checks if number of attempts exceed some specified threshold. Executes internal CallXML elements if the number gets blocked
Attributes:
id (required) - idenfier of the blacklist. The system may have multiple blacklists
maxtime (required) - max time to store the numbers in the list. Example: 60s, 60m, 24h
maxcount (required) - max number of occurences of the specified number in the list to block the call
value (required) - the number
var (optional) - name of variable where to save number of occurences in the list, if the number gets blocked
<dynamicblacklist id="01" maxtime="60s" maxcount="1" value="$calledId;" var="numAttempts">
<log value="$calledId; is blocked, number of attempts = $numAttempts;" />
<reject />
<exit />
</dynamicblacklist>
<log value="$calledId; is passed" />

else Is used after "if"; is executed if the test condition is false
Attributes:
[none]

enablesipscanner Enables and starts SIP scanner (for VoIP security tests)
The element allows VoIP hacking, it is a part of SIP security testing suite. Executes inner CallXML code within new CallXML session, passes variables "ipAddress", "port", "responsePacketData", "method", "responseFirstLine", "softwareHeader" into the new session for further processing Attributes:
maxRPS (optional, default is 10000) - target number of SIP scan requests per second
numberOfThreads (optional, default is 4) - number of concurrent threads
enable (optional, "true"/"false", default is "true") - turns on/off the SIP scanner threads
method (optional, "OPTIONS"/"INVITE"/"REGISTER"/"RANDOM" default is "OPTIONS") - method of SIP scanning
ipSequence (optional, "random"/"linear" default is "random") - IP addresses range enumeration sequence mode
portSequence (optional, "random"/"linear" default is "random") - UDP ports range enumeration sequence mode
portRange (optional, default is "5060-5060") - UDP port range for scanning, lower and upper bound values are included. Example: 5060-5080
ipMasks (optional, default is "[all IPs]") - IP ranges for scanning. Example: 192.168.1.0/24;192.168.2.0/24;192.168.0.0/24
userAgent (optional, default is "StarTrinityFriendlyScanner") - User-Agent SIP header value
<!-- starts multithreaded SIP scanner. default SIP method is OPTIONS, port 5060, random IP range (all possible IP's). -->
<enablesipscanner maxRPS="10000" numberOfThreads="4">
 <log value="SIP scanner got response from $ipAddress;: $responsePacketData;" />
</enablesipscanner>
<enablesipscanner maxRPS="20000" numberOfThreads="4">
 <log enabled="false" value="SIP scanner got OPTIONS response from $ipAddress;: $responsePacketData;" />
<sendsipmessage maxtime="2s" var="status" serverheadervar="srv">
<![CDATA[INVITE sip:100@$ipAddress;:5060 SIP/2.0
Via: SIP/2.0/UDP 195.154.173.208:5090
Max-Forwards: 70
To: sip:100@$ipAddress;
From: sip:101@195.154.173.208;tag=test$id;
Call-ID: $randdigits(10);
CSeq: $randdigits(4); INVITE
Contact: sip:101@195.154.173.208:5090
User-Agent: StarTrinityFriendlyScanner
Accept: application/sdp
Content-Length: 0
]]>
 </sendsipmessage>
 <log value="server $ipAddress; responded to INVITE with status=$status;. server: $srv;" />
</enablesipscanner>
<enablesipscanner maxRPS="3000" numberOfThreads="1" enable="true" method="REGISTER" portsRange="5060-5100" ipSequence="linear" ipMasks="192.168.1.0/24;192.168.10.0/24;192.168.0.0/24">
  <log enabled="true" value="got response from $ipAddress; port $port; response: $responsePacketData;" />
</enablesipscanner>

enqueue Adds an element to a global queue
Attributes:
queueId (optional) - idenfier of the global queue
value0, value1, ... (multiple) - element's values to add into the queue. An element in the queue is an array of values: "value0" .. "valueN"
<accept value="200" />
<enqueue value0="$sipCallId;" value1="$id;" />

<dequeue label="dequeue" var0="peerCallId" var1="peerSessionId" exceptValue0="$sipCallId;" />
<if test="'$peerCallId;' = ''">
  <wait value="3s" />
  <if test="$movedConferenceByPeerCall; = 1"> <log value="don't dequeue: already moved to conference" /> <wait /> </if>
  <goto value="dequeue" />
</if>

<dequeue onlyValue0="$sipCallId;" />
<assign var="conferenceId" value="$sipCallId;" />
<log value="connecting 2 calls: this call $sipCallId; peer call $peerCallId; session $peerSessionId;. conference ID = $conferenceId;" />

<sendevent session="$peerSessionId;" value="conference" />
<conference value="$sipCallId;" />
<on event="externalevent:conference">
  <assign var="movedConferenceByPeerCall" value="1" />
  <log value="joining to conference $conferenceId;" />
  <conference value="$conferenceId;" />
</on>

exec Parses string as CallXML script and executes it. Is similar to "eval" in JavaScript
Attributes:
value (required) - the CallXML script as string. It can be dynamically computed
<assign var="xml" value="&lt;log value=&quot;test" /&gt;" />
<exec value="$xml;" />

exit Terminates SIP call if it is created and not terminated yet. Sends BYE or CANCEL SIP message.
Terminates execution of CallXML script.
Attributes:
[none]
<exit />

exitcli Terminates current command-line-mode SIP Tester. Is used to pass result of testing to .bat script
See also: "setexitcode" Attributes:
value (optional) - process exit code
graceful (optional, "true"/"false", default "false") - "true" to stop call generator and to wait for all current calls to complete
<exitcli value="777" />

function Defines a function or subroutine. Is executed with "runfunction".
Session variables, global variables and parameters are shared between caller code and the function's code, there is no "function scope". There is only a "flat context" of variables. Functions enable to have all of repetitive code, like initiating environment, in one place. Attributes:
name (required) - unique name of function
[parameters] (optional, "in[;defaultValue]" or "out") - names and types of parameters. There are "in" (input) and "out" (output) types of function parameters. Input parameters may have default values (separated by semicolon); otherwise input parameters are required when running the function. Output parameters contain name of variable
<function name="func1" param1="in" param2="in" resultvar="out" >
 <log value="func1: param1 = $param1;, param2 = $param2;" />
 <assign var="resultvar" value="$param1;: OK" />
</function>

<runfunction name="func1" param1="TestValue1" param2="TestValue2" resultvar="result" />
<log value="result=$result;" />

getaudiofilelength Reads WAV or MP3 audio file, calculates its duration, saves result to variable
Attributes:
value (required) - absolute or relative path to audio file(s), separated by semicolon. If multiple files are specified, minimal duration is saved as result
var (required) - name of CallXML variable where to save audio length in milliseconds.
<getaudiofilelength value="music.wav" var="length" />
<log value="length = $length;ms" />

getcallcenteragent Gets available call center agent. Is used to develop a call center with CallXML.
Agents are uploaded to the softswitch via an API method /API/MainViewModel/CallcenterAgents/Upload. Attributes:
<getcallcenteragent g="group1">
 <if test="$u;!=''">
   <log value="transferring to SIP phone user $u; $ext($u;);" />
   <transfer value="$ext($u;);" />
 </if>
 <else>
   <log value="transferring to number $n;, via VoIP provider, using a regular PSTN call" />
   <transfer value="sip:$n;@192.168.10.50:5070" />
 </else>
 <exit />
</getcallcenteragent>
<log value="no free agents, rejecting call with 503" />
<reject value="503" />

getcallgeneratorparams Saves call generator parameters into CallXML variables.
Attributes:
maxcpsvar (optional) - name of CallXML variable to save max calls per second
maxconcurrentcallsvar (optional) - name of CallXML variable to save max concurrent calls
<getcallgeneratorparams maxcpsvar="maxcps" maxconcurrentcallsvar="nchannels" />
<log value="current params of call generation: max cps = $maxcps;, num of channels = $nchannels;" />

getcallinfo Saves RTP information into CallXML variables, for currently processed SIP call.
Attributes:
codecvar (optional) - name of CallXML variable to save name of current codec
<accept value="183"/>
<getcallinfo codecvar="codec" />
<log value="received call with codec = $codec;" />

getcdrcallscount Queries CDR with specified query expression and saves number of returned records into a variable. Is used in StarTrinity Softswitch for advanced filtering.
The software uses "memory" CDR (limited by global setting "MaxMemoryCdrCallsCount"), for higher performance. Calls in memory (RAM) get erased when the software is restarted. Attributes:
expression - boolean expression to query CDR
period (optional) - identifies CDR search period. Example: 24h - query calls in recent 24 hours
var - name of CallXML variable to save the number of queried calls
<getcdrcallscount expression="CalledId = 123456" var="c" period="24h"/>
<log value="there are $c; calls in CDR with specified criteria in recent 24 hours" />
<getcdrcallscount expression="MyCustomCdrHeader = SomeValue" var="c" period="24h"/>
<log value="there are $c; calls in CDR with specified criteria in recent 24 hours" />
<writecdr header="MyCustomCdrHeader" value="SomeValue"/>
<callxml type="custom">
<!-- this CallXML script can be set for specific originator/client -->
 <log value="StarTrinity softswitch processes the call with custom callxml script. Originator ID is: $originatorId;" />
 <log value="A number is $callerId;, B number is $calledId;" />

<!-- the custom CDR header "blocked" could be set according to your own logic, you can also reject the call or pass it to some different terminator/vendor -->
 <writecdr header="blocked" value="1" />

 <assign var="t1" value="$rand(15,45);" />
 <getcdrcallscount expression="blocked = '1' and originatorId='$originatorId;' and Direction = in" var="c" period="$t1;m" />
 <log value="$c; calls in RAM (memory) CDR with flag blocked = 1 in recent $t1; minutes. this log is accessible in CDR - call details" />

 <transfer terminators="routed" />
</callxml>

getdblcallscount Queries RAM-based dynamic black list and saves number of returned records into a variable. Is used in StarTrinity softswitch for advanced filtering.
Attributes:
value - number for the lookup
dblType - type of the dynamic blacklist for the lookup. One of following: cli_dbl1, cli_dbl2, cld_dbl1, cld_dbl2
terminatorId (optional) - specifies terminator's blacklists wor the lookup, by terminator ID. If not set, current originator's blacklists are used
var - name of CallXML variable to save the number of queried calls
<getdblcallscount value="$callerId;" var="count" dblType="cli_dbl1" />
<log value="number of items in dynamic CLI blacklist is $count; for number $callerId;" />
<if test="$count; &&gt; 10">
 <accept /> <!-- pass junk calls to IVR FAS -->
 <playaudio value="ivr.wav" />
 <exit />
</if>

getfilenamefrompath Parses full file path, extracts file name
Attributes:
value (required) - input file name with path
var (required) - name of CallXML variable to save file name without path
<getfilenamefrompath var="fn" value="c:\path\file.txt" />
<log value="file name = $fn;" />

gethash Calculates hash of a string
Attributes:
value (required) - input string
var (required) - name of CallXML variable to save hashed string
<gethash var="h" value="1231234123" />
<log value="hashed string = $h;" />

getrtpinfo gets RTP information from media into CallXML variables
The CallXML variables are: RTP_Remote_IP, RTP_Codec, RTP_Remote_Port, RTP_ExpectedDuration_ms, RTP_AfterJbDuration_ms . See also: "getrtpmeasurements" Attributes:
[none]
<accept />
<wait value="6s" />
<getrtpinfo />
<log value="RTP info: RTP_Remote_IP: $RTP_Remote_IP;, RTP_Codec: $RTP_Codec;, RTP_Remote_Port: $RTP_Remote_Port;, RTP_ExpectedDuration_ms: $RTP_ExpectedDuration_ms;ms, RTP_AfterJbDuration_ms: $RTP_AfterJbDuration_ms;ms" />
<callxml type="custom">
<!-- this is custom callxml script for originator in StarTrinity Softswitch -->
  <getrtpinfo />
  <log value="before transfer to B: RTP_Remote_IP: $RTP_Remote_IP;" />
 <transfer terminators="routed" />
 <on event="hangup;localHangup">
  <getrtpinfo />
<log value="after transfer: RTP_Remote_IP: $RTP_Remote_IP;, RTP_Remote_Port: $RTP_Remote_Port;, RTP_ExpectedDuration_ms: $RTP_ExpectedDuration_ms;ms, RTP_AfterJbDuration_ms: $RTP_AfterJbDuration_ms;ms" />
 </on>
</callxml>

getrtpmeasurements Saves measured RTP quality indicators into CallXML variables
The CallXML variables correspond to CDR header names in CSV files: RTP_Caller_G107R, RTP_Caller_G107MOS, RTP_Caller_LostPackets, RTP_Caller_MaxRfc3550Jitter, RTP_Caller_MeanRfc3550Jitter, RTP_Caller_MaxDelta, RTP_Caller_MinDelta, RTP_Caller_PacketTime, RTP_Caller_NonSilentDuration, RTP_Caller_Delay, SDP_RTP_Caller_Delay, RTP_Called_G107R, RTP_Called_G107MOS, RTP_Called_LostPackets, RTP_Called_MaxRfc3550Jitter, RTP_Called_MeanRfc3550Jitter, RTP_Called_MaxDelta, RTP_Called_MinDelta, RTP_Called_PacketTime, RTP_Called_NonSilentDuration, RTP_Called_Delay, SDP_RTP_Called_Delay, RTCP_RTT_Max, RTCP_RTT_Mean, RTCP_Caller_Jitter_Max RTCP_Caller_Jitter_Mean, RTCP_Caller_LostPackets, RTCP_Called_Jitter_Max, RTCP_Called_Jitter_Mean, RTCP_Called_LostPackets, RTP_Rx_PacketsTotal, RTP_Rx_PacketsDiscarded, RTP_Rx_PacketsDiscarded_Duplicated, RTP_Rx_PacketsDiscarded_Early, RTP_Rx_PacketsDiscarded_Late, RTP_Rx_PacketsDiscarded_Error Note: the RTP stream is removed from the Packet Analyser, when no RTP packets are detected for some time, and RTP measurements get erased. Please increase global setting "DetectedRtpStreamMaxIdleTimeMs" if you want to keep the RTP stream for longer time.
See also: "resetrtpmeasurements", "getrtpinfo" Attributes:
[none]
<accept />
<wait value="6s" />
<getrtpmeasurements />
<log value="caller-called RTP stream: sdp-rtp delay: $SDP_RTP_Caller_Delay;ms, packet loss: $RTP_Caller_LostPackets;%, max delta: $RTP_Caller_MaxDelta;ms, max rfc3550 jitter: $RTP_Caller_MaxRfc3550Jitter;ms, G.107 MOS: $RTP_Caller_G107MOS;" />
<log value="RTCP measurements: caller max jitter: $RTCP_Caller_Jitter_Max;ms; caller packet loss: $RTCP_Caller_LostPackets;%, called max jitter: $RTCP_Called_Jitter_Max;ms; called packet loss: $RTCP_Called_LostPackets;%, max round trip delay: $RTCP_RTT_Max;ms" />

getsiptrace Saves information about previously sent or received SIP packet into a variable
Searches SIP trace of current SIP call or another call by SIP Call ID, saves SIP message into a variable. Then searches for a specific line (SIP header or SDP attribute) and saves matched line to a variable
See also: substring, sendsipmessage, sendsiprequest
Attributes:
sipCallId (optional, default is current SIP call) - SIP Call-ID header (unique identifier of SIP call) used to find the SIP trace
packetStart (required) - first bytes of searched SIP packet. Example: SIP/2.0 200
packetVar (optional) - name of variable where to save the SIP packet
lineStart (optional) - first bytes of searched line in the SIP packet. Example: m=
lineVar (optional) - name of variable where to save the line
<call value="sip:test@192.168.10.77:5060">
 <on event="answer" >
   <getsiptrace packetStart="SIP/2.0 200" packetVar="latest200SipPacket" /> <!-- get "200 OK" packet and save it to a variable -->
   <log value="200 OK packet: $latest200SipPacket;" />
   <getsiptrace packetStart="SIP/2.0 100" packetVar="latest100SipPacket" /> <!-- get "100 Trying" packet and save it to a variable -->
   <log value="100 Trying packet: $latest100SipPacket;" />

   <getsiptrace packetStart="SIP/2.0 200" lineStart="Allow: " lineVar="latest200okAllowLine" /> <!-- get "Allow" header from "200 OK" packet and save it to a variable -->
   <log value="200 OK packet Allow line: $latest200okAllowLine;" />
   <getsiptrace packetStart="SIP/2.0 200" lineStart="m=" lineVar="latest200okSdpMLine" /> <!-- get "m=" SDP attribute from "200 OK" packet and save it to a variable -->
   <log value="200 OK packet SDP m= line: $latest200okSdpMLine;" />

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

getstatistics Gets statistics about processed SIP calls
Saves statistics into CallXML variables:
incomingCps1s, incomingCps10s, incomingCps100s - incoming calls rate per second, averaged by 1, 10 and 100-second filters
outgoingCps1s, outgoingCps10s, outgoingCps100s - outgoing calls rate per second, averaged by 1, 10 and 100-second filters
answeredCallsCount - total number of answered calls
answeredCallsAverageDuration - average answered duration (in seconds)
currentAnsweredCallsCount - number of answered calls at current time
currentCallsCount - number of concurrent calls at current time
See also: resetstatistics
Attributes:
[none]
<getstatistics />
<log value="incomingCps1s = $incomingCps1s;; incomingCps10s = $incomingCps10s;; incomingCps100s = $incomingCps100s;" />
<log value="outgoingCps1s = $outgoingCps1s;; outgoingCps10s = $outgoingCps10s;; outgoingCps100s = $outgoingCps100s;" />
<log value="answeredCallsCount = $answeredCallsCount; answeredCallsAverageDuration = $answeredCallsAverageDuration; currentAnsweredCallsCount = $currentAnsweredCallsCount; currentCallsCount = $currentCallsCount;" />

getstringlength Calculates length of a string/number in characters/digits
Saves result into CallXML variable Attributes:
value (required) - input string
var (required) - name of variable where to save result
<getstringlength value="$calledId;" var="calledIdLength" />
<log value="Called ID length = $calledIdLength;" /> <getstringlength value="$callerId;" var="callerIdLength" />
<log value="Caller ID length = $callerIdLength;" />

getwg67info Saves WG-67 RTP header extension data into CallXML variables. Measures round-trip delay time if peer SIP-UA has PTT-SQU loopback connection
Attributes:
ptt2squdelayvar (optional) - name of CallXML variable to save measured round-trip delay time [in milliseconds]
ptttypevar (optional) - name of CallXML variable to save WG-67 PTT-type field from RX stream
pttidvar (optional) - name of CallXML variable to save WG-67 PTT-ID field from RX stream
squvar (optional) - name of CallXML variable to save WG-67 SQU field from RX stream
pmvar (optional) - name of CallXML variable to save WG-67 PM field from RX stream
pttsvar (optional) - name of CallXML variable to save WG-67 PTTS field from RX stream
sctvar (optional) - name of CallXML variable to save WG-67 SCT field from RX stream
<!-- script for UAC side: make a call, play RTP extension sequence, measure delay and save data to CDR -->
<call value="sip:111@devpc:5070" callerId="1111" />
<on event="answer">
 <setrtpextension wg67_pttType="1" wg67_pttId="16" />
 <playaudio value="music.wav" maxtime="3s" />
 <setrtpextension wg67_pttType="0" wg67_pttId="16" />
 <playaudio value="music.wav" maxtime="3s" />
 <getwg67info ptt2squdelayvar="ptt2squdelay" ptttypevar="ptttype" pttidvar="pttid" squvar="squ" pmvar="pm" pttsvar="ptts" sctvar="sct" />
 <log value="WG67 measurements: ptt2squdelay=$ptt2squdelay;ms, ptttype=$ptttype;, pttid=$pttid;, squ=$squ;, pm=$pm;, ptts=$ptts;, sct=$sct;" />
 <writecdr field="RX_WG67_PTT_ID" value="$pttid;" />
 <writecdr field="RX_WG67_PTT2SQU_DELAY" value="$ptt2squdelay;" numeric="true" qualityIsAscending="false" />
<!-- save measured delay to CSV CDR file, GUI report and history charts on "reports/statistics" tab -->
 <exit />
</on>

<!-- script for UAS side: accept the call and set up PTT->SQU loopback connection -->
<accept />
<setrtpextension wg67_pttType="1" wg67_pttId="33" wg67_squ="rxptt" wg67_pm="0" wg67_ptts="0" wg67_sct="0" />
<playaudio value="music2.wav" repeat="infinite" maxtime="60s" />
<exit />

goto Performs one-way transfer of control to another CallXML element with specified "label".
Attributes:
value (required) - destination CallXML element "label" attribute
test (optional) - boolean expression, specifies condition of transfer
<goto value="play_music1" test="$callerId; = 100" />
<goto value="play_music2" test="$callerId; = 101" />
<reject />
<block label="play_music1" >
  <playaudio value="music1.wav" />
  <exit />
</block>
<block label="play_music2" >
 <playaudio value="music2.wav" />
 <exit />
</block>

if Executes internal CallXML elements if specified conditions are satisfied
Optionally executes internal elements of "else", "elseif", which should be placed after "if" Attributes:
test (required) - boolean expression, specifies condition of executing internal CallXML elements. Syntax of condition is following:
<if test="abc = abc">
 <log value="abc = abc - it is true" />
</if>
<else>
 <log value="abc != abc - it is not true" />
</else>

<if test="abc = def">
 <log value="abc = def - it is not true" />
</if>
<else>
 <log value="abc != def - it is true" />
</else>

<if test="abc = abc and def = def">
 <log value="abc = abc AND def = def - it is true" />
</if>
<accept />
<if test="$callerId; startswith 44 or $callerId; startswith +44">
 <log value="Caller ID starts with 44 or +44" />
 <playaudio value="IVR1.wav" />
 <exit />
</if>
<if test="$callerId; startswith 1 or $callerId; startswith +1" >
 <log value="Caller ID starts with 1 or +1" />
 <playaudio value="IVR2.wav" />
 <exit />
</if>
<log value="some unknown Caller ID: $callerId;" />
<playaudio value="IVR3.wav" />
<exit />
<log value="start of test" />
<if test="1=2">
  <log value="1=2" />
</if>
<if test="3=2">
  <log value="3=2" />
</if>
<elseif test="1=1">
  <log value="1=1" />
</elseif>
<else>
  <log value="inside 'else' element" />
</else>
<log value="end of test" />

ifcallexists Executes internal CallXML elements if a SIP sall with specified criteria exists in current calls or in call history
Ignores leading "+" character in the numbers. You can check if call exists at another (remote) instance of SIP Tester by sending a HTTP API request, see in "sendhttprequest" examples Attributes:
sipCallId (optional) - SIP Call-ID
callerId (optional) - SIP User ID in "From" header
calledId (optional) - SIP User ID in "To" header
calledId_WithoutTechPrefix (optional) - CLD (B) number (used in StarTrinity Softswitch only)
direction (optional, "in" or "out") - incoming or outgoing call
expression (optional) - CDR filter boolean expression, when querying call history. It must be constant, for callerId and calledId filters use corresponding attributes
considerThisCall (optional, "true" or "false", default "true") - specifies whether to consider current call when searching for the matching call
foundCallSessionIdVar (optional) - name of CallXML variable where to put CallXML session ID of matched call, if call exists. Is used to send an event to the matched call.
<assign label="generate_new" var="from" value="$rand(1000,1005);" />
<ifcallexists callerId="$from;" >
 <goto value="generate_new" />
</ifcallexists>
<call value="sip:test@10.10.10.10" callerId="$from;" />
<ifcallexists query="CalledId = $calledId;" >
 <log value="this number has already been called" />
</ifcallexists>

ifconferenceexists Executes internal CallXML elements if conference with specified ID currently exists
Attributes:
value (required) - ID of conference
<ifconferenceexists value="$confId;">
 <accept />
 <conference value="$confId;" />
</ifconferenceexists>
<reject value="503"/>

ifnumberexists Executes internal CallXML elements if a number list contains specified number (fast number lookup by prefix)
A number list may contain millions of records. An item in list may contain concatenated A and B numbers Attributes:
value (required) - searched number (prefix)
numberListId (required) - number list ID (number list is uploaded via softswitch web interface)
<ifnumberexists value="$calledId;" numberListId="blacklist_CLI_01">
 <reject value="503" />
</ifnumberexists>

include Reads and executes another CallXML file. Returns control to current file after the execution. Imports functions from included file.
The included file is read from disk or obtained from memory cache only when CallXML flow reaches the "include" element. Included file name could be dynamically calculated. File must have ASCII encoding. Note: "on" elements (event handlers) can not be placed inside included file. Please have "on" elements in main Attributes:
value (optional) - path to included CallXML file. It can be dynamically calculated. The path can be absolute or relative to currently executed CallXML file location
httpUrl (optional) - HTTP URL of included CallXML file. It can be dynamically calculated
cache (optional, "true" or "false", default "true") - specifies whether to use previously cached included file from memory or not. By default the "include" uses cached copy of callXML file and asynchronously starts to update the cache from disk, so the CallXML flow is not delayed with file access operation
<include value="CustomScripts\script1.xml" />
<switch value="$callerId;">
 <case startswith="198" > <include value="params198.xml" /> </case>
 <case startswith="199" > <include value="params199.xml" /> </case>
</switch>

<playaudio value="$param.greeting;" />

inputdigits Collects digits and saves them into variable
Attributes:
value (optional) - absolute or relative audio file name(s) or URL(s) to be played. Multiple file names or URLs are separated by semicolon (example: speech.wav;music.wav). If relative file name is specified, in multitenant mode first it tries to locate a tenant-specific audio file in \[tenantId]\ subfolder, and if it is not found, it uses file from program root folder
repeat (optional, default is "1") - number of times to repeat audio file
var (required) - name of variable to save entered digits
maxdigits (optional) - max number of entered digits. The played announcement is stopped afrter first entered digit
finalkey (optional) - terminating key which ends the entry of digits
finalkeys (optional) - terminating keys which end the entry of digits, example: #* - both # and * digits terminate the entry. The terminating key is saved into output variable
maxsilence (optional, default is "infinite") - time interval of waiting for DTMF digits after end of playing audio file. Is set in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix).
updateCacheFromDisk (optional, "true"/"false", default is "false") - if set to "true", checks file last modification time and updates RAM cache when file is modified
digittimeout (optional, default is "infinite") - max time to wait after every entered digit (max time between digits)
<inputdigits value="C:\wav\enter_phone_and_press_pound_key.wav" finalkey="#" var="enteredNumber" maxsilence="20s" maxdigits="10" />
<transfer value="sip:$enteredNumber;@192.168.1.4" />
<accept />
<inputdigits var="d" maxsilence="20s" />
<writecdr header="digits" value="$d;" />
<accept />
<inputdigits value="enter_digits.wav" var="d" digittimeout="7s" maxdigits="100" />
<writecdr header="digits" value="$d;" />

inputspeech Recognizes voice (speech) to text and saves the text into variable. Uses VOSK speech recognition server (based on Kaldi).
Attributes:
maxtime (optional) - max recognition time, timeout. Example: "5s"
var (required) - name of variable to save recognized text
singlePhrase (optional, "true"/"false", default is "false") - set to "true" if need to recognize one phrase (text command), not continuous speech. In this case exits and goes to next CallXML element when a phrase is completed. If set to "false", raises "sr" CallXML events when the voice phrases are recognized. See examples for more details
<playaudio value="say_name.wav" />
<playaudio value="beep.wav" dontwait="true" />
<inputspeech voskServer="ws://192.168.1.2:2700/" var="t" maxtime="5s" singlePhrase="true" />
<switch value="$t;">
  <case equals="Sales"> <transfer value="sip:101@10.10.10.10" /> </case>
  <case equals="Support"> <transfer value="sip:102@10.10.10.10" /> </case>
</switch>
<playaudio value="ask_customer_feedback.wav" />
<inputspeech voskServer="ws://192.168.1.2:2700/" var="t" singlePhrase="false" />
<on event="sr">
  <log value="recognized phrase $t; you can send it to your server via HTTP API or to database via ODBC driver" />
</on>

limitcps Limits number of calls per second (CPS) and concurrent calls (CC) in dialer scripts. Allows you to limit CPS and CC per destination IP.
If CPS/CC goes over specified limit (parameter "maxCPS" or "maxCC"), puts the CallXML session into a queue (identified by parameter "queueId"). This queue gets dequeued when CPS/CC goes back below the "maxCPS"/"maxCC". When delay in the queue gets over "maxDelay", an error is generated. Attributes:
queueId (required) - identifies the queue (see above)
maxDelay (required) - specifies max. delay in the queue
maxCPS (optional) - limits number of calls per second
maxCC (optional) - limits number of concurrent calls
putFirstInQueue (optional, "true"/"false", default is "false") - set to "true" if need to put this call first into the queue. For high-priority calls that need to be dialed urgently
<limitcps queueId="01" maxDelay="10s" maxCPS="40" maxCC="1000" putFirstInQueue="false" />
<!-- after the "limitcps" element(s) you put "call" element(s) -->
<call value="sip:xxx@1.2.3.4" />

log Writes a message to GUI or CLI and to file log. Is used for debugging and reporting.
Attributes:
value (required) - text message to be written into log
level (optional, "debug"/"error", default "debug") - if "error", writes output to "stderr" stream instead of "stdout"
<log value="processing call from CLI/ANI '$callerId;'" />
<callxml type="custom">
 <log value="StarTrinity softswitch processes the call with custom callxml script. Originator ID is: $originatorId;" />
 <log value="A number is $callerId;, B number is $calledId;" />
 <transfer terminators="routed" />
</callxml>

loopbackaudio Plays received (RX stream) RTP audio back to SIP call (TX stream). Is used to verify audio path.
Attributes:
maxtime (optional, default is "infinite") - time of playing. Is set in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix).
<accept value="200" /> <loopbackaudio />

measuresignal Measures min and max audio level of RX RTP stream. Saves result to variables.
Attributes:
maxtime (required) - time of measurement. Is set in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
maxlevelvar (optional) - name of variable to save maximal (peak) signal level in decibels
minlevelvar (optional) - name of variable to save minimal (min. of 10ms-length-frame maximums) signal level in decibels. Is used for audio verification with sine test signals
<accept />
<measuresignal maxlevelvar="max" maxtime="1s" />
<log value="measured audio level for incoming call: max=$max;dB" />
<!-- display measured level in reports and CDR -->
<writecdr header="maxLevelDb" value="$max;" numeric="true" qualityIsAscending="true" />
<!-- CallXML script:
     1) make call to a SIP server, wait for answer. recording is enabled in global settings
     2) make a pause of 1 second to skip noise in beginning of the call
     3) do this 5 times:
      3.1) wait for signal above -40db (expect a tone with same frequencey, 4 different volumes/levels)
      3.2) measure level of signal during 2 seconds, convert measured level to 1 of 4 codes
      3.3) wait for silence below -40db
     4) save the recognized codes to CDR as a column, this CDR is used later to check correctness of played audio files with the tones
-->

 <function name="level2code" level="in" codevar="out">
  <assign var="code" value="X" />
  <switch value="$level;">
    <case from="-35" to="-24">  <assign var="codevar" value="1" /> </case>
    <case from="-24" to="-18">  <assign var="codevar" value="3" /> </case>
    <case from="-18" to="-10">  <assign var="codevar" value="4" /> </case>
    <case from="-10" to="-3">  <assign var="codevar" value="2" /> </case>
  </switch>
 </function>


 <call value="sip:CP000181-14-86553@52.16.126.118:5060" />
 <on event="answer">
  <wait value="1s" />
   <waitforsignal level="-40dB" />
   <measuresignal maxlevelvar="l1" maxtime="2s" />
   <runfunction name="level2code" level="$l1;" codevar="c1" />
   <log value="level1=$l1;dB code1=$c1;" />
   <waitforsilence level="-40dB" />
  
   <waitforsignal level="-40dB" />
   <measuresignal maxlevelvar="l2" maxtime="2s" />
   <runfunction name="level2code" level="$l2;" codevar="c2" />
   <log value="level2=$l2;dB code2=$c2;" />
   <waitforsilence level="-40dB" />

   <waitforsignal level="-40dB" />
   <measuresignal maxlevelvar="l3" maxtime="2s" />
   <runfunction name="level2code" level="$l3;" codevar="c3" />
   <log value="level3=$l3;dB code3=$c3;" />
   <waitforsilence level="-40dB" />

   <waitforsignal level="-40dB" />
   <measuresignal maxlevelvar="l4" maxtime="2s" />
   <runfunction name="level2code" level="$l4;" codevar="c4" />
   <log value="level4=$l4;dB code4=$c4;" />
   <waitforsilence level="-40dB" />

   <waitforsignal level="-40dB" />
   <log value="measuresignal 5" />
   <measuresignal maxlevelvar="l5" maxtime="2s" />
   <runfunction name="level2code" level="$l5;" codevar="c5" />
   <log value="level5=$l5;dB code5=$c5;" />
   <waitforsilence level="-40dB" />

   <writecdr header="codes" value="$c1;$c2;$c3;$c4;$c5;" />
   <log value="level codes = $c1;$c2;$c3;$c4;$c5;" />
  <exit />
 </on>
<call maxtime="35000ms" value="sip:2222@192.168.10.4:5070" codec="G711A" callerId="+331234324234">
 <on event="answer">
  <wait value="1s" /> <!-- wait while audio stream is initializing -->
  <measuresignal minlevelvar="min" maxlevelvar="max" maxtime="5s" />
  <!-- remote side should play a sine signal with same audio level during at least 6 seconds, so min level should be same as max level, if audio path is good -->
  <log value="measured signal: min=$min;dB max=$max;dB" />
  <!-- display measured level in reports and CDR -->
  <writecdr header="maxLevelDb" value="$max;" numeric="true" />
  <writecdr header="minLevelDb" value="$min;" numeric="true" />
  <exit />
 </on>
 </call>

movingAverageGet Gets output of a "moving average", saves it to variable
Attributes:
id (required) - identifies the "moving average"
var (required) - name of variable where to save the output
See example here

movingAveragePut Puts a value into a "moving average", configures number of samples to store for the calculation
Attributes:
id (required) - identifies the "moving average"
size (required) - specifies number of samples to store in the "moving average"
value (required) - input value
See example here

movingAverageReset Resets a "moving average", i.e. removes all previously stored values from memory
Attributes:
id (required) - identifies the "moving average"
See example here

on Handles CallXML events. Sets variable "eventType" and "eventSubType"
The "on" event handler is searched in child XML elements of current element and also in all sibling and parent XML elements. Note: "on" event handler can not be placed inside included callxml files, please have "on" elements in main CallXML file Attributes:
event (required) - type and optionally subtype of the handled event. Types of events are following:
  • answer - answering of outgoing call
  • callfailure - receiving error response for outgoing call
  • dtmf - receiving DTMF signal. Warning: the call flow must not exit an element which is being used to wait for the DTMF event, otherwise it will generate a duplicate CallXML flow in the script
  • error - system error
  • hangup - termination of current SIP call by remote side after answer
  • localHangup - termination of current SIP call by local side after answer
  • cancelled - termination of current incoming SIP call by remote side before answer (when received CANCEL)
  • idleMedia - detection of idle media event (not receiving RTP stream from remote side) - see global setting "IdleMediaTimeToEndSession"
  • maxringtime - ringing timeout
  • pr - receiving provisional response (1xx) to INVITE. Subtype of the event is SIP status code. Examples: "pr:100", "pr:180", "pr:180;pr:183"
  • reinvite - receiving a RE-INVITE from remote side
  • sipinfo - receiving SIP INFO
  • sr - recognizing voice command
  • transferred - answering of outgoing call, which was initiated by receiving REFER
The "event" may contain multiple event types separated by ";". Examples: "maxringtime;callfailure", "pr:180;pr:183"
<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 -->
   <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 -->
  <block test="$global.available; != false"> <!-- 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>
</call>
<log value="making call to the server. it should be configured to answer to 'test' number with no delay" />
<call value="sip:test@localhost:5060" maxringtime="5s" />
<on event="answer">
 <log value="call answered. aborting call" />
 <exit />
</on>
<on event="maxringtime;callfailure">
 <log value="call failed (5-sec timeout or error response). restarting server if did not restart already 3 minutes ago" />
 <block minInterval="3m">
  <sendemail value="mailto:email@gmail.com?subject=call to server failed. restarting the server" />
  <log value="restarting SIP server" />
   <!-- here you should set path to your SIP server -->
  <restartprocess value="C:\Users\User\AppData\Roaming\StarTrinity SipTester\StarTrinity.SIPTester.exe" />
 </block>
 <exit />
</on>
  <!-- read destinations from csv file, make call, set max timeout to get 200OK response = 950ms (if no answer in 950ms, send CANCEL) -->
<call value="$seq_sip_uri_from_csv(C:\StarTrinity\destinations.csv, 0);" maxringtime="950ms" />
 <on event="pr:180;pr:183" >
  <!-- this handles 180 Ringing and 183 Session Progress responses from destination -->
  <block probability="0.5">
    <!-- this code will be executed for 50% of 180 and 183 responses -->
    <exit /> <!-- this sends CANCEL -->
  </block>
 </on>
 <on event="answer">
  <!-- when SIP call is answered, play an audio file for 90 seconds -->
  <playaudio value="music.wav" repeat="10000" maxtime="90s" />
  <!-- end the call (send BYE) -->
  <exit />
 </on>

params Declares parameters for the script
Parameters are read-only, their purpose is to have user-editable configurations for script in a separated place. There can be multiple declarations of params in script. The params can be declared in an included callxml file, or in parent callxml file. Params aren't like variables. They are the one (or few) section(s) of the code, where the adjustable params are. Attributes:
[none]
<params>
 <param name="param1" value="value1" />
 <param name="param2" value="value2" />
</params>

<log value="param1 = $param.param1;. param2 = $param.param2;" />

param Is used within "params"; defines a parameter which can be used later in script
Attributes:
name (required) - name of the parameter
value (required) - value of the parameter

performAAA Performs authentication, authorization and accounting for an incoming SIP call. Sets CallXML variables "originatorId", "tenantId", "language"
Uses integrated billing engine, 'Originator' entities. Sets variable 'balance', 'language', 'originatorId', 'tenantId'
Attributes:
var (optional) - variable where to save authenticated originator ID
<!-- simplest softswitch script for GSM termination and wholesale -->
<performAAA />
<accept value="183" />
<transfer terminators="routed" />

playaudio Plays audio file from specified WAV/MP3 file/URL. Exits on end of file or end of silence (if "maxsilence" is specified), unless "dontwait" is set to "true"
The files are pre-cached into memory before playback, at startup time. If file name is dynamic and the audio file does not exist in the cache, it is cached at runtime. The caching includes reading audio file from disk and encoding it into RTP payload using appropriate codec. When transferring (in Softswitch), the audio is played to both call legs: A and B (if available).
See also: controlaudio Attributes:
value (required, if no attribute "valuePattern") - absolute or relative audio file name(s) or URL(s). Multiple file names or URLs are separated by semicolon (example: speech.wav;music.wav). If relative file name is specified, in multitenant mode first it tries to locate a tenant-specific audio file in \[tenantId]\ subfolder, and if it is not found, it uses file from program root folder
maxtime (optional, default is "unlimited") - max time of playing. Is set in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix).
repeat (optional, default is "1") - number of times to repeat audio file
valuePattern (optional) - pattern for the file name. "?" is replaced by digit
valuePatternRandomSeed (optional) - any string data used to initialize random generator for "valuePattern"
conference (optional) - ID of conference where to play audio file. If not set, audio file is played only to current SIP call
updateCacheFromDisk (optional, "true"/"false", default is "false") - if set to "true", checks file last modification time and updates RAM cache when file is modified
dontwait (optional, "true"/"false", default is "false") - if set to "true", control is returned immediately, before ending of audio file. In this case audio is still played during execution of next CallXML elements. It can be stopped using "stopaudio"
leg (optional, "A"/"B"/"both", default is "both") - during call transfer in StarTrinity Softswitch, specifies call leg: A=origination side or B=termination side
mode (optional) - if set to "siprec", the "playaudio" expects to open a stereo WAV file (8kHz, 16bit) to play it into the 2 RTP streams for SIPREC testing. see sample CallXML script. If set to "" (empty), mono WAV file is played to 1st RTP stream of a SIPREC test call. If set to "siprec2", mono WAV file is played to 2nd RTP stream of a SIPREC test call.
<playaudio value="C:\music\01.mp3" maxtime="10m" repeat="infinite" >
<log value="making call to server" />
<call callerId="test" value="sip:9999@server.com:5060" codec="G711A" />
<on event="pr:183">
 <log value="received 183 Session Progress, playing early media to the server" />
 <playaudio value="C:\early_media_tx.wav" dontwait="true" />
</on>
<on event="answer">
 <log value="call answered" />
 <exit />
</on>
<accept value="183" /> <playaudio value="ringbacktone.wav" dontwait="true" /> <!-- do something here: request database, read from file, etc --> <stopaudio /> <accept value="200" />

playdtmf Sends one or many DTMF digits to current SIP call. Returns control immediately. If "UseRFC2833ToSendDTMF" setting is set to "1", sends DTMF within RTP stream (according to RFC2833), otherwise uses SIP INFO method. If you need to send audible DTMF signals, please use "playaudio" and pre-recorded WAV files with DTMF
See also: sendsiprequest Attributes:
value (required) - DTMF digits to send. If more than one digits are specified, time between digits is set by "DtmfSendingIntervalMs" setting (default is 200ms). The value may contain 'p' character which means 1-second pause between DTMF digits
signaldelayvar (optional) - name of variable where to save audio response delay value in milliseconds. If set, the "playdtmf" waits for audio response with signal level "DefaultSignalDetectorThresholdDb" (set in settings).
method (optional, "sipInfo"/"rfc2833", default from global settings) - method to send the DTMF
<playdtmf value="1">
<wait value="500ms">
<playdtmf value="2">
<wait value="1000ms">
<playdtmf value="34p5">
<wait value="$rand(10,5000);ms"> <playdtmf value="#">
<playdtmf value="1">
<playaudio value="played_1.wav"> <!-- play audio file to hear it in recording, for debugging purposes -->
<wait value="5000ms">
<playdtmf value="2">
<playaudio value="played_2.wav">
<wait value="10000ms">
<playdtmf value="1" />
<log value="sent DTMF digit 1" />
<waitforsignal signaldelayvar="ivrDelay"/>
<log value="IVR response in RTP audio is $ivrDelay;ms" />
<playdtmf value="1" signaldelayvar="ivrDelay" />
<log value="IVR response in RTP audio is $ivrDelay;ms" />
<playaudio value="http://startrinity.com/speech.wav" repeat="infinite" >

readcsv Reads a row from CSV file, stores fields into variables
Progress of reading the CSV file is displayed in SIP Tester's GUI on "reports/statistics" tab. If the entire CallXML script is executed, but “readcsv" element is not executed, the CSV reader is left in current position. CSV readers are shared between sessions, file data is cached into memory. CSV file must have ASCII encoding. CSV fields delimiter is taken from "CsvDelimiter" global setting. See also: "readdb" Attributes:
value (required) - absolute or relative CSV file name, or HTTP/HTTPS URL
var[columnIndex] (required) - names of variables to store fields from row. Zero-based [columnIndex] identifies column.
mode (optional, "sequential"/"random", default is "sequential") - mode of reading rows in CSV file
countsColumnIndex (optional) - zero-based index of column which contains count of reads for each row. Is used to read some rows more than one time.
skipHeaders (optional, "true"/"false", default is "false") - indicates whether to skip first row with headers
repeat (optional, default is "1") - number of times to repeat the whole CSV file. "infinite" to repeat file infinitely
repeatCounterVar (optional) - variable to save the repeat counter. The counter starts from zero and gets incremented with every pass of entire CSV file
eofMode (optional, "error" or "emptyValues", default "error") - specifies what to do when there are no more rows to read in file (EOF) and when "repeat" counter is finished, also when "rowIndex" is out of bounds. "error" - raises 'error' event; "emptyValues" - return empty field values
rowIndex (optional) - zero-based row index. If not set, global pointer is used. The global counter is incremented with every read.
<readcsv value="c:\list.csv" var0="resultField0" var1="resultField1" var2="resultField2" repeat="3" />
<on event="error">
 <log value="CSV EOF, 3 times repeated all rows" />
</on>
<readcsv value="list.csv" var0="callerIdFromCsv" var1="calledIdFromCsv" countsColumnIndex="2" mode="random" />
<call value="sip:$calledIdFromCsv;@10.10.10.1" callerId="$callerIdFromCsv" />
<readcsv value="c:\01.csv" mode="random" var0="dialNumber" var1="cli" var2="pin" skipHeaders="true" repeat="infinite" />
<call value="sip:$dialNumber;@10.10.10.10:5060" callerId="$cli;" />
<on event="answer">
 <wait value="500ms" />
 <playdtmf value="$pin;#" />
 <playaudio value="$randswitch(c:\01.wav,c:\02.wav,c:\03.wav);" maxtime="$rand(10,20);s" />
 <exit />
</on>
<switch>
 <case probability="50" >
  <call maxringtime="7000ms" value="$seq_sip_uri_from_csv(C:\Users\Administrator\Desktop\Data\XXXXXXXXXXX.csv, 1);" />
 </case>
 <case probability="50" >
  <call maxringtime="7000ms" value="$seq_sip_uri_from_csv(C:\Users\Administrator\Desktop\Data\YYYYYYYYYYY.csv, 1);" />
 </case>
</switch>
<on event="answer">
 <playaudio value="music.wav" maxtime="10s" />
 <exit />
</on>
<!-- 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>
<!-- 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 -->
<if test="$repeatCounter1; == 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>

readdb Executes a database query, returns rows one by one, stores fields into variables
The database request is done via ODBC drivers to MSSQL, MySQL, PostgreSQL, other databases. Database readers are shared between sessions, queried records are cached into memory. See also: "readcsv" Attributes:
value (required) - SQL query to execute
odbcConnection (required) - ODBC connection string
var[columnIndex] (required) - names of variables to store data fields. Zero-based [columnIndex] identifies column.
repeat (optional, default is "1") - number of times to repeat the queried records. "infinite" to repeat file infinitely
reloadOnRepeat (optional, "true" or "false", default is "false") - need to reload data from database when queried records are repeated
<readdb value="select Number from NumbersToDial" odbcConnection="Driver={SQL Server};Server=server.com\SQLEXPRESS;Database=Test;Uid=sa;Pwd=abcxyz;" var0="number" repeat="infinite" reloadOnRepeat="false" />
<log value="read number from database: $number;" />
<call value="sip:$number;@12.34.56.67">
 <on event="answer" >
  <playaudio value="music.wav" />
  <exit />
 </on>
</call>
<readdb value="select Number, ServerIP from NumbersToDial" odbcConnection="Driver={SQL Server};Server=server.com\SQLEXPRESS;Database=Test;Uid=sa;Pwd=abcxyz;" var0="number" var1="serverIp" repeat="infinite" reloadOnRepeat="false" />
<log value="read number from database: $number;@$serverIp;" />
<call value="sip:$number@$serverIp;">
 <on event="answer" >
  <playaudio value="music.wav" />
  <exit />
 </on>
</call>

readnumberlist Reads a row from number list file, stores fields into variables
Is used with dialer campaigns in StarTrinity softswitch and with API method "UploadNumberList" in StarTrinity SIP Tester. The number list readers are shared between CallXML sessions, but are kept separate between softswitch tenants. File data is cached into RAM for high performance. CSV file must have ASCII encoding. CSV fields delimiter is ";" or ",". See also: "readdb", "readcsv" Attributes:
value (required) - identifier of number list, its file name
mode (optional, "sequential"/"random", default is "sequential") - mode of reading rows in the number list
singleRowRepeatCount (optional, default is "1") - number of times to repeat every read row
var[columnIndex] (required) - names of variables to store fields from row. Zero-based [columnIndex] identifies column.
repeatInfinitely (optional, "true"/"false" default is "false") - set to "true" to repeat the number list infinitely
<readnumberlist value="a_numbers_txt" var0="cli" />
<log value="read CLI $cli;" />

receivefax Initiates RE-INVITE with T.38 fax SDP offer, receives T.38 fax to file.
Does not return control untile fax operation is complete. If the fax operation fails, raises an "error" event, it could be handled in CallXML script Attributes:
value (optional) - file name where to save received fax. If not set, unique file name will be generated
<receivefax />
<receivefax value="C:\receivedfax.tiff" />

recordcall Switches on/off recording for current SIP call or conference.
Returns control immediately. Recording is started only when RTP media session is established. Audio is recorded from mix of RX and TX audio streams of current SIP call, and from mix of RX streams of all calls in conference. Recorded wav file name pattern is configured with settings. Attributes:
value (required) - percentage of SIP calls to be recorded. If "100", always starts recording; if "0" always stops recording
conference (optional) - ID of conference for recording. If not set, only current SIP call is recorded
uploadToUrls (optional) - semicolon-separated list od URLs where to upload the recorded files. The software sends HTTP POST with form fields "recorded_file" and "sip_call_id" and deletes the recorded file after successful upload. This can be used to get the recording at your custom HTTP server
basepath (optional) - folder for recorded files
mode (optional, "rx", "tx", default "mix") - source of audio data for recording. "rx" - audio received from remote side, "tx" - audio transmitted to remote side, "mix" - mix of "rx" and "tx"
recorderId (optional, default is "") - unique identifier of the recorder, is used when multiple recorders are used for one call
<recordcall value="100" basepath="F:\recordings" />
<recordcall value="100" uri="c:\recorded_files\$time();_$callerId;.wav" />
<recordcall value="100" conference="01" />
<recordcall value="0" /> <!-- stop recording -->

recordmessage Records audio message e.g. for voicemail, optionally detects silence
Returns control after message is recorded. Recording is ended by pressing any DTMF key, if "finalkeys" parameter is not specified. Recording is also ended when silence is detected (when person is no longer speaking) if "stopOnSilenceLevelDb" and "stopOnSilenceMinimalSilentDuration" parameters are specified. Attributes:
value (required) - path to new recorded file
recorderId (optional, default is "") - unique identifier of recorder, is used when multiple recorders are used for one call
finalkeys (optional) - DTMF keys which end the recording, example: #* - both # and * digits end the recording. By default any DTMF key stops the recording
maxtime (optional) - maximal duration of the recording in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
stopOnSilenceLevelDb (optional) - silence detection threshold level in dB. "0" corresponds to max level, "-6" to 50%, recommended value is "-24"
stopOnSilenceMinimalSilentDuration (optional) - minimal duration of input audio below the "stopOnSilenceLevelDb" before stopping the recording. Recommended value is "3s"
<recordmessage value="d:\recordings\$time(yyyyMMdd_HH_mm_ss_fff);.wav" />
<recordmessage value="d:\recordings\$time(yyyyMMdd_HH_mm_ss_fff);.wav" maxtime="3m" stopOnSilenceLevelDb="-24" stopOnSilenceMinimalSilentDuration="3s" />

redirect Redirects incoming SIP call to new destination. Sends "302 Moved Temporarily" response with new contact.
Attributes:
value (required) - SIP URI with new contact
<redirect value="sip:1000@10.10.10.1" />

regexsearch Searches for patterns in strings using regular expressions
Uses System.Text.RegularExpressions.Regex.Match method from Microsoft .NET library Attributes:
value (required) - input string
regex (required) - regular expression. Nnote that it should be XML-escaped, i.e. '<' and '>' should be replaced with '&lt;' and '&gt;'
var (required) - list of variables' names to store results
<regexsearch value="ABCD 123 456 789"
  regex="ABCD\W*(?&lt;digits1&gt;\d+)\W*(?&lt;digits2&gt;\d+)\W*(?&lt;digits3&gt;\d+)" var="digits1;digits2;digits3" />
<log value="digits1='$digits1;', digits2='$digits2;', digits3='$digits3;'" />
<regexsearch value="$sipheadercontact;" regex="@(?&lt;sip_contact_address&gt;[^;]*)" var="sip_contact_address" />
<regexsearch value="asdasg s dfghdfghdfgh 777 asdf asd asf" regex="[0-9]+" var="digits" />
<log value="found digits: $digits;" />
<call value="sip:$randdigits(10);@1.2.3.4" callerId="$randdigits(7);" maxringtime="100s" var="r" codec="G711A" fromTag="TEST$randdigits(10);">
 <on event="answer">
   <log value="received To header '$sipHeaderTo;'" />
   <regexsearch value="$sipHeaderTo;" regex=";tag=(?<toTag>\S*)" var="toTag" />
   <log value="received To header tag = '$toTag;'" />
   <wait value="300s" />
   <exit />
  </on>
</call>

register Sends REGISTER, waits for response, saves status to a variable. Measures delay between sending "REGISTER" request and receiving "200 OK" response
Attributes:
value (required) - SIP URI of destination. SIP URI can contain user and password for authentication, "transport" query parameter ("udp"/"tcp"/"tls", "udp" is default), "proxyAddress" and "proxyPort" query parameters
var (optional) - name of variable to store response status code
delayvar (optional) - name of variable to store response delay in milliseconds
expires (optional) - value of "Expires" SIP header. Default is 3600 (seconds). If set to 0, the REGISTER request means un-registration
headers (optional) - list of custom SIP headers to be included into the REGISTER request.
Example: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
localSipPort (optional) - explicitly set local SIP/UDP transport port. Is used with global settings "LocalSipPort", "LocalSipPortRange"
localSipAddress (optional) - explicitly set local SIP IP address, is used to select network interface. Is used with global setting "LocalSipAddresses"
contactHeaderFormat (optional) - custom Contact header format. Example: "Eran%20Younger" <sip:[userId]@[localIp]:[localPort];transport=TLS;ob>;reg-id=1;+sip.instance="<urn:uuid:2c72cde9-c1d4-321d-8727-9bb0e165519f>"
sipCallId (optional) - custom Call-ID header to put into REGISTER request packet. Is used to link unregistration REGISTER request to registration REGISTER request.
<log value="sending REGISTER..." />
<register value="sip:100@192.168.0.17?user=100&amp;password=123456" expires="180" var="status" delayvar="delay" />
<log value="received response code = $status;, delay = $delay;ms" />
<register value="sips:$rand(100,200);@192.168.10.4:5061?transport=tls" var="status" />
<register value="sip:555@startrinity.com" contactHeaderFormat="sip:666@23.45.56.78:7895" />
<log value="sending un-REGISTER (expires = 0)..." />
<register value="sip:100@192.168.0.17?user=100&amp;password=123456" expires="0" var="status" delayvar="delay" />
<log value="received response code = $status;, delay = $delay;ms" />
<register value="sip:+16509090910@mydomain.net?user=%2B165090909100&amp;password=1230&amp;proxyAddress=mydomain2.net0&amp;proxyPort=5060" expires="3600" var="result" delayvar="delay" />
<register value="sip:$rand(400,200);@192.168.10.4:5060?user=%2B165090909100&amp;password=1230&amp;transport=udp" localSipAddress="192.168.10.$rand(1,4);" localSipPort="506$rand(0,9);" var="status" />

reinvite Sends RE-INVITE. Is used to put SIP call on hold (call parking feature)
See also: "update" Attributes:
direction (optional, "SendOnly"/"ReceiveOnly"/"None"/"Both") - RTP media stream direction. The meaning of the direction in SDP is a little bit confusing. It is explained in RFC3264. If one side (A) sends "recvonly" in its SDP offer, the other side (B) should say "sendonly" (opposite) in its SDP answer. After that (when SIP call is put on hold), A "receives only, not sends" from B, and B "sends only, not receives" to A, in other words RTP stream flows in one direction: from B to A, microphone at A is muted
sendSdp (optional, "true"/"false", default "true") - send SDP in the RE-INVITE packet. "false" is used to test case of SDP offer in "200 OK" and SDP answer in "ACK"
localRtpAddress (optional) - a custom IP address to put into SDP. Is used for test purposes
codec (optional, "G711A"/"G711U"/"G723"/"G729", default is "current") - new RTP media codec (SDP media stream payload type) to be sent in the RE-INVITE SDP
<reinvite direction="ReceiveOnly" />
<call value="sip:test@10.10.10.10" /> <!-- make call with all available codecs declared in SDP -->
<on event="answer">
 <playaudio value="music.wav" maxtime="5s" />
 <reinvite codec="G729" /> <!-- change codec to G729 -->
 <playaudio value="music.wav" maxtime="5s" />
 <reinvite codec="G711A" /> <!-- change codec to G711A -->
 <playaudio value="music.wav" maxtime="5s" />
 <exit />
</on>

reject Rejects incoming SIP call before answering. Sends response with custom SIP status code.
Attributes:
value (optional, default is "603") - SIP status code for the response
headers (optional) - list of custom SIP headers to be included into the INVITE message.
Example: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
<reject value="486" />
<reject value="486" headers="Reason=Q.850;cause=17" />
<reject value="302" headers="Contact=sip:152@192.168.0.56" />

replacestring Performs text replacement
Attributes:
value (required) - input text
var (required) - name of variable where to save result
old (required) - old text to be found and replaced
new (required) - new text
<replacestring value="this is original text" old="initial" new="new" var="result" />
<log value="result of replacement is: $result;" />

report Saves custom performance indicator to SIP Tester's GUI and HTML report
See also: "writecdr" Attributes:
name (required) - name of the performance indicator which will be displayed in report
value (required) - numeric value of the performance indicator
qualityIsAscending (optional, "true"/"false") - indicates whether call quality increases or decreases with increasing of the indicator. Is used to calculate percentiles and list of worst quality calls.
<playdtmf value="1" />
<waitforsignal signaldelayvar="ivrDelay"/>
<report name="IVR_delay_1" qualityIsAscending="false" value="$ivrDelay;" />

requestcsv Makes a fast (RAM-based) lookup in a CSV file
The "requestcsv" first reads CSV file into memory cache, builds index and then for subsequent requests uses the cache. The cache can be reset with a button using web UI or desktop GUI. System setting "CsvDelimiter" is used to parse CSV files. See also: "requestdb" Attributes:
value (required) - file name or URL of CSV file
column0 (required) - value of first column in CSV file (index #0), key to make the lookup
column1var (required) - name of CallXML variable where to save result. If key was not found - an empty value is saved as result. If multiple values found for same key - random value is returned.
rereadAfter (optional) - max time to use cached CSV data, before re-reading the CSV file. Example: 60m
<requestcsv value="C:\CSV\myCliDictionary.csv" column0="$callerId;" column1var="result" />
<log value="query result for $callerId;: $result;" />

requestdb Executes MSSQL command (select, insert, delete statements, stored procedures). Stores fields from the first requested row into variables. If no rows returned, saves empty values
The "requestdb" is executed even if current SIP call is disposed, independently from SIP thread. If no connection string is set by parameters, CDR connection string from settings is used. See also: "requestcsv" Attributes:
connection (optional) - connection string to MSSQL server, contains name of server, name of database, authentication parameters. Example: Data Source=(local)\SQLEXPRESS;User ID=sa;Password=123;Initial Catalog=db1;Asynchronous Processing=true
odbcConnection (optional) - ODBC connection string to database server. Examples: Driver={SQL Server};Server=localhost\SQLEXPRESS;Database=testCDR;Uid=sa;Pwd=pass;,
command (required) - SQL command text. If not set by XML attribute, the command text is taken from inner XML text (see example)
var[columnIndex] (required) - names of variables to store results returned by MSSQL server
<requestdb command="exec SaveCallerId '$callerId;', 'Test', 'Test'"
    connection="Data Source=(local);User ID=sa;Password=123456;Initial Catalog=DtmfTest;Asynchronous Processing=true"
    var0="resultField0" var1="resultField1" var2="resultField2" />
<inputdigits var="enteredNumber" maxsilence="20s" maxdigits="10" />
<requestdb command="select InfoMessage from Table1 where PinCode = '$enteredNumber;'"
 connection="Data Source=(local)\SQLEXPRESS;User ID=sa;Password=123;Initial Catalog=db1;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 -->
<requestdb odbcConnection="Driver={SQL Server};Server=startrinity.com\SQLEXPRESS;Database=TestCDR;Uid=sa;Pwd=asv2015HJLK;" var0="f0" var1="f1" var2="f2">
 select top 1 callerId, calledId, created from StartrinitySipTesterCdrs order by created desc
</requestdb>
<log value="result from database: callerId = $f0;, calledId = $f1;, created = $f2;" />
<requestdb odbcConnection="Driver={MySQL ODBC 5.3 ANSI Driver}; Server=91.121.146.1;Database=mor; User=usr1; Password=pass1; Option=3;" var0="f0">
 SELECT `src` FROM `calls` WHERE `calldate` > DATE_SUB(NOW(), INTERVAL 48 HOUR) AND `localized_dst` LIKE '%09299802' LIMIT 1
</requestdb>
<log value="result from MySQL MOR CDR database: callerId = $f0; (empty if not found)" />

resetrtpmeasurements Resets RTP measurement state of current SIP call. Is used to have multiple independent RTP measurements for one SIP call
See also: "getrtpmeasurements" Attributes:
[none]
<accept />
<wait value="20s" />
<getrtpmeasurements />
<log value="measurement 1: caller-called RTP stream: sdp-rtp delay: $SDP_RTP_Caller_Delay;ms, packet loss: $RTP_Caller_LostPackets;%, max delta: $RTP_Caller_MaxDelta;ms, max rfc3550 jitter: $RTP_Caller_MaxRfc3550Jitter;ms, G.107 MOS: $RTP_Caller_G107MOS;" />
<log value="RTCP measurements 1: caller max jitter: $RTCP_Caller_Jitter_Max;ms; caller packet loss: $RTCP_Caller_LostPackets;%, called max jitter: $RTCP_Called_Jitter_Max;ms; called packet loss: $RTCP_Called_LostPackets;%, max round trip delay: $RTCP_RTT_Max;ms" /> <resetrtpmeasurements />
<wait value="20s" />
<getrtpmeasurements />
<log value="measurement 2: caller-called RTP stream: sdp-rtp delay: $SDP_RTP_Caller_Delay;ms, packet loss: $RTP_Caller_LostPackets;%, max delta: $RTP_Caller_MaxDelta;ms, max rfc3550 jitter: $RTP_Caller_MaxRfc3550Jitter;ms, G.107 MOS: $RTP_Caller_G107MOS;" />
<log value="RTCP measurements 2: caller max jitter: $RTCP_Caller_Jitter_Max;ms; caller packet loss: $RTCP_Caller_LostPackets;%, called max jitter: $RTCP_Called_Jitter_Max;ms; called packet loss: $RTCP_Called_LostPackets;%, max round trip delay: $RTCP_RTT_Max;ms" />

resetstatistics Resets global statistics of processed SIP calls; resets all moving averages
Attributes:
[none]
<resetstatistics />

restartprocess Restarts a windows process
Is used to monitor availability of SIP server and restart it if test calls fail Attributes:
value (required) - full path to executable file
<log value="making call to the server. it should be configured to answer to 'test' number with no delay" />
<call value="sip:test@localhost:5060" maxringtime="5s" />
<on event="answer">
 <log value="call answered. aborting call" />
 <exit />
</on>
<on event="maxringtime;callfailure">
 <log value="call failed (5-sec timeout or error response). restarting server if did not restart already 3 minutes ago" />
 <block minInterval="3m">
  <sendemail value="mailto:email@gmail.com?subject=call to server failed. restarting the server" />
  <log value="restarting SIP server" />
   <!-- here you should set path to your SIP server -->
  <restartprocess value="C:\Users\User\AppData\Roaming\StarTrinity SipTester\StarTrinity.SIPTester.exe" />
 </block>
 <exit />
</on>

run Generates a new CallXML session. Copies all variables from current session to the new session. The "run" XML element should contain child XML elements to be executed by new session.
Attributes:
var (optional) - name of variable to store ID of new session
<block repeat="5">
   <run var="newSessionId">
     <call value="sip:$Id;@192.168.0.1" />
     <on event="answer">
       <playaudio value="music" />
     </on>
   </run>
   <log value="generated new session, ID = $newSessionId;" />
</block>
<assign var="ParentSessionID" value="$id;"/>
<assign var="NumToCall" value="sip:152@192.168.0.56"/>
<run var="secondarySessionId" >
  <call value="$NumToCall;" to="$NumToCall;" callerId="123" maxringtime="100s" />
  <on event="answer" >
    <sendevent value="answer" session="$parentSessionId;" />
    <conference value="$Id;" />
  </on>
  <on event="callfailure">
   <log value="call failed with status $lastError;" />
   <sendevent value="callfailure" session="$parentSessionId;" />
  </on>
</run>
<playaudio value="ringbacktone.wav" />
<on event="externalevent:answer" >
 <accept />
 <conference value="$eventsenderId;" />
</on>
<on event="externalevent:callfailure" >
 <exit />
</on>

runfunction Executes a function
Attributes:
name (requierd) - unique name of function
[parameters] (optional) - values of input parameters, names of variables to store output parameters
<function name="func1" param1="in" param2="in" resultvar="out" >
 <log value="func1: param1 = $param1;, param2 = $param2;" />
 <assign var="resultvar" value="$param1;: OK" />
</function>

<runfunction name="func1" param1="TestValue1" param2="TestValue2" resultvar="result" />
<log value="result=$result;" />

runprocess Runs an .exe or .bat file with custom command line arguments. Saves console output and process exit code into variables. Is used for integration with third party tools
Attributes:
value (required) - path to executable file
args (optional) - command line arguments
exitcode (optional) - name of variable to store exit code. Normal exit code is "0"
user (optional) - name of Windows user in case if you need to run .exe as different user
password (optional) - password of Windows user in case if you need to run .exe as different user
workingdirectory (optional) - working directory for .exe file
<runprocess value="C:\folder\something.exe" args="plink -ssh connectremote -l testuser" stdoutput="stdoutput" exitcode="exitcode" user="xxx" password="yyy" />
<log value="executed something.exe. stdoutput = '$stdoutput;', exitcode = '$exitcode;'" />

runtenantscript For multitenant softswitch or PBX: runs custom tenant's script
Attributes:
none
<runtenantscript />

say Speaks text using a Microsoft Speech API 5 engine. Waits until the engine speaks all the text. Text is set by "value" attribute or by child XML elements
You may need to install SAPI5 SDK. Note: default TTS engine that comes with Windows Server 2008 may cause memory leak and crash. Attributes:
value (optional) - text to be spought
voice (optional) - identifies TTS speaker
conference (optional) - ID of conference where to speak the text. If not set, test is spought only to current SIP call
nowait (optional, "true"/"false", default is "false") - if set to "true", control is returned immediately, before end of speaking text. In this case text is still spought during execution of next CallXML elements
<say voice="Microsoft Anna" value="Welcome to the startrinity.com SIP server with text to speech functionality" />
<say>
  <voice required="NAME=Microsoft Mike">you are calling from $callerId;</voice>
</say>
<say voice="Microsoft Mike" >
  you are calling from $callerId; to $calledId;
</say>

searchfile Search for random file in a directory
Attributes:
directory (required) - absolute or relative path to directory
var (required) - name of variable where to save file name
<searchfile directory="d:\recordings" var="fn" />
<playaudio value="$fn;" />

sendemail Sends email using SMTP server, returns control immediately. Connection to SMTP server is configured on settings screen Note that subject and body text have to be escaped
Attributes:
value (required) - "mailto" URI of destination
<sendemail value="mailto:user@server.com?subject=call from $callerId;&amp;body=test body" />
<playdtmf value="1" />
<waitforsignal signaldelayvar="ivrDelay" maxringtime="3000"/>
<if test="$ivrDelay; &gt;= 3000">
 <sendemail value="mailto:user@server.com?subject=IVR timeout: $time();&body=Timeout in IVR1" />
</if>
<inputdigits value="c:\wav\ivr.wav" var="d" maxdigits="1" maxsilence="10s" />
<if test="$d; = 1" > <sendemail value="mailto:user@server.com?subject=call from $callerId;&amp;body=user pressed 1" /> </if>
<if test="$d; = 2" > <sendemail value="mailto:user@server.com?subject=call from $callerId;&amp;body=user pressed 2" /> </if>

sendevent Sends external event to another (destination) session. Sets "eventsenderId" variable to the destination session. The external event should be handled with <on event="externalevent:[subType]"> handler or "waitforevent" element.
Optionally sends variables into destination session. The CallXML variables are set using XML attributes within the "sendevent" element. To send events between different instances of SIP Tester|see web API method "SendCallxmlEvent" and element "sendhttprequest" Attributes:
value (optional) - eventID, ID/subtype of the external event. The event ID is accessible using CallXML script from variable "eventSubtype", or using "value" attribute
session (optional) - ID of the destination session. If not set, sends events to all current sessions
calledId (optional) - called ID of SIP call in destination session
callerId (optional) - caller ID of SIP call in destination session
<assign var="conferenceId" value="conf_$Id;" />
<sendevent session="$generatedSessionId;" value="join_to_conference" />
<!-- warm transfer unit test - using REFER with complex Replaces header -->
<readcsv repeat="infinite" value="C:\StarTrinity\2steptest.csv" var0="from" var1="to_name" var2="sbc_ip" var3="sbc_port" var4="password" var5="reffile" var6="xferext" var7="password2" />

<assign var="to" value="sip:$to_name;@$sbc_ip;:$sbc_port;?user=$from;&password=$password;" />
<log value="calling from $from; to $to;" />
<!-- from: (A) who initially makes call (agent); to - (B) customer; xferext - (C) supervisor
   finally customer will be connected with supervisor (B to C)
-->


<!-- generate random IDs -->
<assign var="fromTag" value="$randdigits(10);" />
<assign var="callIdC" value="$randdigits(10);" />

<!-- make a call from agent to customer -->
<call value="$to;" callerId="$from;" headers="X-Attributes=*;test=A014" testId="A014" sipCallId="$callIdC;" fromTag="$fromTag;" />
 <on event="answer">
  <wait value="2s" />
  <run var="newSessionId">
   <!-- call from agent (A) to supervisor (C) in a new (independent) CallXML session -->
   <call value="sip:$xferext;@$sbc_ip;:$sbc_port;" sipCallId="$callIdC;" />
   <on event="answer">
    <!-- call C answered: extract 'To' header tag from '200 OK' SIP packet. Note: you can also handle "pr:180" or "p3:183" event, instead of "answer" -->

    <log value="received To header '$sipHeaderTo;'" />
    <regexsearch value="$sipHeaderTo;" regex=";tag=(?<toTag>\S*)" var="toTag" />
    <log value="received To header tag = '$toTag;'" />

    <!-- call C answered: pass 'To' header tag into main CallXML session -->
    <sendevent value="answer" session="$parentSessionId;" toTag="$toTag;" />

    <playaudio value="music.wav" />
    <exit/>
   </on>
  </run>

  <wait value="30s" /> <!-- wait for 'c_answered' event from the secondary session, max. 30 seconds -->
  <exit/> <!-- exit the script on timeout, this should not happen during normal test -->

  <on event="externalevent:c_answered" >
   <log value="main callxml session: got 'c_answered' event from secondary session. toTag = '$toTag;' -->
   
   <!-- send REFER passing the C number, and IDs -->
   <transfer value="<sip:$xferext;@$sbc_ip;:$sbc_port;;user=phone?Replaces=$callIdC;%3Bto-tag%3D$toTag;%3Bfrom-tag%3D$fromTag;>" mode="blind" dontwait="true" />
  
   <wait value="11s" />
   <exit /> <!-- abort call (from agent (A) to customer (B)) -->
  </on>
</on>

sendfax Initiates RE-INVITE with T.38 fax SDP offer, sends fax from TIFF image file
Does not return control untile fax operation is complete. If the fax operation fails, raises an "error" event, it could be handled in CallXML script.
Default installation contains a file "sample_fax.tiff" for tests Attributes:
value (required) - subtype of the external event
<sendfax value="C:\fax\01.tiff" />

sendhttprequest Sends HTTP/HTTPS request to a web server
Is used to integrate with third-party APIs (HLR lookups, etc), exchange data and signals between SIP Tester instances. Note: you can analyse the API response using regexsearch Attributes:
value (required) - HTTP URL where to send the request
maxtime (optional) - HTTP request timeout. example: 1000ms
contentvar (optional) - name of variable where to store downloaded HTTP message body
delayvar (optional) - name of variable where to store measured delay of HTTP response (in milliseconds)
statusvar (optional) - name of variable where to store HTTP response status code
user (optional) - user name for authentication
password (optional) - password for authentication
headers (optional) - list of custom HTTP headers to be included into the HTTP request. Example: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
tlsversion (optional) - TLS version: "1.0", "1.1" or "1.2". Note: may require restart of the software in some cases
method (optional, "GET"/"POST", default is "GET") - HTTP method to use. If using "POST", the software sends inner content of the "sendhttprequest" XML elements to the web server (see examples). Inner "CDATA" element can be used to send HTTP POST with JSON data.
<sendhttprequest value="http://google.com" contentvar="c" delayvar="d" statusvar="s" />
<log value="HTTP test result: delay=$d;ms, HTTP status code = $s;, content: $c;" />
<sendhttprequest value="https://yourserver.com/savetestresult.aspx?token=$token;" method="POST" contentvar="c" delayvar="d" statusvar="s">
 <result>
  <callxmlSessionId value="$id;" />
  <status value="$status;" />
 </result>
</sendhttprequest>
<log value="HTTP POST delay=$d;ms, HTTP status code = $s;, returned content: $c;" />
<sendhttprequest method="POST" value="https://api.hlrlookup.com/apiv2/hlr" contentvar="c" delayvar="d" statusvar="s">
<![CDATA[{
"api_key":"xxxx",
"api_secret":"yyyy",
"requests":
[
{"telephone_number": "$callerId;",
"cache_days_private":0,
"get_landline_status":"NO",
"get_imsi_hash":"NO"
}
]
}
]]>
</sendhttprequest>
<log value="API request delay=$d;ms, HTTP status code = $s;, returned $c; " />
<log value="sending request to another instance of SIP Tester to check if call exists there from 'test' to 'test'" />
<sendhttprequest value="http://10.10.10.10:19019/API/MainViewModel/CurrentCallExists?callerId=test&amp;calledId=test" user="admin" password="123456" contentvar="r" />
<log value="result: $r;" />
<log value="sending request to another instance of SIP Tester to create 2 synchronous calls. the another instance will send a HTTP request to your web server to get script for the second call" />
<sendhttprequest value="http://siptester-instance-2:19019/API/MainViewModel/CreateCall?url=http://your-web0server/script.xml&user=admin01&amp;password=passw01" user="admin" password="123456" />
<log value="sent request to the second instance. now making a call from this (first) instance" />
<call value="sip:test@192.168.10.56" callerId="test">
 <on event="answer">
  <playaudio value="music.wav" maxtime="20s" />
  <exit />
 </on>
</call>
<sendhttprequest value="http://startrinity.com" headers="Authorization=Bearer 1234567890" />

sendsipinfo Sends SIP INFO with custom body content to current call or to other calls in conference
Attributes:
value (required) - SIP INFO message body content
contentType (optional, default is "application/dtmf-relay") - Content-Type SIP header value
<sendsipinfo value="Signal=1" />
<sendsipinfo value="the text" contentType="text/plain" />

sendsipmessage Sends a custom SIP message. The message is set by content of XML element
Uses a common SIP parsing procedure which is used to parse normal SIP messages received from IP network. If the message is recognized as SIP request, the "sendsipmessage" exits after receiving response. If the message is recognized as SIP response, the "sendsipmessage" exits immediately after sending.
See also: sendsiprequest getsiptrace Attributes:
maxtime (optional) - for SIP requests: timeout to wait for response (see example)
var (optional) - for SIP requests: variable where to save response status code (see example)
localSipPort (optional) - explicitly set local SIP/UDP transport port. Is used with global settings "LocalSipPort", "LocalSipPortRange"
localSipAddress (optional) - explicitly set local SIP IP address, is used to select network interface. Is used with global setting "LocalSipAddresses"
transport (optional) - explicitly set SIP transport: "udp", "tcp" or "tls", default is "udp"
delayvar (optional) - for SIP requests: variable where to save the response delay in milliseconds (see example)
serverheadervar (optional) - for SIP requests: variable where to save "Server" header from the response
<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/>
<sendsipmessage>
<![CDATA[INVITE sip:88@localhost SIP/2.0
Max-Forwards: 69
Session-Expires: 3600;refresher=uac
Min-SE: 600
Supported: timer, 100rel
To: 888963217843506 <sip:888963217843506@80.239.172.171;user=phone>
From: <sip:905348591511@80.239.172.144>;tag=3621105032-66026
Remote-Party-Id: <sip:905348591511@80.239.172.144:5061;user=phone>;privacy=off;screen=yes
Call-ID: 5115009-3621105032-66020@msc1.voipdomain.com
CSeq: 1 INVITE
Allow: INVITE, BYE, OPTIONS, CANCEL, ACK, REGISTER, NOTIFY, INFO, REFER, SUBSCRIBE, PRACK, UPDATE, MESSAGE, PUBLISH
Via: SIP/2.0/UDP 80.239.172.144:5060;branch=z9hG4bK6e470d385b78ed88288a3488169f3448
Contact: <sip:905348591511@80.239.172.144:5060>
Call-Info: <sip:80.239.172.144>;method="NOTIFY;Event=telephone-event;Duration=1000"
Content-Type: application/sdp
Content-Length: 419

v=0
o=msc1 1412116227 1412116227 IN IP4 80.239.172.144
s=sip call
c=IN IP4 80.239.172.145
t=0 0
m=audio 31358 RTP/AVP 18 96 4 97 98 0 8
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:96 G729/8000
a=fmtp:96 annexb=yes
a=rtpmap:4 G723/8000
a=fmtp:4 annexa=yes
a=rtpmap:97 G729/8000
a=fmtp:97 annexb=no
a=rtpmap:98 G729/8000
a=fmtp:98 annexb=yes
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
]]>
</sendsipmessage>
<sendsipmessage>
<![CDATA[OPTIONS sip:test@192.168.10.6 SIP/2.0
Via: SIP/2.0/UDP 192.168.10.6
Max-Forwards: 70
To: <sip:test@192.168.10.6>
From: Alice <sip:test@192.168.10.5>;tag=test$id;
Call-ID: test$id;
CSeq: $id; OPTIONS
Contact: <sip:test@192.168.10.5>
Accept: application/sdp
Content-Length: 0
]]>
</sendsipmessage>
<log value="sending OPTIONS (SIP ping) to check availability of server. waiting for response during 3 seconds"/>
<sendsipmessage maxtime="3s" delayvar="delay" var="status">
<![CDATA[OPTIONS sip:test@192.168.10.6 SIP/2.0
Via: SIP/2.0/UDP 192.168.10.6
Max-Forwards: 70
To: <sip:test@192.168.10.6>
From: Alice <sip:test@192.168.10.5>;tag=test$id;
Call-ID: test$id;
CSeq: $id; OPTIONS
Contact: <sip:test@192.168.10.5>
Accept: application/sdp
Content-Length: 0
]]>
</sendsipmessage>
<if test="$status; = 200" > <log value="server is available. response delay is $delay;ms" /> </if>
<else> <log value="server is unavailable. status: $status;" /> </else>
<callxml>
 <assign enabled="false" var="d4" mathvalue="$id; % 256" />
 <assign enabled="false" var="ip" value="5.135.179.$d4;" />
 <assign enabled="true" var="d1" mathvalue="$rand(1,255);" />
 <if test="$d1; = 127" > <exit/> </if> <!-- skip 127.x.x.x (loopback) IP address range -->
<!-- scan random IP addresses -->
 <assign enabled="true" var="ip" value="$d1;.$rand(1,255);.$rand(1,255);.$rand(1,255);" />
 <assign var="port" value="5060" />
 <sendsipmessage maxtime="2s" var="status">
<![CDATA[OPTIONS sip:test@$ip;:$port; SIP/2.0
Via: SIP/2.0/UDP 163.172.210.13:6000
Max-Forwards: 70
To: <sip:test@$ip;>
From: StarTrinity <sip:test@163.172.210.13>;tag=test$id;
Call-ID: $randdigits(10);
CSeq: $randdigits(4); OPTIONS
Contact: <sip:test@163.172.210.13:6000>
Accept: application/sdp
Content-Length: 0
]]>
 </sendsipmessage>
 <if test="$status; = 200" > <log value="server $ip;:$port; is available" /> </if>
 <else> <log enabled="false" value="server $ip;:$port; is unavailable. status: $status;" /> </else>
</callxml>
<assign enabled="true" var="d1" mathvalue="$rand(1,255);" />
 <if test="$d1; = 127"> <exit /> </if> <!-- skip 127.x.x.x (loopback) IP address range -->
<!-- scan random IP addresses, more complex script -->
 <assign enabled="true" var="ip" value="$d1;.$rand(0,255);.$rand(0,255);.$rand(0,255);" />
 <assign var="port" value="5060" />

 <sendsipmessage maxtime="2s" var="status" serverheadervar="srv">
<![CDATA[OPTIONS sip:test@$ip;:$port; SIP/2.0
Via: SIP/2.0/UDP 163.172.210.13:6000
Max-Forwards: 70
To: <sip:test@$ip;>
From: StarTrinity <sip:test@163.172.210.13>;tag=test$id;
Call-ID: $randdigits(10);
CSeq: $randdigits(4); OPTIONS
Contact: <sip:test@163.172.210.13:6000>
Accept: application/sdp
User-Agent: StarTrinityFriendlyScanner
Content-Length: 0
]]>
 </sendsipmessage>
 <if test="$status; = 200">
    <log value="server $ip;:$port; responded to OPTIONS. server: $srv;" />
<sendsipmessage maxtime="2s" var="status" serverheadervar="srv">
<![CDATA[INVITE sip:100@$ip;:$port; SIP/2.0
Via: SIP/2.0/UDP 163.172.210.13:6000
Max-Forwards: 70
To: <sip:100@$ip;>
From: sip:101@163.172.210.13;tag=test$id;
Call-ID: $randdigits(10);
CSeq: $randdigits(4); INVITE
Contact: <sip:test@163.172.210.13:6000>
User-Agent: StarTrinityFriendlyScanner
Accept: application/sdp
Content-Length: 0
]]>
 </sendsipmessage>
    <log value="server $ip;:$port; responded to INVITE: server: $srv;" />
    <!-- the IP adresses could be saved as txt file, forwarded to some other system HTTP API or via a database -->
 </if>
 <else> <log enabled="false" value="server $ip;:$port; is unavailable. status: $status;" /> </else>
<exit />

sendsiprequest Sends custom SIP request for current SIP call, within current INVITE dialog. The request is set by content of XML element. Returns control immediately. Headers like Call-ID and request URI are overwritten, content-length is calculated automatically
Uses a common SIP parsing procedure which is used to parse normal SIP messages received from IP network
See also: sendsipmessage getsiptrace Attributes:
none
<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 -->
<![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>
<call value="sip:123456@myserver.com:5060" callerId="19056089570" maxringtime="20s" codec="G711A">
  <on event="answer">
     <wait value="3s" />
<!-- send DTMF signal via SIP INFO request. The software automatically replaces request line, standard headers: Via, From, To, Content-Length, CSeq, Call-ID -->   <sendsiprequest><![CDATA[INFO sip:11@1.2.3.4 SIP/2.0 User-Agent: StarTrinity
Content-Type: application/dtmf-relay
Content-Length: 10 Signal=10
Duration=150
]]></sendsiprequest >
     <wait value="3s" />
     <exit/>
   </on>
</call>

sendspoofedudppacket Sends generic UDP packet with spoofed source IP address
The element allows VoIP hacking, it is a part of SIP security testing suite Attributes:
sourceIp - source/fake IP address
destinationIp - destination IP address
sourcePort - sourceUDP port
destinationPort - destination UDP port
<sendspoofedudppacket sourceIp="1.2.3.4" sourcePort="1234" destinationIp="5.6.7.8" destinationPort="5678">
<![CDATA[
TEST PACKET WITH SPOOFED (FAKE) SOURCE IP ADDRESS!!!
NOT TO BE USED BY HACKERS!!!
FOR PENETRATION SIP TESTS ONLY!!!!!
]]>
</sendspoofedudppacket>

sendudppackets Sends generic UDP packets via current SIP/UDP socket
The element allows VoIP hacking, it is a part of SIP security testing suite Attributes:
repeat - number of times to repeat the packet
destinationIp - destination IP address
destinationPort - destination UDP port
<sendudppackets destinationIp="5.6.7.8" destinationPort="5678" repeat="100">
<![CDATA[TEST PACKET some data]]>
</sendudppackets>
<sendudppackets destinationIp="$rand(1,255);.$rand(1,255);.$rand(1,255);.$rand(1,255);" destinationPort="5060">
<![CDATA[INVITE sip:100@localhost:5060 SIP/2.0
Via: SIP/2.0/UDP 195.154.173.208:6000;rport;branch=z9hG4$randdigits(10);
Route: <sip:195.154.173.208:6000;lr>
Record-Route: <sip:195.154.173.208:6000;lr>
Max-Forwards: 70
To: <sip:100@localhost>
From: <sip:101@195.154.173.208>;tag=$randdigits(10);
Call-ID: $randdigits(10);
CSeq: 5664 INVITE
Contact: <sip:101@195.154.173.208:6000>
User-Agent: StarTrinityFriendlyScanner
Accept: application/sdp
Content-Type: application/sdp
Content-Length: 419

v=0
o=msc1 1412116227 1412116227 IN IP4 195.154.173.208
s=sip call
c=IN IP4 195.154.173.208
t=0 0
m=audio 6000 RTP/AVP 18 96 4 97 98 0 8
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:96 G729/8000
a=fmtp:96 annexb=yes
a=rtpmap:4 G723/8000
a=fmtp:4 annexa=yes
a=rtpmap:97 G729/8000
a=fmtp:97 annexb=no
a=rtpmap:98 G729/8000
a=fmtp:98 annexb=yes
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
]]>
</sendudppackets>

setcallgeneratorparams Changes call generation parameters
The call generator starts new CallXML session on time (clock) every N milliseconds, with fixed or random intervals. The interval between calls is set by "maxcps", "maxcpsL", "maxcpsH", "callspertick" parameters, maximum number of concurrent calls is set by "maxconcurrentcalls", "maxoutgoingconcurrentcalls". If number of concurrent calls exceeds "maxconcurrentcalls", the call generator is temporary stopped, so number of calls per second will be limited also Attributes:
maxcps (optional) - max calls per second (fixed interval betweeen calls)
maxcpsL (optional) - max calls per second, lower bound (random interval betweeen calls, linear probability distribution)
maxcpsH (optional) - max calls per second, higher bound (random interval betweeen calls, linear probability distribution)
maxconcurrentcalls (optional) - max concurrent calls (incoming + outgoing)
maxoutgoingconcurrentcalls (optional) - max concurrent calls (outgoing only)
callspertick (optional) - number of calls to create at a time (number of calls in a burst)
maxcallstoattempt (optional) - max. total number of calls to attempt
writeSettingsFileToDisk (optional, "true" or "false", default is "false") - specifies whether you need to save the call generator parameters to settings file. Note: setting this to "true" may cause too many disk writing operations
<setcallgeneratorparams maxcps="3" maxconcurrentcalls="10" />
<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;" />
<!-- please use SIP Tester's GUI to set daily start/stop time -->

<!-- here is the code to set different call load for different periods of time -->
<if test="$timeOfDayInHours(); > 10 & $timeOfDayInHours(); < 11">
<!-- from 10AM to 11AM - set number of channels = 30 -->
 <setcallgeneratorparams maxconcurrentcalls="30" />
</if>
<if test="$timeOfDayInHours(); > 11 & $timeOfDayInHours(); < 13">
<!-- from 11AM to 1PM - set number of channels = 50 -->
 <setcallgeneratorparams maxconcurrentcalls="50" />
</if>
<if test="$timeOfDayInHours(); > 13 & $timeOfDayInHours(); < 17">
<!-- from 1PM to 5PM - set number of channels = 10 -->
 <setcallgeneratorparams maxconcurrentcalls="10" />
</if>


<call maxringtime="$rand(45500);ms" value="$seq_sip_uri_from_csv(C:\StarTrinity\CSV Files\Mali Aug 26 Dialer Ready 4x 2xAST.csv);" codec="G729" />
<on event="answer">
<!-- on answer: verify called party, it should send DTMF digit 7 -->
 <inputdigits var="d" maxsilence="5s" />
 <if test="$d; != 7" > <exit /> </if>

<!-- play random wav file from folder -->
 <playaudio value="$randfile(C:\StarTrinity\Wav Files\*.wav);" repeat="infinite" maxtime="$rand(500000);ms" />
 <exit />
</on>

setexitcode Sets exit code for SIP Tester process. Is used to pass result from CallXML script into .bat script via using command line interface
See also: "exitcli" Attributes:
value (required) - exit code
<setexitcode value="-1" />

setimpairmentparams Configures simulated RTP loss, jitter and SIP packet loss parameters
See impairments generation in SIP Tester Attributes:
sipPacketLossProbability (optional) - simulated SIP packets loss probability
rtpPacketLossGapProbability (optional) - simulated RTP packet loss gap probability
rtpPacketLossMaxLostPacketsInGap (optional) - max. number of RTP packets in the simulated RTP packet loss gap
rtpJitterDelayProbability (optional) - probability of simulated delay in RTP thread, to generate RTP jitter
rtpJitterAverageDelay (optional) - average delay of simulated delay in RTP thread
<setimpairmentparams sipPacketLossProbability="0.01" rtpPacketLossGapProbability="0.005" rtpPacketLossMaxLostPacketsInGap="10" rtpJitterDelayProbability="0.005" rtpJitterAverageDelay="50ms" >

setinterval Executes internal CallXML code at specified intervals, when current SIP calls is still alive
Is similar to "setInterval" in JavaScript. The internal CallXML code is executed in a separate thread. See also: "settimeout" Attributes:
value (required) - interval between the executions of the internal CallXML code
<setinterval value="1s">
 <log value="do something every 1 second during the call. e.g. request database and destroy the call if needed" />
</setinterval>
<call value="sip:test@10.10.10.10" />
<on event="answer">
 <playaudio value="music.wav" repeat="infinite" />
</on>

setrtpextension Sets or removes RTP extension data for transmitted RTP stream
Attributes:
hexData (optional) - generic RTP extension data in hexademical text format. Example: '01C04FFA'
extensionId (required if 'hexData' is set) - identifier of RTP extension data format, defined by audio/video profile
wg67_pttType (optional) - PTT-type field, defined in INTEROPERABILITY STANDARDS FOR VOIP ATM COMPONENTS VOLUME 1: RADIO. If wg67_pttType is set to "rxptt", it gets PTT-type from received RTP stream, in other words it creates PTT-type RX-TX loopback connection. This loopback connection is used to measure round-trip RTP audio delay for ED-137 performance testing of air traffic management (ATM) VoIP networks.
wg67_pttId (optional) - PTT-ID
wg67_squ (optional, 1 or 0, default is 0) - SQU flag. If wg67_squ is set to "rxptt", it creates loopback connection from PTT-Type field of received RTP stream: If RX-PTT-ID is 0 then TX-SQU is 0, otherwise TX-SQU is 1
wg67_pm (optional, 1 or 0, default is 0) - PM flag
wg67_ptts (optional, 1 or 0, default is 0) - PTTS flag
wg67_sct (optional, 1 or 0, default is 0) - SCT flag
<call value="sip:line@192.168.3.3:5062" callerId="line"></call>
<on event="answer">
  <setrtpextension wg67_pttType="3" wg67_pttId="16" wg67_squ="1" wg67_pm="0" wg67_ptts="0" wg67_sct="1" />
<!-- set RTP extension data for transmitted stream in WG 67 format (0x167). For more information about fields see
   INTEROPERABILITY STANDARDS FOR VOIP ATM COMPONENTS VOLUME 1: RADIO -->

  <playaudio value="music.wav" maxtime="3s" /> <!-- play music.wav during 3 seconds -->
  <setrtpextension wg67_pttType="0" wg67_pttId="16" wg67_squ="1" wg67_pm="0" wg67_ptts="0" wg67_sct="1" />
<!-- set another RTP extension data -->
  <playaudio value="music.wav" maxtime="3s" />
  <setrtpextension wg67_pttType="0" wg67_pttId="16" wg67_squ="1" wg67_pm="0" wg67_ptts="0" wg67_sct="0" />
  <playaudio value="music.wav" maxtime="3s" />
  <setrtpextension wg67_pttType="0" wg67_pttId="16" wg67_squ="0" wg67_pm="0" wg67_ptts="0" wg67_sct="0" />
  <playaudio value="music.wav" maxtime="3s" />
  <setrtpextension /> <!-- turn off RTP extension data -->
  <playaudio value="music.wav" maxtime="3s" />
  <exit />
</on>
<call value="sip:test@192.168.3.3:5062" callerId="test"></call>
<on event="answer">
  <setrtpextension extensionId="359" hexData="01C00000" />
  <playaudio value="music.wav" maxtime="3s" />
  <exit />
</on>
<accept />
<setrtpextension wg67_pttType="rxptt" wg67_pttId="7" wg67_squ="0" wg67_pm="0" wg67_ptts="0" wg67_sct="0" />
<!-- set up PTT-type loop from RX RTP stream to TX RTP stream -->
<playaudio value="music2" repeat="infinite" maxtime="60000ms" />
<exit />

setrtpmalformer Configures RTP malformer
The element allows VoIP hacking, it is a part of SIP security testing suite Attributes:
malformBitProbability - probability to randomly change a bit in transmitted RTP packets
note: the documentation is hidden due to potential dangerous misuse of our software
<setrtpmalformer >

setrtptxfields Modifies transmitted RTP stream, fields SSRC, timestamp, sequence
Attributes:
ssrc (optional) - SSRC field, in decimal format
ts (optional) - timestamp field, in decimal format
seq (optional) - sequence field, in decimal format
<setrtptxfields ssrc="1234" />

setsetting Sets a global setting value
The settings are described in the UI on the 'settings' screen. Attributes:
name (required) - name of setting
value (required) - value of setting
<setsetting name="SaveSipAndRtpPacketsToDisk" value="1" />

settimeout Executes internal CallXML code after specified timeout
Is similar to "setTimeout" in JavaScript. The internal CallXML code is executed in a separate thread. See also: "setinterval" Attributes:
value (required) - time to delay the execution of the internal CallXML code
<assign var="receivedReinvite" value="false" />
<call maxringtime="10s" value="sip:test@localhost:5060">
 <on event="answer">
  <settimeout value="60s">
   <log value="60 seconds passed: checking if received re-invite" />
   <if test="$receivedReinvite; = false" > <log value="aborting call" /> <disconnect /> </if>
   <else> <log value="received re-invite: continue the call" /> </else>
  </settimeout>
  <playaudio value="music.wav" repeat="infinite" /> <exit />
 </on>
 <on event="reinvite"> <log value="received re-invite" /> <assign var="receivedReinvite" value="true" /> </on>
</call>

setuaccredentials Sets user name and password to handle 401 and 407 UAS responses. Is used for incoming calls, to authorize further BYE and RE-INVITE requests from SIP Tester to server
Attributes:
user (required) - user name
password (required) - password

setwebapiresult Passes key-value result to web API "CreateCall_Post"
Attributes:
key (optional) - key
value (required) - value

srand Initializes the CallXML engine's random generator with the specified seed value
Is used to reproduce random tests Attributes:
value (required) - the seed value, integer
<!-- initialize random generator for the first CallXML session (ID = 0)
<if test="$id; = 0"> <srand value="123" /> </if>
<log value="random = $rand(100);" />

startcallgenerator Starts generation of outgoing calls
Attributes:
[none]
<startcallgenerator />

stopaudio Stops audio player which was started previously
Attributes:
[none]
<stopaudio />

stopcallgenerator Stops generation of outgoing calls
Attributes:
[none]
<stopcallgenerator />

substring Retrieves a substring from a specified value, saves result to a variable
Attributes:
value (required) - input string
startIndex (required) - zero-based starting character position of a substring
length (optional) - number of characters in the substring
<substring var="result1" value="01234567890" startIndex="0" length="2" />
<log value="result1=$result1;" />

<substring var="result2" value="01234567890" startIndex="6" />
<log value="result2=$result2;" />

<substring var="result3" value="startrinity CallXML" startIndex="12" length="4" />
<log value="result3=$result3;" />
<if test="$callerId; startswith +"> <substring var="callerId" value="$callerId;" startIndex="1" />  </if>
<getstringlength var="calledIdLength" value="$calledId;" />
<block repeat="$calledIdLength;" var="i">
 <substring value="$calledId;" startIndex="$i;" length="1" var="digit" />
 <log value="extracted called ID digit #$i;: $digit;" />
 <playaudio value="C:\startrinity_siptester_latest\Wav\digit;.wav"/>
</block>

switch Checks if a value matches to one of many conditions, executes an action accordingly
The conditions are defined by inner "case" XML elements. If no "case" element is found, "default" element is executed. If "probability" attributes are defined for the conditions, a random "case" is selected. "case" XML element may be empty. See also: "case", "default" Attributes:
value (optional) - input value for checking
<switch value="$callerId;">
 <case equals="111"> <log value="call is from 111" /> </case>
 <case equals="222"> <log value="call is from 222" /> </case>
 <case startsWith="2"> <log value="call is from 2xxx" /> </case>
 <default> <log value="caller ID is not recognized" /> </default>
</switch>
<switch>
  <case probability="10">
   <log value="this has probability of 10%" />
  </case>
  <case probability="30">
   <log value="this has probability of 30%" />
  </case>
  <case probability="60">
   <log value="this has probability of 60%" />
  </case>
</switch>
<switch value="$timeOfDayInHours();">
 <case from="0" to="12"> <setcallgeneratorparams callspertick="1" maxcpsL="0.1" maxcpsH="0.22" /> </case>
 <case from="13" to="24"> <setcallgeneratorparams callspertick="3" maxcpsL="0.2" maxcpsH="0.32" /> </case>
</switch>

throw Raises an event
Attributes:
value (required) - type and (optionally) subtype of event, separated by ":"
<inputdigits value="enter_digit.wav" var="entered_digit" maxsilence="20s" maxdigits="1" />
<throw value="digit:$entered_digit;" />
<on event="digit:1">
   <playaudio value="1" />
</on>
<on event="digit:2">
   <playaudio value="2" />
</on>

transfer Redirects call to another SIP URI. Is used to proxy call at server side or to send REFER
Raises "pr", "audioSignal", "maxringtime", "maxansweredtime", "callfailure" and "answer" events
Attributes:
value (required if 'terminators' attribute is not set) - specifies SIP URI of destination. SIP URI can contain user and password for authentication, and "transport" query parameter ("udp" or "tcp", "udp" is default). The SIP URI may contain following query parameters:
  • "transport" - "udp" or "tcp", "udp" is default
  • "user", "password" - credentials for authentication
  • "proxyAddress", "proxyPort" - address of proxy server
  • "localSipPort" - local SIP UDP port to use for the call
  • "callerId" - user ID in 'From' header
If value equals to "$ext(100);" - call is forwarded to a registered extension (UAS registration) with SIP ID = "100". In softswitch mode the "value" overwrites destination (B) number.
terminators (required if 'value' attribute is not set) - identifiers of terminators, separated by semicolons, used for Softswitch scripts. Terminators are configured via web interface. If 'terminators' is set to 'all', all available terminators are used; if set to 'routed' - the terminators are taken from settings of originator and routing group. If attribute 'dontProxyCallfailure' is set, CallXML flow goes to next element after "transfer" in case of call failure or unavailable terminators.
gatewayId (optional) - identifies GSM gateway ID (when using the softswich with GoIP SIM management features), to select it explicitly in CallXML script
channelId (optional) - identifies GSM gateway channel ID (when using the softswich with GoIP SIM management features), to select it explicitly in CallXML script
mode (optional, default is "bridged") - list of call transfer modes, separated by semicolon. If "terminators" attribute is set, default mode is taken from the terminator.
  • "blind" - if mode is "blind", sends REFER to the caller. In this mode "value" atribute goes into "Refer-To" SIP header
  • "bridged" - if "mode" is "bridged", makes another SIP call (call B) and connects RTP streams between current call (call A) and call B. If call A is not answered yet, sends answer response to call A when call B is answered. Optionally plays ringback tone from WAV or MP3 file. Proxies provisional responses (180, 183) from call B to call A. Returns control on time out or after completion of call B. Automatically converts codecs (e.g. performs G.729-G.711 transcoding). Raises "callfailure" and "maxringtime" events. Automatically redirects call B to new destination if receives "302 Moved Temporarily" response. If "callfailure" event is not handled, rejects call A automatically
  • "proxydtmf" - pass DTMF messages between call A and call B
  • "disablehold" - disable call hold and 3-way conferencing
  • "suppressAnswerBeforeRbt" - suppress FAS, start billing only if there was ringback tone before answer. If the answer from terminator is received before ringback tone (450 Hz), it waits for the ringback tone and generates answer 5 seconds after last tone. Stops fake ringbacktone, if it was started before the "transfer" element in the script
  • "recognizeAnswerFromRtpB" - ignore answer signal from terminator, recognize it from RTP audio from call leg B - first sound after ringback tone
  • "recognizeAnswerFromRtpA" - ignore answer signal from terminator, recognize it from RTP audio from call leg A - first sound above specified level (in decibels, "level" attribute, default is "-20")
For "bridged" mode only:
ringbacktone (optional) - absolute or relative path to ringback tone audio file which will be played to call A
ringbacktoneMaxtime (optional) - max time for ringback tone audio file playback. After the ringbacktoneMaxtime call leg A starts to receive early media from call leg B
to (optional) - "To" header for SIP INVITE message. If "to" is not set, it is taken from "value" SIP URI
callerId (optional, default is "unknown") - SIP ID for "From" header in INVITE message
callId (optional) - Call-ID header for call leg B
sendSdpInInitialInvite (optional, "true" or "false", default is "true") - specifies whether to send SDP in SIP INVITE message. If no SDP is sent in request, and if destination also does not send SDP in response, the SIP call will be established without RTP media.
direction (optional, "SendOnly"/"ReceiveOnly"/"None"/"Both", default is "Both") - RTP media direction to be declared in SDP
maxringtime (optional, default is "no timeout") - timeout of waiting for call answer in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "maxringtime" expires, call is leg B aborted with CANCEL SIP message and "maxringtime" event is generated
_18xTimeout (optional, default is "no timeout") - timeout of waiting for 180 or 183 response in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "_18xTimeout" expires, call leg B is aborted with CANCEL SIP message
maxansweredtime (optional, default is "no timeout") - max call duration after answering in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "maxansweredtime" expires, call leg B is aborted and "maxansweredtime" event is raised. If no event handler for "maxansweredtime" exists, the call leg A is aborted with BYE SIP message
headers (optional) - list of custom SIP headers to be included into the INVITE message.
Example: Header1Name=Header1Value|Header2Name=Header2Value|Header3Name=Header3Value
sdpAttributes (optional) - list of custom SDP attributes to be included into the INVITE message.
Example: Attr1Name:Attr1Value|Attr2Name:Attr2Value|Attr3Name:Attr3Value
codec (optional, "G711A"/"G711U"/"G723"/"G729", default is "any of supported") - RTP media codec (SDP media stream payload type) to be used for the SIP call.
rtpProxyMode (optional, "transcoding"/"open RTP"/"fast RTP proxy", default is "transcoding") - specifies the way how the softswitch connects RTP media of A and B call legs. The mode can be selected individually for every call
disconnectOnSilenceLevel (optional, default is "none") - if specified, disconnects the call if both A and B call legs are silent for a long time
disconnectOnSilenceTimeout (optional, default is "30s") - if "disconnectOnSilenceLevel" attribute is set: minimal silent time before disconnecting the call
simulateFasAfterConnection (optional, "true" or "false", default is "false") - is used in combination with element "wait" after "transfer". When the attribute is set, the "transfer" continues to next CallXML element after successful call. In this way you can simulate FAS / extra billing after connection. The attribute must be used for testing purposes only, not for live traffic to generate fraud.
proxyPR (optional, "true" or "false", default is "true") - enables unconditional proxying of 180 and 183 provisional responses from call leg B to call leg A
proxyRingbacktone (optional, "true" or "false", default is "true") - if set to "false", disables sending ringback tone from call leg B to call leg A, when playing a custom ringback tone
dontProxyRtpMedia (optional, "true" or "false", default is "false") - enables passing RTP directly from originator directly to terminator, without the softswitch (third party call control)
dontProxyCallfailure (optional, "true" or "false") - enables proxying call failure packet (4xx, 3xx, 6xx) from destination call leg to source call leg. Is set to false when additional processing is needed after call failure
localRtpPort (optional) - explicitly set local RTP UDP port number. If empty or zero, a socket from RTP transport pool is used (see settings "MediaTransportPoolMinPort", "MediaTransportPoolMaxSocketsCountPerInterface")
localRtpAddress (optional) - explicitly set local RTP IP address, is used to select network interface. If empty, the network interface is selected by remote IP address using system routing table (WinAPI function GetBestInterface())
localSipPort (optional) - explicitly set local SIP/UDP transport port. Is used with global settings "LocalSipPort", "LocalSipPortRange"
localSipAddress (optional) - explicitly set local SIP IP address, is used to select network interface. Is used with global setting "LocalSipAddresses"
antiFasConnectionDelay (optional) - technique against short-duration FAS calls. Time to delay 200 OK (connection signal) from leg B to leg A. Example: 2000ms
antiFasRingingTimePeriodsMs (optional) - time periods of ringing duration to turn on the anti-FAS technique. Example: 9500-10500,30000-60000
For "blind" mode only:
dontwait (optional, "true" or "false", default is "false") - turns off waiting for completion of REFER procedure. If set to "true", goes to next element in script immediately
referredBy (optional) - Referred-By header for the transmitted REFER request packet
<transfer value="sip:152@192.168.0.56" mode="bridged" ringbacktone="wait_for_answer.wav"
     maxansweredtime="20m" maxringtime="40s" >
 <on event="callfailure:486">
   <playaudio value="busy.wav" />
 </on>
 <on event="callfailure">
   <playaudio value="call_error.wav" />
 </on>
 <on event="maxringtime">
   <playaudio value="call_does_not_answer_on_timeout.wav" />
 </on>  <on event="maxansweredtime">
   <playaudio value="speaking_timeout_call_again.wav" />
 </on>
</transfer>
<playaudio value="thank_you_for_call.wav" />
<exit />
<assign var="transferPrefix" value="+1" />
<transfer value="sip:$transferPrefix;$calledId;@x.x.x.x:5060" callerId="$callerId;" mode="bridged" maxringtime="50s" codec="G729" />
<on event="callfailure">
 <log value="call 'B' failed, status = $eventSubType;. rejecting call leg 'A' with same status code" />
 <reject value="$eventSubType;" />
 <exit />
</on>
<on event="maxringtime">
 <playaudio value="call_does_not_answer_on_timeout.wav" />
 <reject value="503" />
</on>
<accept value="183" />

<!-- play fake rbt -->
<playaudio value="rbt$randswitch(1,2,3,4,5);.wav" repeat="100" dontwait="true" />

<!-- split traffic into 2 gateways, 5 channels each. suppress IVR (announcement) from destination before receiving ringback tone -->
<transfer value="$rand_from_options;" callerId="$callerId;" mode="bridged;proxydtmf;suppressAnswerBeforeRbt" maxringtime="70s">
 <option value="sip:$calledId;@51.254.245.55" maxCallsPerDestinationResource="5" destinationResourceId="server1" />
 <option value="sip:$calledId;@51.254.245.43" maxCallsPerDestinationResource="5" destinationResourceId="server2" />
 <on event="callfailure"> <reject value="$eventSubType;" /> </on>
</transfer>
<!-- transfered to registered SIP phone with extension 100 -->
<transfer value="$ext(100);" >
 <on event="callfailure"> <reject value="$eventSubType;" /> </on>
</transfer>
<!-- simplest softswitch script for GSM termination and wholesale -->
<performAAA />
<transfer terminators="routed" />
<!-- script used to suppress FAS when getting an IVR from SIM - for GSM termination -->
<performAAA />
<transfer terminators="routed" mode="bridged;suppressAnswerBeforeRbt;proxydtmf" />
<!-- script used for bluetooth - GSM termination, to generate answer and disconnect signals from media streams -->
<performAAA />
<accept value="183" />
<transfer terminators="routed" mode="bridged;recognizeAnswerFromRtpB;proxydtmf" disconnectOnSilenceLevel="-40" disconnectOnSilenceTimeout="30s" maxringtime="60s" />
<on event="maxringtime"> <reject value="487" /> </on>
<!-- script used for bluetooth - GSM termination, to generate answer and disconnect signals from media streams -->
<performAAA />
<accept value="183" />
<transfer terminators="routed" mode="bridged;recognizeAnswerFromRtpA;proxydtmf" level="-20" disconnectOnSilenceLevel="-40" disconnectOnSilenceTimeout="30s" maxringtime="60s" />
<on event="maxringtime"> <reject value="487" /> </on>
<!-- script used to simulate over-billing (FAS after connection) for 1..10% of total billed time -->
<performAAA/>
<transfer terminators="routed" simulateFasAfterConnection="true">
<on event="answer"> <assign var="answeredTime" value="$timeMs();" /> </on>
</transfer>
<if test="$answeredTime;">
 <assign var="connectedTime" mathvalue="$timeMs(); - $answeredTime;" />
 <assign var="additionalTime" mathvalue="$connectedTime; * 0.01 * $rand(1,10);" />
 <wait value="$additionalTime;ms" />
</if>
<!-- send REFER with complex Refer-To header -->
<transfer mode="blind" value="&lt;sip:1017@xxx.com;user=phone?Replaces=75e4fb7-bdba627c-2d5c4bfd%4010.192.222.38%3Bto-tag%3D53993a5c-88b7-e51e-da9c-e8ce9f20e505%3Bfrom-tag%3DFA1A6CFB-B7991CF0&>" referredBy="sip:test@example.com" />
<!-- warm transfer unit test - using REFER with complex Replaces header -->
<readcsv repeat="infinite" value="C:\StarTrinity\2steptest.csv" var0="from" var1="to_name" var2="sbc_ip" var3="sbc_port" var4="password" var5="reffile" var6="xferext" var7="password2" />

<assign var="to" value="sip:$to_name;@$sbc_ip;:$sbc_port;?user=$from;&password=$password;" />
<log value="calling from $from; to $to;" />
<!-- from: (A) who initially makes call (agent); to - (B) customer; xferext - (C) supervisor
   finally customer will be connected with supervisor (B to C)
-->


<!-- generate random IDs -->
<assign var="fromTag" value="$randdigits(10);" />
<assign var="callIdC" value="$randdigits(10);" />

<!-- make a call from agent to customer -->
<call value="$to;" callerId="$from;" headers="X-Attributes=*;test=A014" testId="A014" sipCallId="$callIdC;" fromTag="$fromTag;" />
 <on event="answer">
  <wait value="2s" />
  <run var="newSessionId">
   <!-- call from agent (A) to supervisor (C) in a new (independent) CallXML session -->
   <call value="sip:$xferext;@$sbc_ip;:$sbc_port;" sipCallId="$callIdC;" />
   <on event="answer">
    <!-- call C answered: extract 'To' header tag from '200 OK' SIP packet -->

    <log value="received To header '$sipHeaderTo;'" />
    <regexsearch value="$sipHeaderTo;" regex=";tag=(?<toTag>\S*)" var="toTag" />
    <log value="received To header tag = '$toTag;'" />

    <!-- call C answered: pass 'To' header tag into main CallXML session -->
    <sendevent value="answer" session="$parentSessionId;" toTag="$toTag;" />

    <playaudio value="music.wav" />
    <exit/>
   </on>
  </run>

  <wait value="30s" /> <!-- wait for 'c_answered' event from the secondary session, max. 30 seconds -->
  <exit/> <!-- exit the script on timeout, this should not happen during normal test -->

  <on event="externalevent:c_answered" >
   <log value="main callxml session: got 'c_answered' event from secondary session. toTag = '$toTag;' -->
   
   <!-- send REFER passing the C number, and IDs -->
   <transfer value="<sip:$xferext;@$sbc_ip;:$sbc_port;;user=phone?Replaces=$callIdC;%3Bto-tag%3D$toTag;%3Bfrom-tag%3D$fromTag;>" mode="blind" dontwait="true" />
  
   <wait value="11s" />
   <exit /> <!-- abort call (from agent (A) to customer (B)) -->
  </on>
</on>
<!-- example of call transfer using REFER with Replaces -->

 <accept /> <!-- accept call (from A to B) -->

 <assign var="fromTag" value="$randdigits(10);" />
 <assign var="callIdC" value="$randdigits(10);" />

 <run var="secondarySessionId">
  <!-- new call goes to the destination (from B to C) -->
  <call value="sip:204@xxsip.com:5060" maxringtime="60s" sipCallId="$callIdC;" fromTag="$fromTag;">
   <on event="answer">
    <!-- once the destination C answers - then the original call (A-B) gets transferred to the new call (refer with replaces) -->
    <log value="received To header '$sipHeaderTo;'" />
    <regexsearch value="$sipHeaderTo;" regex=";tag=(?<toTag>\S*)" var="toTag" />
    <log value="received To header tag = '$toTag;'" />

    <!-- the event and pass 'To' header tag into main CallXML session -->
    <sendevent value="answered" session="$parentSessionId;" toTag="$toTag;" />

    <playaudio value="C:\vm\PleaseWaitTransfer.wav" repeat="infinite" maxtime="60s" />
    <exit/>
   <on>
   <on event="externalevent:mainSessionHangup">
    <log value="received mainSessionHangup event in the second session" />
    <disconnect />
   </on>
  </call>
 <run>
 <playaudio value="C:\vm\PleaseWaitTransfer.wav" repeat="infinite" maxtime="60s" />

 <on event="externalevent:answered" >
  <log value="main callxml session: got 'answered' event from secondary session. toTag = '$toTag;'" />
  <!-- send REFER with replaces -->
  <transfer value="<sip:204@xxsip.com:5060;user=phone?Replaces=$callIdC;%3Bto-tag%3D$toTag;%3Bfrom-tag%3D$fromTag;>" mode="blind" dontwait="true" />
  <wait value="11s" />
  <exit /> <!-- abort call (from A to B) -->
 </on>
 <on event="hangup" >
  <sendevent session="$secondarySessionId;" value="mainSessionHangup" />
 </on>

update Sends UPDATE with new media description.
See also: "reinvite" Attributes:
direction (optional, "SendOnly"/"ReceiveOnly"/"None"/"Both") - RTP media stream direction. The meaning of the direction in SDP is a little bit confusing. It is explained in RFC3264. If one side (A) sends "recvonly" in its SDP offer, the other side (B) should say "sendonly" (opposite) in its SDP answer. After that (when SIP call is put on hold), A "receives only, not sends" from B, and B "sends only, not receives" to A, in other words RTP stream flows in one direction: from B to A, microphone at A is muted
sendSdp (optional, "true"/"false", default "true") - send SDP in the UPDATE packet. "false" is used to test case of SDP offer in "200 OK" and SDP answer in "ACK"
localRtpAddress (optional) - a custom IP address to put into SDP. Is used for test purposes
codec (optional, "G711A"/"G711U"/"G723"/"G729", default is "current") - new RTP media codec (SDP media stream payload type) to be sent in the UPDATE SDP
<update direction="ReceiveOnly" />
<call value="sip:test@10.10.10.10" /> <!-- make call with all available codecs declared in SDP -->
<on event="answer">
 <playaudio value="music.wav" maxtime="5s" />
 <update codec="G729" /> <!-- change codec to G729 -->
 <playaudio value="music.wav" maxtime="5s" />
 <update codec="G711A" /> <!-- change codec to G711A -->
 <playaudio value="music.wav" maxtime="5s" />
 <exit />
</on>

verifyaudio Verifies RTP audio stream of current SIP call, compares it with one or many reference audio files. Identifies matched reference file along with either a confidence score, or audio quality measurement (PESQ MOS). Also, measures the delay between the start of audio verification and the occurrence of the matched audio file.
For offline mode: records audio signal into memory during "maxtime" regardless of reference file length. After that, passes the recording to audio verification threads and returns control after verification.
For real-time mode: verifies audio immediately, returns control when "waitConfidenceThreshold" is exceeded or when timeout is expired.
The known ("reference") audio fragment could be located in middle of a longer IVR prompt.
Note: works only in "normal" media processing mode (not "Lightweight", "Winpcap RTP sender")
See also: "waitforsignal" to measure delay of IVR response without any verification, "measuresignal" to measure min/max level in sine test audio signal Attributes:
reference (required) - absolute or relative reference audio file names or URLs, separated by ";"
callLeg (optional, "a"/"b", "default is "a") - selects call leg (A or B) for the audio verification. Listening to "B" leg is useful when you need to analyse audio in softswitch mode coming from termination side (ringback tone or some IVR announcement)
maxtime (required) - max time of verification in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). For real-time audio verification mode "maxtime" is a timeout of waiting for initial match
waitConfidenceThreshold (optional, 1-100) - Setting this value enables real-time audio verification. To enable real-time audio verification set this value to a number between 1 and 100. In real-time audio verification mode, the audio stream is verified for a match to any portion of the audio file (or files) specified in by the "reference" parameter. As soon as a partial match is made, the "maxtime" timer is cancelled. The audio stream continues to be monitored until either the confidence reaches the specified value, or for number of seconds equal to the longest reference audio file has occurred, whichever comes first. In the real-time mode audio verification is performed by media threads. It is recommended to set setting "MediaThreadsCount" greater than 64. The real-time mode works for G.711 codec only. By default, the algorithm searches for matches by testing delays equal to multiples of RTP frame duration (N*10ms), in this way saving CPU time. If there are partial-frame delays in your environment (e.g. if voice goes over non-RTP channels like TDM), set setting "EnablePartialFrameOffsetInRealtimeAudioVerifier" to "1"
ravParameters (optional, default is "mode=exact") - only for real-time audio verification mode, configures mode of real-time audio verification: "mode=fuzzy" or "mode=exact"
debugRecordingThreshold (optional) - for real-time audio verification: "verifyaudio" saves debug recordings of observed audio, if confidence is less than the "debugRecordingThreshold" (0-100). for PESQ-mode audio verification (with "mosvar" attribute set) the "debugRecordingThreshold" means PESQ MOS threshold to save the recording. Recorded file names are built from settings "DebugMediaPath" and "DebugMediaFileNamePattern".
confidencevar (optional) - name of variable to store measured confidence, i.e. similarity rate between RTP audio stream and reference audio file = 100 * matched_duration / reference_wav_duration
mosvar (optional) - name of variable to store PESQ MOS. If "mosvar" attribute exists, PESQ algorithm is used to calculate MOS. If recorded duration and reference duration are not equal, minimum duration is selected for PESQ.
Note: If waitConfidenceThreshold is specified, this value has no effect.
If you have low PESQ MOS scores while it is not expected, you can:
  • Enable RX debug recording (set setting "DebugMedia = "1"), listen to recorded audio to check if audio quality is really bad
  • Increase SIP Tester's jitter buffer size, set it according to settings of your VoIP software
  • Try to use recorded RX wav file as reference file. Some implementations like SIPP make small distortions which affect work of SIP Tester's jitter buffer loss compensator
  • Try to use a different audio file. The algorithm works better with speech, not music. There is a "speech.wav" in default installer

recognizedreferencevar (optional) - name of variable to store matched reference audio file. If more than one file is passed in the reference value, the file with the highest match is returned.
recognizeddelayvar (optional) - name of the variable to store delay between the start of audio verification and the occurrence of the matched audio file in milliseconds. The delay can be negative if some part of IVR file is already played before the start of verification
probability (optional) - probability of audio verification being executed. Is used to verify audio for only part of calls, in this way reducing CPU load. Valid range is a decimal value from 0-1.
<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;" />
<call value="sip:XX@10.10.10.10" />
<on event="answer">
   <verifyaudio reference="C:\reference_file_speech.wav" maxtime="10s" mosvar="pesq_mos" />
   <writecdr header="PESQ_MOS" value="$pesq_mos;" numeric="true" qualityIsAscending="true" />
   <exit />
</on>
<!-- outgoing script: make call via IP PBX to verify 2-way audio connection (note that you have to create entries in 'UAC registrations' -->
<callxml>
 <call value="$random_least_busy_uac_registration();" >
  <on event="answer">
   <playaudio value="speech.wav" dontwait="true" />
   <verifyaudio reference="speech.wav" maxtime="12s" mosvar="pesq_mos" />
   <writecdr header="PESQ_MOS" value="$pesq_mos;" numeric="true" qualityIsAscending="true" />
   <exit />
  </on>
 </call>
</callxml>

<!-- incoming script: accept call and play same audio back to caller -->
<callxml>
 <accept />
 <loopbackaudio maxtime="60s" />
</callxml>
<!-- real-time audio verification mode, exact byte comparison. see also setting "EnablePartialFrameOffsetInRealtimeAudioVerifier " -->
<call value="sip:YY@10.10.10.10" />
<on event="answer">
   <verifyaudio reference="C:\reference_file_speech.wav" maxtime="14s" waitConfidenceThreshold="100" confidencevar="confidence" recognizeddelayvar="delay" />
   <writecdr header="CONFIDENCE" value="$confidence;" numeric="true" qualityIsAscending="true" />
   <writecdr header="DELAY" value="$delay;" numeric="true" qualityIsAscending="false" />
   <exit />
</on>

wait Introduces delay with specified amount of time
See also: "waitforsignal" Attributes:
value (optional, default is "infinite") - timer in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix). If "value" is not specified, the "wait" sets current call into idle state
<wait value="1s" />
<wait value="$rand(10000);ms" />

waitforevent Waits for external event, sent by other CallXML session via "sendevent" element. Is used to synchronize CallXML scripts
Attributes:
value (optional) - event subtype to wait from sender. If not set, all external events are accepted
maxtime (optional) - optional timeout

waitforringbacktone Waits for a ringback audio tone with frequency 400..450Hz and level at least -30dB. Is used to validate SIP trunks
If there is no RTP, it does not return control. See also: "waitforsignal" Attributes:
var (optional) - name of variable to store measured delay in milliseconds. If the "maxtime" timeout expires, it receives a value of "maxtime"
maxtime (optional) - timeout of waiting in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
<call value="sip:test@10.10.10.10">
 <on event="pr:183">
  <log value="received 183 response. waiting for ringback tone for max 6000ms..." />
  <waitforringbacktone var="d" maxtime="6s" />
  <log value="RBT wait time = $d;ms" />
  <if test="$d; >= 6000"> <log value="RBT is not detected" /> </if>
 </on>
 <on event="answer">
  <log value="received 200 response" />
  <exit />
 </on>
</call>
<assign var="rbtDetected" value="NO" />
<!-- please look into sample file with destinations in program folder. example line in file: +12027412777,172.1.2.2,5060,123456789,password2,udp -->
<assign var="sipUriToDial" value="$seq_sip_uri_from_csv(C:\SipTester\destinations.csv);" />
<call value="$sipUriToDial;" maxringtime="10s" codec="G711U">
 <on event="pr:183">
  <log value="received 183 response. waiting for ringback tone for max 6000ms..." />
  <waitforringbacktone var="rbtWaitTime" maxtime="6s" />
  <log value="RBT wait time = $rbtWaitTime;ms" />
  <if test="$rbtWaitTime; &gt;= 6000"><log value="RBT is not detected" /></if>
  <else> <assign var="rbtDetected" value="YES" /> </else> <
 </on>
 <on event="answer">
  <log value="received 200 response" />
  <playaudio value="music.wav" maxtime="3s" />   
  <assign var="statusCode" value="200" />
 </on>
 <on event="callfailure"> <assign var="statusCode" value="$eventSubType;" /> </on>
</call>
<writefile newLine="true" fileName="C:\SipTester\log.csv" splitInterval="1h" value="$sipUriToDial;,$statusCode;,$rbtDetected;" />

waitforringbacktoneabsence Waits for absence of ringback audio tone with frequency 400..450Hz and level at least -30dB. Is used to skip fake SIM card answer and "welcome" announcement with GSM gateways (see sample script)
See also: "waitforringbacktone"
Attributes:
var (optional) - name of variable to store measured delay in milliseconds. If the "maxtime" timeout expires, it receives a value of "maxtime"
maxtime (optional) - timeout of waiting in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
minabsencetime (optional, default "5s") - minimum time without ringback tone, in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
<call value="sip:1234567@10.10.10.10" />
<on event="pr:183">
 <log value="got early media from destination: waiting for ringback tone (RBT). we ignore the 200 OK signal, use audio signal instead" />
 <waitForRingbacktone />
 <log value="got ringback tone. waiting for ringback tone absence (voice answer or silence)" />
 <waitForRingbacktoneAbsence />
 <log value="got RBT absence. playing audio file" />
 <playaudio value="music.wav" />
 <exit />
</on>

waitforsilence Waits for RTP audio signal below specified level. Is used to wait for the end of IVR prompt
If there is no RTP, it does not return control. See also: "waitforsignal" Attributes:
maxtime (optional) - timeout of waiting in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
level (optional, default is "-24dB") - threshold level in dB. 0dB corresponds to max level, -6dB to 50%, -[Infinity]dB to silence
minTimeBelowLevel (optional, default is "500ms") - minimal duration of audio below the "level" before exiting the "waitforsilence"
interruptableByDtmf (optional, default is "false") - specifies presence of additional DTMF event handlers in script
<playdtmf value="1" />
<waitforsignal />
<log value="detected IVR audio prompt" />
<waitforsilence />
<log value="detected silence after prompt" />

waitforsignal Waits for RTP audio signal above specified level, measures delay. Is used to verify response times in IVR menus
If there is no RTP, it does not detect any signal and does not return control. If you have problems when call flow hangs in the "waitforsignal", please put "recordcall" with mode="rx" before the "waitforsignal", to record received audio into WAV file and understand what happens. See also: "measuresignal", "waitforsilence" Attributes:
maxtime (optional) - timeout of waiting in milliseconds ("ms" suffix), seconds ("s" suffix) or minutes ("m" suffix)
signaldelayvar (optional) - name of variable to store measured delay in milliseconds. If the "maxtime" timeout expires, it receives a value of "maxtime"
level (optional, default is "-24dB") - threshold level in dB. 0dB corresponds to max level, -6dB to 50%, -[Infinity]dB to silence
minTimeAboveLevel (optional, default is "0ms") - minimal duration of exceeding the "level" before exiting the "waitforsignal"
callLeg (optional, "A" or "B", default is "A") - identifies call leg when doing call transfer
maxlevelvar (optional) - name of variable to save maximal (peak) signal level in decibels, if the "waitforsignal" is aborted by the "maxtime" timeout
<playdtmf value="1" />
<waitforsignal signaldelayvar="ivrDelay"/>
<report name="IVR_delay_1" qualityIsAscending="false" value="$ivrDelay;" />
<!-- RTP media should be established to execute 'waitforsignal' -->
<waitforsignal signaldelayvar="d" level="-15dB" maxtime="3s" minTimeAboveLevel="10ms" />
<log value="delay = $d;ms" />
<log value="received call from $callerId;" />
<accept value="183" />
<waitforsignal signaldelayvar="d" level="-20dB" maxtime="3000ms" />
<log value="signal delay (-20dB) = $d;ms" />
<block test="$d; > 3000">
 <log value="rejecting call: no signal is detected above -20dB within 3 seconds" />
 <reject value="503" />
</block>
<log value="accepting call: signal is detected above -20dB within 3 seconds" />
<accept value="200" />
<playaudio value="music.wav" maxtime="222s" />

writecdr Saves a variable to CDR report, optionally analyses it as numeric performance indicator
Notes:
  • A CDR record represents SIP call, not CallXML session. However it is possible to execute "writecdr" before making a call
  • If you use CDR CSV files, and if your code contains conditional branches (i.e. "writecdr" is not always executed), you should put a "writecdr" with empty value in the beginning of your script, so it will be always executed.
  • CSV CDR file's schema (headers) are updated only for the first call in the file. You may need to delete old CDR CSV files if you add new custom CDR headers
  • If you save CDR to your a database, you need to make CDR field names compatible with SQL syntax: e.g. column name must not start with a digit
See also: "report"
Attributes:
header (required) - header in CDR file
value (required) - variable to be saved
numeric (optional, "true"/"false", default is "false") - specifies whether to analyses variable as numeric performance indicator
qualityIsAscending (optional, "true"/"false") - indicates whether call quality increases or decreases with increasing of the variable. Is used to calculate percentiles and list of worst quality calls
<verifyaudio reference="C:\ivr.wav" maxtime="10s" mosvar="mos" />
<writecdr header="MOS" value="$mos;" numeric="true" qualityIsAscending="true" />
<-- if code contains conditional branches, you should put a "writecdr" with empty value in the beginning of your script, so it will be always executed -->
<writecdr header="callerCountry" value="" />
<if test="$calledId; matches ^\d{11}$">
 <writecdr header="callerCountry" value="Syria" />
</if>
<call value="sip:13108790819@1.2.3.4" />
<on event="answer">
 <writecdr header="call_suceeded" value="1" />
 <playaudio value="music.wav" maxtime="20000ms" />
 <exit />
</on>
<on event="callfailure">
 <writecdr header="call_suceeded" value="0" />
</on>

writefile Writes a text to file. Is used to write files with custom format in CallXML script. Appends text to end of file
Attributes:
value (required) - text to be written to file
fileName (required) - absolute or relative file name
newLine (optional, "true"/"false", default is "false") - specifies whether to insert line break before the text
splitInterval (optional) - enables splitting file into parts periodically, sets the period in seconds ("s" suffix), minutes ("m" suffix) or hours ("h" suffix). Adds a suffix "_yyyyMMdd_HHmmss" to the file name
<readcsv value="b_numbers_2014mar.csv" var0="numB" repeat="5" mode="random" />
<readcsv value="a_numbers.csv" var0="numA" mode="random" />
<log value="calling from $numA; to $numB;" />
<assign var="callStart" value="$time();" />
<call value="sip:$numB;@85.110.209.50" callerId="$numA;" maxringtime="60s" />
<on event="answer">
  <log value="call answered from $numA; to $numB;" />
  <wait value="$rand(1000,3000);ms" />
  <assign var="callEnd" value="$time();" />
  <writefile newLine="true" fileName="F:\ftproot\SUCEEDED.txt" splitInterval="1m"
   value="$callStart;;$callEnd;;$numA;;$numB;"
  />
  <on event="hangup">
   <assign var="callEnd" value="$time();" />
   <writefile newLine="true" fileName="F:\ftproot\SUCEEDED.txt" splitInterval="100m"
    value="$callStart;;$callEnd;;$numA;;$numB;"
   />
  </on>
  <exit />
</on>
<on event="callfailure">
  <log value="call failed from $numA; to $numB;" />
  <assign var="callEnd" value="$time();" />
  <writefile newLine="true" fileName="F:\ftproot\FAILED.txt" splitInterval="1m"
   value="$callStart;;$callEnd;;$numA;;$numB;"
  />
</on>
<on event="maxringtime">
  <log value="call timed out from $numA; to $numB;" />
  <assign var="callEnd" value="$time();" />
  <writefile newLine="true" fileName="F:\ftproot\FAILED.txt" splitInterval="1m"
   value="$callStart;;$callEnd;;$numA;;$numB;"
  />
</on>

CallXML elements - common attributes

All CallXML elements may contain following common attributes:

  • enabled ("true"/"false", default "true") - is used to turn off a CallXML element.

Substitutions

Attributes in script may contain substitutions. A substitution starts with '$' and ends with ';'. It is replaced in runtime with another string depending on type of substitution.

$rand(x); is replaced by random integer value which is exponentially distributed from 0 to infinity with mean of x
$rand(x,y); is replaced by random integer value which is uniformly distributed from x (inclusive) to y (inclusive)
$randswitch(case1,case2,case3,...); is replaced by one of optional cases, selected randomly
$randdigits(number_of_digits); is replaced by a string of random digits from 0 to 9, with specified length = number_of_digits
$randfile(path\mask); is replaced by a random file from directory:
<playaudio value="$randfile(C:\StarTrinity\wav\*.wav);" />
The directory search is performed in main SIP thread, so large directories can slow down the software
$x; is replaced by value of variable with name x. Variable names are not case-sensitive. Name of variable can be computed dynamically from a prefix and another variable: $prefix$suffixVar;; or $arrayName[$arrayIndex;];
$global.x; is replaced by value of global variable with name x Name of global variable can be computed dynamically from a prefix and another variable: $global.prefix$suffixVar;; or $global.someCache[$key;];
$time();, $time(format); is replaced by current date and time:
<recordmessage value="d:\recordings\$time(yyyyMMdd_HH_mm_ss_fff);.wav" />

Note: the software uses QueryPerformanceCounter() procedure inside to get accuracy of microseconds and avoid time jumps when system clock is updated (so the "$time();" always increments without interruptions). As a drawback, there can be a small time drift between the "$time();" and system clock, it can be rset by restarting SIP Tester.

$timeMs(); is replaced by software uptime in milliseconds. Can be used to calculate delays:
<assign var="t1" value="$timeMs();"/>
<call value="sip:test@23.45.67.89:5060" />
<on event="answer">
 <assign var="delay" mathvalue="$timeMs(); - $t1;"/>
 <log value="delay = $delay;ms" />
 <exit />
</on>
$timeOfDayInMinutes(); is replaced by number of minutes between current moment and previous midnight
$timeOfHourInMinutes(); is replaced by number of minutes between current moment and beginning of current hour
$param.x; is replaced by value of parameter which is defined in <params> section inside the script
$env.x; is replaced by windows environment variable:
<log value="temp directory: $env.TMP;; user name: $env.USERNAME;; windows directory: $env.windir;; machine name: $env.COMPUTERNAME;" />
$ext(x); is replaced by 'Contact' header of registered extension (see UAC registrations)
<transfer value="$ext(100);"/>

XML escape characters

According to XML specifications of the W3C, there are 5 characters that must not appear in their literal form in an XML document. The characters must be replaced according to table:
Original character XML replacement
" &quot;
' &apos;
& &amp;
" &quot;
< &lt;
> &gt;
Example:
<call value="sip:111@10.10.10.1?user=XXX&amp;password=YYY" />
You can use this tool to escape the characters automatically

Default variables

  • answerDelay - for outgoing calls after answer: answer delay in milliseconds
  • calledId - user ID (number) in "To" SIP header
  • callerId - user ID (number) in "From" SIP header
  • callerIdName - display name in "From" SIP header
  • callerIpAddress - IP address of SIP call initiator. Is taken from IP protocol (layer 3)
  • callNumberInBurst - number of call in burst, when generating calls in burst mode, starts from 0
  • eventSubType - subtype of event which is currently handled by "on" CallXML element. Contains additional information about the event
  • eventType - type of event which is currently handled by "on" CallXML element
  • Id - CallXML session identifier. Starts with 0, increments sequentially. Is reset to 0 when call generator is started ("Start" button is clicked) if setting "ResetCallXmlSessionIdWhenStartedCallGenerator" is set to 1
  • launcherType - identifies the way how the CallXML script is launched: "cli" - SIP Tester CLI; "gui" - SIP Tester GUI; "softswitch" - Softswitch
  • originatorId - identifier of current originator. Is set by "performAAA" CallXML element
  • language - language of current originator. Is set by "performAAA" CallXML element. Is used to play IVR files from corresponding folder
  • redirectedNumber - user ID (number) in "Diversion" SIP header for incoming calls
  • sdpAttribute[name] - prefix for variables which contain attributes of remote SDP. Example: sdpAttributeptime, sdpAttributefmtp[0], sdpAttributefmtp[1], sdpAttributertpmap[2]
  • sipCallId - "Call-ID" SIP header
  • sipHeader[name] - prefix for variables which contain headers of "INVITE" packet for incoming calls and "INVITE provisional response" packet for outgoing calls. For outgoing calls the variables are accessible in "pr", "answer" and "callfailure" event handlers. Example: sipHeaderVia, sipHeaderVia[0], sipHeaderVia[1]. Note: please use CallXML element "getsiptrace" to have full access to received and transmitted SIP messages, and SIP headers, SDP attributes
  • tenantId - identifier of current tenant, in softswitch multi-tenant mode. Is set by "performAAA" CallXML element

Attributes which are common to all CallXML elements

  • enabled ("true"/"false", default is "true") - turns off execution of a CallXML element. Is used to temporarily disable and enable some parts of the CallXML script
  • label - is used to identify the destination CallXML element in "goto"

Boolean expressions

The boolean expressions are used in "if", "block" and "goto" CallXML elements and in CDR display filter. The expression contain one or many comparisons, parentheses, boolean operators, strings in single quotes. Comparison operators are:
<less than
<=less than or equal
>greater than
>=greater than or equal
=, ==equal
!=, <>inequal
startswithleft operand starts with prefix (right operand)
matchesleft operand matches to regular expression (right operand)
containsleft operand contains right operand as a substring
Boolean operators are:
&, &&, and|, ||, or
Strings which are considered as "boolean false":
false0[empty string]
Examples of boolean expressions for CallXML script:
  • $calledId; = 98764352343
  • $callerId; startswith 123 or $calledId; = 345
  • $callerId; = 123456 and $calledId; = 1345678
  • 'a=123' = 'a=123'
Examples of boolean expressions for CDR filter:
  • Answered_Duration > 1000
  • Answered_Duration > 1000 and (CalledId startswith 10 or CalledId startswith 11)
  • Disconnection_Status = 200
  • Answer_Delay > 10000
  • CalledId = 123456
  • CallerId = 123456
  • CallerId contains 456
  • SIP_CallId = asefruyhnsdfteomhu7sngd@10.10.10.20
  • MyCustomCdrField1 > 10000 and MyCustomCdrField2 != OK
List of available CDR columns (fields) is displayed in GUI (CDR - fields..)
Copyright 2011-2024 StarTrinity.com | Blog | Contact lead developer via LinkedIn |