tSIP softphone: "script" button type and event scripts

"Script" button executes small Lua script when clicked. It may partially duplicate script.dll plugin functionality, but while script.dll is intended to control softphone for arbitrary time (i.e. use delays) script button should be limited to running code that executes immediately. Same scripts can be also executed automatically, on events like call state change (call confirmed, call disconnected, etc.), registering or unregistering.

To assign Lua script to button create "script" subdirectory in softphone folder and place script file in this location. Use any text editor for editing script and "print" function for debugging purposes.
Script button configuration

Lua is extended with following commands:

Call(number)
enter specified digits and start calling
Hangup()
end current call
Answer()
answer current incoming call
SetDial(number)
set number edit field
GetDial()
get dial edit content
GetClipboardText()
text from system clipboard
SetClipboardText(text)
set text in system clipboard
Sleep(ms)
pause execution for specified time in miliseconds; not recommended as UI is blocked but can be used in combination with Beep() to create audible feedback
Beep(freq, time)
equivalent for WinAPI Beep() (PC speaker or - with 64 bit windows - default audio output)
ShowMessage
display standard modal Win32 message
MessageBox
direct equivalent of WinAPI function with the same name
  MessageBox("message with just [OK] button", "message title", 0)
  MessageBox("message with ICON_INFORMATION", "message title", 64)
  local res = MessageBox("message with MB_YESNO and question icon", "message title", 4+32)
  if res == 6 then
  	ShowMessage("\"Yes\" was pressed")
  else
  	ShowMessage("Result is other than \"Yes\"")
  end  
  
SwitchAudioSource(module, device)
change audio source used during current call or streaming, e.g. SwitchAudioSource("aufile", "test.wav"), SwitchAudioSource("winwave", "USB Phone")
SendDtmf(digits)
send DTMF characters to current call, e.g. SendDtmf("1234*#)
BlindTransfer(phone_num)
transfer (blind) current call to specified destination, e.g. BlindTransfer("123")
GetCallState()
returns current call state: integer value according to Callback::ua_state_e, i.e.
	enum ua_state_e
	{
		CALL_STATE_CLOSED = 0,
		CALL_STATE_INCOMING, // 1
		CALL_STATE_OUTGOING, // 2, etc.
		CALL_STATE_TRYING,
		CALL_STATE_RINGING,
		CALL_STATE_PROGRESS,
		CALL_STATE_ESTABLISHED,
	}   
    
IsCallIncoming()
returns non-zero if call direction = outgoing
GetCallPeer()
returning caller or callee number (i.e. second party, depending on call direction)
GetStreamingState()
information if RTP streaming is currently active - int as in Callback::paging_tx_state_e enum
GetInitialCallTarget() and SetInitialCallTarget(number)
function pair intented to be use for "on making call" event, allowing to override number dialed by the user - see HOWTO list, SIP originate for example use
ShellExecute(...)
built-in Lua os.execute() displays nasty command line windows; this function gives access to WinAPI ShellExecute; example: ShellExecute("open", "nircmd.exe", "speak text \"Luke, I am your father\"", nil, 1)

Functions that allow passing data between different scripts or from one script execution to another are worth special mention. As scripts are running in GUI thread context they are intented to run to completion in short time (i.e. use of Sleep() should be limited even if it does not block GUI message processing) and they are mostly uninterruptible. As some uses require keeping some state data (e.g. original call target that was replaced in case of SIP originate function) following function were added:

SetVariable("name", "value")
set text "value" for variable with specified "name" (variables are holding text and are indexed by text)
value, isset = GetVariable("name")
read back variable value; function returns two variables (Lua can do this) and if variable was not set before then isset equals 0
ClearVariable("name")
"unset" variable (remove "name" from variables map)
ClearAllVariables()
clear ("unset") all variables

Output of print() is passed to application log window.

Examples

Call to number from clipboard

txt = GetClipboardText()
print(string.format("Clipboard text = %s, dialing...\n", txt))
Call(txt)  
  

"Normalize" number entered in dial box

-- get number from softphone dial edit
txt = GetDial()
print(string.format("Dial text = %s\n", txt))
-- remove leading zeroes
nonzero = 1
for i=1, string.len(txt) do
	if string.sub(txt, i, i) ~= "0" then
		do
			print(string.format("Non-zero at index %d (%s)\n", i, string.sub(txt, i, i)))
			break
		end
	else
		nonzero = i+1  
	end
end
txt = string.sub(txt, nonzero)
print(string.format("Leading zeroes removed: %s\n", txt))
-- add (default) country prefix code if not present
if string.len(txt) == 9 then
	txt = "48" .. txt
end
print(string.format("Country code added: %s\n", txt))
-- add CO access code for PABX
txt = "00" .. txt
print(string.format("Setting number to dial: %s\n", txt))
-- set processed number back in dial edit
SetDial(txt)
-- or: Call(txt)  
  

Call to specified number (conference room) and enter code

-- user config
number = "123456789"
dtmf = "1234"
-- end of user config
 
Call(number)
for i=1, 20, 1
do
	if (i == 20) then
		print("Timed out waiting for confirmed state\n")
		break;
	end
 
	Sleep(300)
	call_state = GetCallState()
	if call_state == 6 then
		-- CALL_STATE_ESTABLISHED
		Sleep(2000)
		SendDtmf("1234")
		break
	elseif call_state == 0 then
		-- CALL_STATE_CLOSED
		print("End of call\n")
		break;
	end
end
print("End of script\n")  
  

Back to tSIP softphone


 "Cookie monsters": 2672716    Parse time: 0.001 s