Pause/Resume EFCX Call Recording
Introduction
Basic Working
Pause/resume service expects a post request with the extension of an agent. After receiving the request it makes a connection with freeswitch using ESL(Event Socket Lib). It run a command “show calls” and retrieve all the calls active at that time. A command using
uuid_broadcast uuid record_session_mask::${record_path}/${recording_filename} both
will be sent to mask the call
The call will be paused in a sense that it would be masked and that portion will be muted. An as soon as the call is unmasked it will be recording once again.

Architecture
Inside Apis we have two end point in the controller that handles pause and resume request. With pause and resume service we have an ESL service responsible for the connection making and handling. Inside Pause and resume service we have two major functions one is to mask and other is to umask. These functions are dependent on esl connection for fetching call information and also on another function that extract all the useful information from the response and help masking or unmasking a call.
ESL connection
To Connect to FreeSwitch CLI we use the ESL(Event Socket Layer) libraries, It helps make connections with the free-switch using host, port, and password. Once the connection is established it fetches all the information from free-switch and also it gives commands to free-switch.
public class EslService {
private String eslHost = System.getenv("ESL_HOST");
private int eslPort = Integer.parseInt(System.getenv("ESL_PORT"));
private String eslPassword = System.getenv("ESL_PASSWORD");
private Client inboundClient;
private String recordingPath = System.getenv("REC_PATH_STREAMS");
public EslService() throws InboundConnectionFailure {
inboundClient = new Client();
inboundClient.connect(new InetSocketAddress(eslHost, eslPort), eslPassword, 10);
log.debug("ESL Connection established");
}
...
Configuration
In Pom.xml we need to add the following dependencies.
<dependency>
<groupId>esl-client</groupId>
<artifactId>esl-client</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.56.Final</version>
</dependency>
...
We need further env variables
ESL_HOST = where the freeswitch is up and running
ESL_PORT = ESL makes connection with 8021
ESL_PASSWORD = Password of the freeswitch
Update the Lua script
Go to the /usr/share/freeswitch/scripts/
Find the file with the name set_recording_name.lua script file
look for a line in the script session:setVariable("recording_filename" , agent_leg_uuid .. "." .. ext) and update it to session:setVariable("recording_filename" , customer_leg_uuid .. "." .. ext)
Here is the full lua script as a reference. it is very crucial for Pause/Resume of Call recording.
CODEpackage.cpath ="/usr/lib/x86_64-linux-gnu/lua/5.2/?.so;" .. package.cpath package.path = "/usr/share/lua/5.2/?.lua;" .. package.path local callType = session:getVariable("sip_h_X-CallType") local record_path = session:getVariable("record_path") local uuid = session:getVariable("uuid") local ext = session:getVariable("record_ext") local customer_leg_uuid = '' local api = freeswitch.API(); -- can be consult, OUT, MONITOR, PROGRESSIVE, local function fileExists(file) local f = io.open(record_path .. '/' .. file, 'r') if f == nil then -- freeswitch.consoleLog("ERROR", "set_recording_name.lua FILE NOT FOUND: " .. file) return false; end io.close(f); -- freeswitch.consoleLog("ERROR", "set_recording_name.lua FILE WAS FOUND: " .. file) return true; end local destination = tostring(session:getVariable("destination_number")) -- freeswitch.consoleLog("NOTICE", " \n set_recording_name.lua DESTINATION \n " .. destination) if (callType == "CONSULT") then freeswitch.consoleLog("NOTICE", " \n set_recording_name.lua RECORDING CONSULT CALL \n") session:execute("stop_record_session","all") if (string.match(tostring(destination), "99887766")) then return end local filename = uuid .. "." .. ext session:setVariable("recording_command" , "nolocal:execute_on_answer=record_session " .. record_path .. "/" .. filename) session:setVariable("recording_filename" , filename) return elseif (callType == "MONITOR") then -- no recording enabled here return -- callType == "PROGRESSIVE" or elseif (callType == "OUT") then -- for manual outbound use the preset other leg uuid i.e. customer leg uuid customer_leg_uuid = session:getVariable("customer_leg_uuid") freeswitch.consoleLog("NOTICE", " \n set_recording_name.lua UUID \n " .. uuid) freeswitch.consoleLog("NOTICE", " \n set_recording_name.lua CUSTOMER \n" .. customer_leg_uuid) if (uuid ~= customer_leg_uuid) then freeswitch.consoleLog("NOTICE", " \n set_recording_name.lua RECORDING MANUAL OUTBOUND CALL \n") session:setVariable("recording_command" , "nolocal:execute_on_answer=record_session " .. record_path .. "/" .. customer_leg_uuid .. "." .. ext) session:setVariable("recording_filename" , customer_leg_uuid .. "." .. ext) return end session:execute("stop_record_session","all") local res = api:executeString("bgapi uuid_broadcast " .. uuid .. " stop_record_session::all") uuid = customer_leg_uuid end local filename = uuid -- inbound ivr case freeswitch.consoleLog("NOTICE", "\n set_recording_name.lua RECORDING INBOUND CALL \n") local count = 0 while (fileExists(filename .. '.' .. ext)) do count = count + 1 filename = uuid .. '_' .. count end local suffix = '_' .. count if (count == 0) then suffix = '' end filename = uuid .. suffix.. "." .. ext session:setVariable("recording_filename" , filename) session:setVariable("recording_command" , "nolocal:execute_on_answer=record_session " .. record_path .. "/" .. filename)
ESL connection on Free-switch
Go to /etc/freeswitch/autoload_configs/event_socket.conf.xml and add the following lines
- CODE
<settings> <param name="listen-ip" value="192.168.1.106"/> <!-- Use the server's IP --> <param name="listen-port" value="8021"/> <!-- Default ESL port --> <param name="password" value="1234"/> <!-- Default ESL password --> <param name="apply-inbound-acl" value="esl"/> </settings>
Go to /etc/freeswitch/autoload_config/acl.conf.xml and add the following lines
<list name="esl" default="allow">
<node type="allow" cidr="0.0.0.0/0"/>
</list>
Type ‘fs_cli’ on your terminal it will open free-switch CLI and then run this command ‘reloadxml’ in fs_cli
Type ‘fs_cli’ on your terminal it will open free-switch CLI and then run this command ‘reloadacl’ in fs_cli
Restart the freeswitch using
sudo systemctl restart freeswitch
run ./install-efcx script to restart the vrs.
Controller end
We have two different APIs for pause and resume. Both of them awaits a post request containing extension of the customer. Then end point are as follows
//For masking the call
http://localhost:8080/vrs/recording/{extension}/pause
//For unmasking the call
http://localhost:8080/vrs/recording/{extension}/resume