mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
553 lines
16 KiB
553 lines
16 KiB
DSM quick reference
|
|
===================
|
|
|
|
Syntax
|
|
======
|
|
-- comment
|
|
#include "script.dsm"
|
|
#include "/path/to/anotherscript.dsm"
|
|
import(mod_name);
|
|
|
|
[initial] state name
|
|
[ enter {
|
|
<actions>
|
|
} ]
|
|
[ exit {
|
|
<actions>
|
|
} ]
|
|
;
|
|
|
|
transition name s1 - [ { [not] condition; [not] condition; ... } ] [/ { <actions>} ] -> s2;
|
|
or
|
|
transition name (s1a, s1b[, s1c, ...]) - [ { [not] condition; [not] condition; ... } ] [/ { <actions> } ] -> s2;
|
|
or (exception transition)
|
|
transition name s1 - exception [ { [not] condition; ... } ] [/ { <actions>} ] -> s2;
|
|
|
|
|
|
function func_name() {
|
|
<actions>
|
|
};
|
|
|
|
<actions> ::=
|
|
action;
|
|
action(param, param, ...);
|
|
|
|
if condition; condition; {
|
|
<actions>
|
|
} else {
|
|
<actions>
|
|
}
|
|
|
|
func_name();
|
|
...
|
|
|
|
|
|
Variables, event parameters, selects
|
|
====================================
|
|
|
|
#paramname uses the event parameter 'paramname' (from current event)
|
|
$varname uses the variable varname (from session's variable)
|
|
@selectname uses the "select" 'selectname' (from the session's dialog)
|
|
|
|
use ## for # (e.g. set($hash=##); )
|
|
$$ for $ (e.g. set($dol=$$); )
|
|
@@ for @ (e.g. set($at=@@); )
|
|
|
|
Variable arrays:
|
|
$myarray[0]
|
|
$myarray[1]
|
|
...
|
|
|
|
Variable structs:
|
|
$mystruct.member1
|
|
$mystruct.member2
|
|
|
|
Core actions
|
|
============
|
|
|
|
DSM flow
|
|
--------
|
|
|
|
|
|
-- call/jump/return sub-FSM
|
|
jumpFSM(name)
|
|
callFSM(name) - note that actions after callFSM may have the event & event params of the sub-FSM
|
|
returnFSM()
|
|
|
|
stop(<send bye>)
|
|
e.g. stop(false), stop(true)
|
|
|
|
-- reprocess the current event after transition:
|
|
repost()
|
|
|
|
Variable manipulation
|
|
---------------------
|
|
|
|
set($var=value)
|
|
e.g. set($var="text"); set($var=$var2); set($var=#key)
|
|
sets($var=value)
|
|
e.g. sets($var="text and some $variable and some #param");
|
|
var($dstvar=srcvarname)
|
|
e.g. var($dstvar=$var_counter)
|
|
param($dstvar=srcparamname)
|
|
e.g. param($dstvar=$myparam) (like: #($myparam) )
|
|
eval($var=value)
|
|
evaluate expression (only simple binary + and - supported)
|
|
e.g. set($var=1+5); set($var=$var2); set($var=#key)
|
|
append($var, value)
|
|
e.g. append($var, "text"); append($var, #key);
|
|
append($var, @select); append($var, $var2);
|
|
substr($var, pos)
|
|
e.g. substr($myvar, 5);
|
|
|
|
size($arrayname, $dst);
|
|
set variable $dst to size of array
|
|
(e.g. $arrayname[0], $arrayname[1] set, $dst set to 2)
|
|
|
|
inc($var)
|
|
clear($var)
|
|
clearArray($var)
|
|
clears all var.* variables
|
|
|
|
Playing prompts and file I/O
|
|
----------------------------
|
|
|
|
playPrompt(param)
|
|
from promptCollection, e.g. playPrompt("hello");
|
|
if $prompts.default_fallback=yes, default prompt set is tried if
|
|
prompt not found in current prompt set
|
|
Throws "prompt" exeption with #name if prompt not found.
|
|
playPromptFront(param) - play a prompt at first item in the playlist
|
|
playPromptLooped(param)
|
|
|
|
setPromptSet(name)
|
|
select active prompt set if more prompt sets are loaded
|
|
Throws "prompt" exeption with #name if prompt set not found
|
|
|
|
playFile(filename [, loop=true])
|
|
e.g. playFile($myfile, true); will play the file looped.
|
|
Throws "file" exeption with #path if file can not be opened
|
|
|
|
playFileFront(filename [, loop=true])
|
|
e.g. playFileFront($myfile, true); will play the file at first
|
|
position in the playlist, and looped.
|
|
Throws "file" exeption with #path if file can not be opened
|
|
|
|
playSilence(millisec) - play silence for millisec ms
|
|
playSilenceFront(millisec) - play silence for millisec ms at first position in playlist
|
|
|
|
recordFile(filename)
|
|
Throws "file" exeption with #path if file can not be opened for recording
|
|
|
|
stopRecord()
|
|
getRecordLength([dst_varname]) -- only while recording! default dst var: record_length
|
|
getRecordDataSize([dst_varname]) -- only while recording! default dst var: record_data_size
|
|
flushPlaylist()
|
|
setInOutPlaylist()
|
|
set playlist as input and output
|
|
setInputPlaylist()
|
|
set playlist as input (output untouched)
|
|
setOutputPlaylist()
|
|
set playlist as output (input untouched)
|
|
addSeparator(id [, bool front])
|
|
fires event when playlist hits it ; front=[true|false]
|
|
connectMedia() - set playlist as input and output of session,
|
|
and start processing of RTP and audio
|
|
(connect to mediaprocessor)
|
|
disconnectMedia() - stop processing of RTP and audio (disconnect from mediaprocessor)
|
|
|
|
enableReceiving() - enable processing of received RTP
|
|
disableReceiving() - disable processing of received RTP
|
|
|
|
enableForceDTMFReceiving() - enable/disable RTP DTMF packets processing even
|
|
disableForceDTMFReceiving() if received RTP is not processed, e.g. after
|
|
disableReceiving() or in passive mode
|
|
(only for RFC2833/4733 DTMF, *no* in-band)
|
|
monitorRTPTimeout(enabled=false)
|
|
set call to monitor RTP timeout (enabled="true" or "false")
|
|
|
|
mute() - set RTP stream to muted (don't send RTP packets)
|
|
unmute() - set RTP stream to unmuted (do send RTP packets)
|
|
|
|
DTMF
|
|
----
|
|
|
|
enableDTMFDetection()
|
|
disableDTMFDetection()
|
|
|
|
sendDTMF(key [, duration_ms])
|
|
send a DTMF event (RFC4733 event)
|
|
duration_ms defaults to 500ms
|
|
|
|
sendDTMFSequence(sequence [, duration_ms])
|
|
send a sequence of DTMF events (RFC4733 event), e.g. 123#45*1
|
|
duration_ms defaults to 500ms
|
|
|
|
B2B call control
|
|
----------------
|
|
B2B.connectCallee(remote_party, remote_uri)
|
|
connect second leg of B2B session (see AmB2BSession)
|
|
R-URI = remote_uri
|
|
To = remote_party
|
|
From = $b2b_local_party
|
|
auth = ($b2b_auth_user, $b2b_auth_pwd)
|
|
Call-ID = $b2b_callid
|
|
$b2b_relayed_invite=[true|false] : use relayed INVITE mode
|
|
|
|
B2B.terminateOtherLeg
|
|
disconnect second leg of B2B session (see AmB2BSession),
|
|
e.g. to connect to a new destination
|
|
note: don't use this when receiving BYE in an established
|
|
B2BUA call, as the BYE is sent end-to-end
|
|
|
|
B2B.sendReinvite(generate_sdp [, string extra_headers])
|
|
send a reinvite in caller leg (first leg), e.g. to
|
|
reconnect first leg after B2B.otherBye received.
|
|
generate_sdp can be 'true' or 'false'
|
|
(B2B.sendReinvite(true) recommended)
|
|
|
|
B2B.clearHeaders()
|
|
clear the headers used for outgoing INVITE on B leg
|
|
|
|
B2B.enableEarlyMediaRelay(enable=[true|false])
|
|
enable or disable relaying of early media SDP (180-183) as re-Invite in the first leg
|
|
|
|
B2B.addHeader(string header)
|
|
add a header for outgoing INVITE on B leg
|
|
|
|
B2B.removeHeader(string header_name)
|
|
remove a header for outgoing INVITE on B leg
|
|
|
|
B2B.setHeaders(string headers [, replace_crlf=true|false])
|
|
set headers for outgoing INVITE on B leg
|
|
replace_crlf=true for replacing \r\n with CRLF
|
|
e.g.
|
|
B2B.setHeaders("P-One: value\r\nP-Two: anothervalue", true)
|
|
|
|
B2B.relayEvent(variable_name;variable_name;...)
|
|
relay B2Bevent to related B2B session; variables copied as event parameters
|
|
e.g. B2B.relayEvent(var1;var2;var3) relay event with var1, var2, var3
|
|
|
|
B2B.relayEvent("var")
|
|
relay B2Bevent to related B2B session with all variables of current DSM session
|
|
|
|
Logging
|
|
-------
|
|
|
|
log(level, text)
|
|
e.g. log(1, $var1)
|
|
-- log all variables:
|
|
logVars(level)
|
|
-- log all selects:
|
|
logSelects(level)
|
|
-- log all Params (only in actions of a transition):
|
|
logParams(level)
|
|
-- log everything:
|
|
logAll(level)
|
|
|
|
Timers
|
|
------
|
|
|
|
setTimer(timer_id, timeout)
|
|
e.g. setTimer(1, $timeout)
|
|
* sets $errno (arg,config)
|
|
removeTimer(timer_id)
|
|
* sets $errno (arg,config)
|
|
removeTimers()
|
|
* sets $errno (config)
|
|
|
|
DI functions
|
|
------------
|
|
DI(factory, function [, params...])
|
|
execute DI function
|
|
e.g. DI(factory, function, $var_param, (int)int_param, "str param", @select_par, (array)arrayname, (struct)structname, (json)json_object...)
|
|
DI(monitoring, set, "mytable", @local_tag, (int)1);
|
|
|
|
set($sweets.candy="nice");
|
|
set($sweets.fruit="superb");
|
|
set($sweets.cake.tahini="great");
|
|
DI(myfactory, myfunc, (struct)sweets);
|
|
|
|
set($bi[0]="ba");
|
|
set($bi[1]="butzki");
|
|
DI(myfactory, myfunc, (array)bi);
|
|
|
|
set($js="{"x":"y", "a": 1}");
|
|
DI(myfactory, myfunc, (json)$js);
|
|
|
|
* sets $errno (arg,config)
|
|
|
|
DIgetResult(factory, function, param,...)
|
|
saves result from DI call to DI_res or DI_res0, DI_res1, ...
|
|
* sets $errno (arg,config)
|
|
|
|
Exception handling
|
|
------------------
|
|
throw(<type>[,arg1=val1;arg2=val2;...])
|
|
e.g. throw(bad_command), throw(bad_command,cmd=help;reason=whynot)
|
|
|
|
throwOnError()
|
|
|
|
Events
|
|
------
|
|
postEvent(sess_id[, variable_name;variable_name;...])
|
|
post dsm event to session sess_id; variables copied as event parameters
|
|
e.g. postEvent(@local_tag, PAI) : post event to ourselves
|
|
postEvent($some_call, var1;var2;var3) post event with var1, var2, var3
|
|
* sets $errno (arg)
|
|
|
|
postEvent(sess_id, var)
|
|
all local variables copied as event variables
|
|
* sets $errno (arg)
|
|
|
|
registerEventQueue(queue_name)
|
|
register session to receive events under the name queue_name
|
|
WARNING: make sure to unregister the event queue before ending the session!
|
|
|
|
unregisterEventQueue(queue_name)
|
|
unregister events queue queue_name
|
|
|
|
Object memory management/Garbage collector:
|
|
freeObject(varname) - free object referenced with varname immediately
|
|
trackObject(varname) - track object referenced with varname, i.e. enable garbage
|
|
collection with the current call/systemDSM
|
|
releaseObject(varname) - release object referenced with varname from garbage collector
|
|
|
|
Conditions
|
|
==========
|
|
|
|
Conditions are combined as AND, i.e. a transition is executed if all conditions match.
|
|
|
|
Generic conditions (regardless of the type of the event):
|
|
test(#key == 1)
|
|
test(#key == prefix*)
|
|
test(#key != 1)
|
|
test(#key < 1)
|
|
test(#key > 1)
|
|
|
|
test($var == 1)
|
|
test($var == prefix*)
|
|
test($var != 1)
|
|
test($var < 1)
|
|
test($var < 1)
|
|
|
|
test(len($var) < len(#key))
|
|
test(len($var) < len(@user))
|
|
|
|
Other conditions only match on the type of event and when the expression expr in the
|
|
brackets match.
|
|
|
|
start
|
|
start of a session (onStart). This event is processed before any other.
|
|
|
|
hangup
|
|
bye/cancel received
|
|
parameters:
|
|
#headers - headers of the BYE/CANCEL request
|
|
|
|
key(expr) or keyTest(expr)
|
|
parameters:
|
|
#key - Key pressed (0 - 11, * is 10, # is 11)
|
|
#duration - duration of key press
|
|
|
|
timer(expr) or timerTest(expr)
|
|
parameters:
|
|
#id - Timer ID
|
|
|
|
noAudio(expr) or noAudioTest(expr)
|
|
parameters:
|
|
#type - "cleared" (audio cleared) or "noAudio" (playlist empty)
|
|
|
|
separator(expr) or separatorTest(expr)
|
|
parameters:
|
|
#id - Separator ID
|
|
e.g. separatorTest(#id == 5)
|
|
|
|
event(expr) or eventTest(expr)
|
|
generic event, e.g. passed from DI or another call with postEvent
|
|
parameters depend on the DI call/the ones passed with postEvent
|
|
|
|
B2Bevent(expr)
|
|
generic event from B2B related call leg
|
|
parameters depend on the ones passed with B2B.relayEvent
|
|
|
|
keyPress(key)
|
|
alias to key(#key==key)
|
|
|
|
remoteDisappeared(expr)
|
|
remote end in an established call is unreachable (408/481 received)
|
|
parameters: see sipReply (below), except #old_dlg_status
|
|
|
|
set #processed="true" if you don't want default behaviour (clear call)
|
|
|
|
sessionTimeout(expr)
|
|
session expired (SST)
|
|
parameters: none
|
|
|
|
set #processed="true" if you don't want default behaviour (clear call)
|
|
|
|
rtpTimeout(expr)
|
|
RTP timeout detected
|
|
|
|
#type - "rtp_timeout"
|
|
#timeout_value - RTP timeout value (as configured)
|
|
|
|
set #processed="true" if you don't want default behaviour (clear call)
|
|
|
|
invite
|
|
invite received/sent (only with run_invite_event):
|
|
parameters: none
|
|
|
|
ringing
|
|
outgoing call: ringing reply, 180 (only with run_invite_event):
|
|
parameters:
|
|
#code - SIP response code, e.g. 180
|
|
#reason - SIP reason string, e.g. "Ringing"
|
|
#has_body - "true" or "false"
|
|
|
|
early
|
|
outgoing call: early session, 183 (only with run_invite_event):
|
|
parameters: none
|
|
|
|
failed
|
|
outgoing call failed (only with run_invite_event):
|
|
parameters:
|
|
#code - SIP response code, e.g. 404
|
|
#reason - SIP reason string, e.g. "Not found"
|
|
|
|
sessionStart
|
|
start of session (with run_invite_event):
|
|
parameters: none
|
|
|
|
startup
|
|
startup of a system DSM
|
|
parameters: none
|
|
|
|
reload
|
|
reload (system DSM)
|
|
|
|
system
|
|
system event - shutdown or SIGNAL sent (kill <pid>)
|
|
parameters:
|
|
#type - system event type, e.g. ServerShutdown, User1, User2
|
|
|
|
B2B.otherRequest (only sbc)
|
|
Request on other B2B leg received
|
|
parameters:
|
|
#method, #r_uri, #from, #to, #hdrs - from request
|
|
|
|
B2B.otherReply
|
|
Reply on other B2B leg received
|
|
parameters:
|
|
#code - reply code
|
|
#reason - reply reason
|
|
#hdrs - headers
|
|
#trans_method - transaction method (only sbc)
|
|
|
|
B2B.otherBye
|
|
BYE on other leg received
|
|
#hdrs - headers
|
|
|
|
sipRequest
|
|
SIP request received - only executed if enable_request_events=="true"
|
|
parameters:
|
|
#method - SIP method
|
|
#r_uri - request URI
|
|
#from - From
|
|
#to - To
|
|
#hdrs - Headers (apart from dialog-IDs)
|
|
#content_type - Content-Type
|
|
#body - body of message
|
|
#cseq - CSeq
|
|
|
|
sipReply
|
|
SIP reply received - only executed if enable_reply_events=="true"
|
|
parameters:
|
|
#code - response code
|
|
#reason - reason string
|
|
#hdrs - Headers (apart from dialog-IDs)
|
|
#content_type - Content-Type
|
|
#body - body of message
|
|
#cseq - CSeq
|
|
|
|
#dlg_status - SIP dialog status (Disconnected, Trying, ...)
|
|
#old_dlg_status - old SIP dialog status (before this reply)
|
|
|
|
|
|
jsonRpcRequest - json-rpc request received
|
|
parameters:
|
|
#ev_type - JsonRpcRequest
|
|
#method - RPC method
|
|
#is_notify - "true" or "false"
|
|
#id - request ID (if present)
|
|
|
|
#params.* - parameters array
|
|
|
|
subscription - SIP subscription status
|
|
#status - status: "active", "pending", "failed", "terminated", "timeout"
|
|
#code - SIP response code (if failed)
|
|
#reason - SIP response reason (if failed)
|
|
NOTIFY body in avar[DSM_AVAR_SIPSUBSCRIPTION_BODY] (if #status=="active")
|
|
|
|
jsonRpcResponse - json-rpc response received
|
|
#ev_type - JsonRpcResponse
|
|
#id - response ID
|
|
#is_error - "true" or "false"
|
|
#udata - user data that was saved when sending the request
|
|
|
|
#result.* or #error.* - response data array (or error data)
|
|
|
|
conference events:
|
|
generic events with
|
|
#type - "conference_event"
|
|
#id - event ID
|
|
|
|
Selects
|
|
=======
|
|
selects :
|
|
@local_tag
|
|
@user
|
|
@domain
|
|
@remote_tag
|
|
@callid
|
|
@local_party
|
|
@local_uri
|
|
@remote_uri
|
|
@remote_party
|
|
|
|
Importing modules
|
|
=================
|
|
|
|
module imported with import(mod_name); loads mod_name.so in
|
|
module load path. modules provide conditions and actions.
|
|
modules' actions/conditions-factory is checked first
|
|
(modules can override core conditions/actions)
|
|
|
|
Variables controlling call flow
|
|
===============================
|
|
special variables:
|
|
connect_session "0" -> after the start event (initial transition):
|
|
do not connect session to
|
|
media processor on start
|
|
|
|
-> after the invite event:
|
|
do not reply with 200 OK and do not
|
|
connect session to media processor on start
|
|
enable_request_events "true" - run events on receiving a request
|
|
"false" - don't run events on receiveing request
|
|
|
|
|
|
b2b_local_party - From in outgoing B2B call
|
|
b2b_local_uri - URI of From for B2B call, for application internal use
|
|
b2b_auth_user - SIP auth user for 2nd leg of B2B call
|
|
b2b_auth_pwd - SIP auth pwd for 2nd leg of B2B call
|
|
|
|
=============================
|
|
errors:
|
|
actions set $errno
|
|
#define DSM_ERRNO_OK ""
|
|
#define DSM_ERRNO_FILE "1"
|
|
#define DSM_ERRNO_UNKNOWN_ARG "2"
|
|
#define DSM_ERRNO_GENERAL "99"
|
|
...
|