About
Discussion and examples for using the Outbound Event Socket.
mod_event_socket's "socket" app is similar to the network based fast-agi (FAGI) of Asterisk. This application makes an outbound TCP connection to the specified ip:port and the other end can control the call in similar ways to an Asterisk AGI only the dialect is much different and it supports async operations e.g. telling the call to play foo.wav and getting an immediate return to listen for DTMF as the file plays rather than block till the file is over.
This document focuses on the outbound operation mode of mod_event_socket, but take note that this module also operates in inbound mode.
When you call outbound socket, FS automatically puts the call in PARK. You can validate that by monitoring the CHANNEL_PARK event.
When you use "sync" mode, many things will not works as you may expect. Particularly, you will not get DTMFs, etc. Please check "async" option.
Diagram
************************************* * | * * FreeSWITCH™ | mod_event_socket * * | 127.0.0.1:9999 * * * ************************************* || || \/ \/ ****************** ****************** * Server A * * Server B * * 127.0.0.1:8022 * * 127.0.0.1:8023 * ****************** ******************
Configuration
The data syntax to invoke the event socket outbound from FreeSWITCH in the dialplan is <ip>:<port> [<keywords>]
<action application="socket" data="address:port [async|full]"/>
Since revision git-8c794ac on 14/03/2012 you can also connect to IPv6 addresses. When using IPv6 addresses the port parameter is required: <action application="socket" data="::1:8021"/> connects to ::1 on port 8021. Since this revision hostnames resolving to IPv6 addresses can be used.
Keywords
async
The "async" keyword indicates that all commands will return instantly, allowing voice processing to proceed and making it possible to monitor the socket for events while the stack of commands are executing.
If the async keyword is absent then all calls on this channel will block until the command has finished.
full
The "full" keyword indicates that the other end will have the full command set for event_socket. This is the same command set on an event socket inbound connection so you can execute API commands, get global events, etc.
If the "full" keyword is absent the command set and events are limited to that particular call.
Variables
socket_resume
If this variable is set to true, the dialplan will resume execution with the next action after the call to the socket application. This can be used for example to allow you to do something intelligent in the dialplan if your IVR application dies in an unclean way. If there is a bridge active when the disconnect happens, it is killed. To do this from your application after the socket is already connected, issue the resume command.
Examples
Here are examples of how to use it in the dialplan.
<action application="socket" data="127.0.0.1:8084"/> <action application="socket" data="127.0.0.1:8084 async"/> <action application="socket" data="127.0.0.1:8084 full"/> <action application="socket" data="127.0.0.1:8084 async full"/>
Event Lock
If you are using async, you need to pay attention to potential race condition. The commands you send may not execute in sequential order. You may force the command to wait by setting event lock until the critical or long-running command finishes:
sendmsg call-command: set execute-app-name: foo=bar\n\n event-lock:true
You may obtain the same result (setting event-lock to true) in scripting using the setEventLock method of connection object:
$con->setEventLock("1");
Server Examples
sock.pl
There are several example Perl scripts that use the ESL library. Here's good one to review:
To run it you will need to compile ESL and perlmod. More information is available on the ESL page.
Using Netcat
Here is a small tutorial on how to use outbound event socket:
This was used to call this via the dialplan:
<action application="socket" data="127.0.0.1:8084 async full"/>
Now lets make netcat listen for connections from our call.
Linux :
nc -v -l 127.0.0.1 -p 8084
On CentOS 5.3 my syntax is this:
nc -v -l 127.0.0.1 8084
On Windows :
nc -v -L -n -p 8084
Connection from 127.0.0.1 port 8084 [tcp/*] accepted
Once the connection is accepted you type:
connect\n\n
Note: The command 'connect' is the first command at your ESL server side to send to FreeSWITCH side.
If without 'connect', FreeSWITCH side would response nothing and waiting.
If first command is not 'connect', FreeSWITCH also output nothing and waiting.
Once you do this you'll be presented the name value pairs of everything related to this call including all variables.
Example:
Now lets answer this call: (Note: sendmsg doesn't need uuid arg when in outbound mode)
sendmsg call-command: execute execute-app-name: answer\n\n
Which will reply:
Content-Type: command/reply Reply-Text: +OK
This call is now answered but its sitting there waiting on your every command.
Now lets play this call a sound file:
sendmsg call-command: execute execute-app-name: playback execute-app-arg: /tmp/swimp.raw\n\n
It is also possible to play tones:
sendmsg call-command: execute execute-app-name: playback execute-app-arg: tone_stream://%(2000,4000,440,480)\n\n
The reply should be:
Content-Type: command/reply Reply-Text: +OK
Now how do you stop the file playing? Here is how you would do that:
sendmsg call-command: execute execute-app-name: break\n\n
The reply should be:
Content-Type: command/reply Reply-Text: +OK
Now lets hang this call up:
sendmsg call-command: execute execute-app-name: hangup\n\n
The reply should be:
Content-Type: command/reply Reply-Text: +OK
Netcat will exit now.
You can also issue "myevents\n\n" or subscribe to other events in the normal way ie "events heartbeat\n\n"
In addition, you can execute API with:
api uuid_bridge <uuid> <uuid>
socket2me
We have someone working on a C library to use as an event socket library also. but in the meantime there is also a crude C example with no client library but just inline commands in scripts/c/socket2me this small C program demonstrates how you can use the interface to not only control the call but to also request a 2 way media stream and process the data. This application uses spandsp to implement a fax send/recv similar to asterisk's rxfax txfax only over the loopback interface.
Java ESL Client
The Java ESL Client provides an Outbound socket mode, with a simple example of how to implement land run it.
Javascript / Node.js server
- Node.js esl module (available using npm) offers both a client and a server implementation. The code is on github with documentation. Examples: Voicemail with CouchDB storage and CNAM injection (short example showing how to set a variable using an async web query).
Events
By default, the connected socket will not receive any FreeSWITCH events. You can issue the following event commands to let FreeSWITCH send events to the connected socket.
Receive only events from this channel
myevents
Receive all events from FreeSWITCH
event text all
Get lingering events on a hung up channel
linger
To make sure you do not miss any events when the channel is hungup, you need to send the "linger command". I found this comment from Anthony Minessale on the FreeSWITCH-users mailing list.
it's a race, sometimes the socket connection ends before the channel the linger socket command was added to tell FS to wait for the last channel event before ending the connection just send the command linger
From a post to the freeswitch-users mailing list dated 2016.03.28 12:02 EDT the following JavaScript code snippet reveals the basics of how to get raw conference events using $.verto.livearray() from the Verto library: You can build on this template in your own JS code.Verto Live Array
var la = new $.verto.liveArray(verto, data.pvtData.laChannel, data.pvtData.laName,
{subParams: {callID: dialog ? dialog.callID : null}, "onChange": function (obj, args) {
}});
la.onChange = function (obj, args) {
console.error("The change", args);
};
FAQ
Q: Ordering and async keyword
When using async keyword, is there any guarantee regarding ordering?
Once you send a command you always get the reply before anything else.
In the case of a bgapi command, your reply will simply contain a job id, and when the command has actually finished it will send an event. See Event_Socket
In some situations (for example, when using the bridge app) you want to ensure the application completely executes before the next command is parsed. Use the following to achieve this:
event-lock: true
When you send the command.
Example:
SendMsg <uuid> call-command: execute execute-app-name: playback execute-app-arg: /tmp/test.wav event-lock: true
You may obtain the same result (setting event-lock to true) in scripting using the setEventLock method of connection object:
$con->setEventLock("1");
Q: Should I use sync mode or async mode?
In sync mode many things may not work as you expect, for example no DTMFs are received. When you're playing a file in sync mode it blocks till the file is done playing. In async mode you are returned control instantly. You can stop the playback, transfer the call and various other things in async mode.
Q: Why are API commands returning 'command not found'?
Remember to use "async full" for full API.
Q: Can I bridge a call with an Outbound socket?
Yes you can, simple execute a 'Bridge'
sendmsg call-command: execute execute-app-name: bridge execute-app-arg: {ignore_early_media=true}sofia/gateway/myGW/177808 event-lock: true
The event-lock is key here, if you don't have it set, other events you might have sent can terminate the call, even if you've sent them before the bridge command. Remember that if you want to hangup the call when the bridge completes, either look for the event [CHANNEL_UNBRIDGE], or send a hangup event after the bridge.