mod_event_socket is a TCP-based interface to control FreeSWITCH, and it operates in two modes, inbound and outbound. (These terms are relative to FreeSWITCH).
By default, connections are only allowed from
localhost, but this can be changed via configuration files (see Configuration section below for details).
First enable the
mod_event_socket module in
modules.conf.xml by removing the comment marks (
To get the location of
The default settings, in the
<conf_dir>/autoload_configs/event_socket.conf.xml configuration file, allow socket connections only from
localhost (see below),
<configuration name="event_socket.conf" description="Socket Client"> <settings> <param name="nat-map" value="false"/> <!-- ::1 is the IPv6 version of 127.0.0.0/8 in IPv4 --> <param name="listen-ip" value="::1"/> <param name="listen-port" value="8021"/> <param name="password" value="ClueCon"/> <!--<param name="apply-inbound-acl" value="loopback.auto"/>--> <!--<param name="stop-on-bind-error" value="true"/>--> </settings> </configuration>
but this behaviour can be changed using the
listen-ip parameter. For example, to allow connections from any host on the network, use 0.0.0.0 instead of the default:
<configuration name="event_socket.conf" description="Socket Client"> <settings> <!-- Allow socket connections from any host --> <!-- :: is the IPv6 version of 0.0.0.0 in IPv4 --> <param name="listen-ip" value="::"/> <param name="listen-port" value="8021"/> <param name="password" value="ClueCon"/> </settings> </configuration>
You can listen on IPv6 addresses (with the
For example, the above example using
Using Access Control List (ACL)s is recommended for enhanced security if you allow ESL connections from another machine. One can either enable named Access Control List (ACL)s (defined in
<conf_dir>/autoload_configs/acl.conf.xml) or allow IP ranges directly in
<param name="apply-inbound-acl" value="<acl_list|cidr>"/>
<param name="apply-inbound-acl" value="10.20.0.0/16"/> <param name="apply-inbound-acl" value="loopback.auto"/>
As of 1.6 you must supply an ACL. In order to allow all IPs you can use
Inbound mode means you run your applications (in whatever languages) as clients, and connect to the FreeSWITCH server to invoke commands and control FreeSWITCH.
******************************************** * | * * FreeSWITCH™ | mod_event_socket * * | 127.0.0.1:8021 * * | * ******************************************** /\ /\ / \ ****************** ****************** * Client A * * Client B * * 127.0.0.1:9988 * * 127.0.0.1:9999 * ****************** ******************
In inbound mode, your application (Client A: Python, Client B: Perl, etc.) connects to the FreeSWITCH™ server on the given port and sends commands, as shown in the above diagram. The rest of this document is biased toward this inbound mode, though there is a lot of overlap with outbound mode. Using inbound socket connections you can check status, make outbound calls, etc.
If you would like to handle incoming calls using inbound mode, you should add the
uuid_park command (see mod_commands) to your dialplan. Otherwise the dialplan might complete executing before your client can send commands to the event socket.
Outbound mode means you make a daemon (with whatever language), and then have FreeSWITCH connect to it. You add an extension to the dialplan, and put <action application="socket" data="ip:port sync full"/> and create a script that runs on that ip:port and answer, playback and everything else you need on the script. Since revision git-8c794ac on 14/03/2012 you can 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.
In outbound mode, also known as the "socket application" (or socket client), FreeSWITCH™ makes outbound connections to another process (similar to Asterisk's FAGI model). Using outbound connections you can have FreeSWITCH™ call your own application(s) when particular events occur. See Event Socket Outbound for more details regarding things specific to outbound mode.
The following section aims at documenting all commands that can be sent. This section is a work in progress.
Send a FreeSWITCH API command, blocking mode. That is, the FreeSWITCH instance won't accept any new commands until the
api command finished execution.
api <command> <arg>
api originate email@example.com 1000 # connect sip:firstname.lastname@example.org to extension 1000 api msleep 5000
Send a FreeSWITCH API command, non-blocking mode. This will let you execute a job in the background, and the result will be sent as an event with an indicated UUID to match the reply to the command.
bgapi <command> <arg>
The same API commands available as with the
api command, however the server returns immediately and is available for processing more commands.
Example return value:
Content-Type: command/reply Reply-Text: +OK Job-UUID: c7709e9c-1517-11dc-842a-d3a3942d3d63
When the command is done executing, FreeSWITCH fires an event with the result and you can compare that to the Job-UUID to see what the result was. In order to receive this event, you will need to subscribe to BACKGROUND_JOB events.
If you want to set your own custom Job-UUID over plain socket:
bgapi status Job-UUID: d8c7f660-37a6-4e73-9170-1a731c442148
Content-Type: command/reply Reply-Text: +OK Job-UUID: d8c7f660-37a6-4e73-9170-1a731c442148 Job-UUID: d8c7f660-37a6-4e73-9170-1a731c442148
Tells FreeSWITCH not to close the socket connection when a channel hangs up. Instead, it keeps the socket connection open until the last event related to the channel has been received by the socket client.
Disable socket lingering. See linger above.
Enable or disable events by class or all (plain text, XML, or JSON output format)
event plain <list of events to log or all> event xml <list of events to log or all> event json <list of events to log or all>
event command are used to subscribe on events from FreeSWITCH. You may specify any number events on the same line that should be separated with spaces.
See Event List page for a comprehensive list of events.
event plain ALL event plain CHANNEL_CREATE CHANNEL_DESTROY CUSTOM conference::maintenance sofia::register sofia::expire event xml ALL event json CHANNEL_ANSWER
Subsequent calls to
event won't override the previous event sets. Supposing, you've first registered for
event plain DTMF
but you want to register for
CHANNEL_ANSWER also, then it is enough to do
event plain CHANNEL_ANSWER
and you will continue to receive
DTMF along with
Events consist of
a header section, and
an optional event body.
Headers are key/value pairs separated by a colon, and headers are separated by 1 line feed.
Some header values may contain multiple line breaks, but because FreeSWITCH URL-encodes all of them, these multi-line header values will still appear as 1 line.
Events may have a body, carrying additional content generated with the event. It is usually not in the key/value form of headers, and may contain its own native formatting.
The presence of
Content-Length in the header section is an indicator that there is an event body. The value of the
Content-Length header is the size of the body in bytes.
Speech-Type: detected-speech Event-Name: DETECTED_SPEECH Core-UUID: aac0f73e-b822-e54c-a02a-06a839ca3e5a FreeSWITCH-Hostname: AMONROY FreeSWITCH-IPv4: 192.168.1.220 FreeSWITCH-IPv6: ::1 Event-Date-Local: 2009-01-26 16:07:24 Event-Date-GMT: Mon, 26 Jan 2009 22:07:24 GMT Event-Date-Timestamp: 1233007644906250 Event-Calling-File: switch_ivr_async.c Event-Calling-Function: speech_thread Event-Calling-Line-Number: 1758 Content-Length: 435 <result grammar="<email@example.com>#nombres"> <interpretation grammar="<firstname.lastname@example.org>#nombres" confidence="0.494643"> <instance confidence="0.494643"> arturo monroy </instance> <input mode="speech" confidence="0.494643"> <input confidence="0.313102"> arturo </input> <input confidence="0.618854"> monroy </input> </input> </interpretation> </result>
Content-Length: <size>\n | Headers in the TCP/IP Content-Type: text/event-plain\n | packet's payload. \n event-hdr1: a\n <-- size starts here | FreeSWITCH | Event headers and body event-hdr2: b\n | event headers | in the the body of the ... | | TCP/IP packet's body. event-hdrN: x\n *---------------- | \n <-- size ends here | body line 1 (if no body) *---------------- | ... | FreeSWITCH | body line N <-- or here if there's | event body | a body | | -------------------------------------------------------------------- \n is a line feed in the form of CRLF.
Content-Length: 625 Content-Type: text/event-plain Job-UUID: 7f4db78a-17d7-11dd-b7a0-db4edd065621 Job-Command: originate Job-Command-Arg: sofia/default/1005%20'%26park' Event-Name: BACKGROUND_JOB Core-UUID: 42bdf272-16e6-11dd-b7a0-db4edd065621 FreeSWITCH-Hostname: ser FreeSWITCH-IPv4: 192.168.1.104 FreeSWITCH-IPv6: 127.0.0.1 Event-Date-Local: 2008-05-02%2007%3A37%3A03 Event-Date-GMT: Thu,%2001%20May%202008%2023%3A37%3A03%20GMT Event-Date-timestamp: 1209685023894968 Event-Calling-File: mod_event_socket.c Event-Calling-Function: api_exec Event-Calling-Line-Number: 609 Content-Length: 41 +OK 7f4de4bc-17d7-11dd-b7a0-db4edd065621
event plainparsing instructions
Get the event data
Read exactly as many bytes from the socket as specified in the
Note that since this is TCP, this may take more than one read so if you are supposed to read 200 bytes and the next read only returns 50, you must continue to read another 150, and so on until you have read 200 bytes or the socket has an error.
Once you have read all the bytes in the
Parse event data
Content-Length header among the event headers? (Implying that there is an event body.)
No → All done.
Read that many bytes
The 'myevents' subscription allows your inbound socket connection to behave like an outbound socket connect. It will "lock on" to the events for a particular uuid and will ignore all other events, closing the socket when the channel goes away or closing the channel when the socket disconnects and all applications have finished executing.
Once the socket connection has locked on to the events for this particular uuid it will NEVER see any events that are not related to the channel, even if subsequent event commands are sent. If you need to monitor a specific channel/uuid and you need watch for other events as well then it is best to use a filter.
You can also set the event format (plain, xml or json):
myevents plain <uuid> myevents json <uuid> myevents xml <uuid>
The default format is plain.
The divert_events switch is available to allow events that an embedded script would expect to get in the inputcallback to be diverted to the event socket.
divert_events on divert_events off
An inputcallback can be registered in an embedded script using setInputCallback(). Setting divert_events to "on" can be used for chat messages like gtalk channel, ASR events and others.
Specify event types to listen for. Note, this is not a filter out but rather a "filter in," that is, when a filter is applied only the filtered values are received. Multiple filters on a socket connection are allowed.
filter <EventHeader> <ValueToFilter>
The following example will subscribe to all events and then create two filters, one to listen for HEARTBEATS and one to listen for CHANNEL_EXECUTE events.
events plain all Content-Type: command/reply Reply-Text: +OK event listener enabled plain filter Event-Name CHANNEL_EXECUTE Content-Type: command/reply Reply-Text: +OK filter added. [filter]=[Event-Name CHANNEL_EXECUTE] filter Event-Name HEARTBEAT Content-Type: command/reply Reply-Text: +OK filter added. [Event-Name]=[HEARTBEAT]
Now only HEARTBEAT and CHANNEL_EXECUTE events will be received. You can filter on any of the event headers. To filter for a specific channel you will need to use the uuid:
filter Unique-ID d29a070f-40ff-43d8-8b9d-d369b2389dfe
This method is an alternative to the myevents event type. If you need only the events for a specific channel then use myevents, otherwise use a combination of filters to narrow down the events you wish to receive on the socket.
To filter multiple unique IDs, you can just add another filter for events for each UUID. This can be useful for example if you want to receive start/stop-talking events for multiple users on a particular conference.
filter plain all filter plain CUSTOM conference::maintenance filter Unique-ID $participantB filter Unique-ID $participantA filter Unique-ID $participantC
This will give you events for Participant A,B and C on any conference. To receive events for all users on a conference you can use something like:
filter Conference-Unique-ID $ConfUUID
You can filter on any of the parameters you get in a freeSWITCH event:
filter plain all filter call-direction Inbound filter Event-Calling-File mod_conference.c filter Conference-Unique-ID $ConfUUID
You can use them individually or compound them depending on whatever end result you desire for the type of events you want to receive
Specify the events which you want to revoke the filter. filter delete can be used when some filters are applied wrongly or when there is no use of the filter.
filter delete <EventHeader> <ValueToFilter>
filter delete Event-Name HEARTBEAT
Now, you will no longer receive HEARTBEAT events. You can delete any filter that is applied by this way.
filter delete Unique-ID d29a070f-40ff-43d8-8b9d-d369b2389dfe
This is to delete the filter which is applied for the given unique-id. After this, you won't receive any events for this unique-id.
filter delete Unique-ID
This deletes all the filters which are applied based on the unique-id.
Send an event into the event system (multi line input for headers).
sendevent <event-name> <headers> <body>
Some phones require authentication for NOTIFY requests. FreeSWITCH can respond to a digest challenge if reverse authentication credentials are supplied for the user. See XML User Directory.
I've not found any documentation of any additional event headers, hopefully someone else with add that information. The events themselves can be found here: Event List
Something that was undocumented but is supported; SIP INFO messages can be sent to every IP you need.
For MWI you make the FreeSWITCH event SWITCH_EVENT_MESSAGE_WAITING with headers:
MWI-Messages-Waiting (yes/no) MWI-Message-Account <any sip url you want> MWI-Voice-Message x/y (a/b) read/unread (urgent read/urgent unread)
sendevent message_waiting MWI-Messages-Waiting: no MWI-Message-Account: sip:email@example.com
sendevent message_waiting MWI-Messages-Waiting: yes MWI-Message-Account: sip:firstname.lastname@example.org MWI-Voice-Message: 0/1 (0/0)
sendevent NOTIFY profile: internal event-string: check-sync;reboot=false user: 1000 host: 192.168.10.4 content-type: application/simple-message-summary
sendeventexamples with a message body
The length of the body is specified by the
sendevent NOTIFY profile: internal content-type: application/simple-message-summary event-string: check-sync user: 1005 host: 192.168.10.4 content-length: 2 OK
sendevent SEND_MESSAGE profile: internal content-length: 2 content-type: text/plain user: 1005 host: 22.214.171.124 OK
Results in a packet like this:
MESSAGE sip:email@example.com SIP/2.0 Via: SIP/2.0/UDP 126.96.36.199;rport;branch=z9hG4bK0apcKrtycp64p Max-Forwards: 70 From: <sip:firstname.lastname@example.org>;tag=4c0Dp49yUNmXH To: <sip:email@example.com> Call-ID: 29916da5-0062-122c-15aa-001a923f6a0f CSeq: 104766296 MESSAGE Contact: <sip:firstname.lastname@example.org:5060> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-9578:9586 Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE, REGISTER, INFO, PUBLISH Supported: 100rel, timer, precondition, path, replaces Content-Type: text/plain Content-Length: 2 OK
To send through a proxy, use the event headers: contact-uri, to-uri, and from-uri
In this example, the SIP proxy is 192.168.207.156:5060 and the UA can be reached at email@example.com:11710
sendevent NOTIFY profile: internal content-type: application/simple-message-summary event-string: check-sync user: 1002 host: 3.local to-uri: firstname.lastname@example.org from-uri: email@example.com contact-uri: sip:firstname.lastname@example.org:11710;fs_path=sip:192.168.207.156:5060
Another example with a notify:
sendevent NOTIFY profile: internal content-type: application/simple-message-summary event-string: check-sync user: 1005 host: 188.8.131.52 content-length: 2 OK
Results in a packet like this:
NOTIFY sip:email@example.com SIP/2.0 Via: SIP/2.0/UDP 184.108.40.206;rport;branch=z9hG4bKpH2DtBDcDtg0N Max-Forwards: 70 From: <sip:firstname.lastname@example.org>;tag=Dy3c6Q1y15v5S To: <sip:email@example.com> Call-ID: 129d1446-0063-122c-15aa-001a923f6a0f CSeq: 104766492 NOTIFY Contact: <sip:firstname.lastname@example.org:5060> User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-9578:9586 Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE, REGISTER, INFO, PUBLISH Supported: 100rel, timer, precondition, path, replaces Event: check-sync Allow-Events: talk, presence, dialog, call-info, sla, include-session-description, presence.winfo, message-summary Subscription-State: terminated;timeout Content-Type: application/simple-message-summary Content-Length: 2 OK
sendevent NOTIFY profile: internal event-string: resync;profile=http://10.20.30.40/profile.xml user: 1000 host: 10.20.30.40 content-type: application/simple-message-summary to-uri: sip:email@example.com from-uri: sip:firstname.lastname@example.org
Results in a packet like this:
NOTIFY sip:email@example.com:5060 SIP/2.0 Via: SIP/2.0/UDP 10.20.30.40:5060;rport;branch=z9hG4bKyK4gHN28Hpyaa Max-Forwards: 70 From: <sip:firstname.lastname@example.org>;tag=FDXet6B470F6B To: <sip:email@example.com> Call-ID: 19ff59fb-2cfc-1230-66b7-00199988ac0c CSeq: 29295547 NOTIFY Contact: <sip:firstname.lastname@example.org:5060> User-Agent: FreeSWITCH-mod_sofia/1.0.head-git-12f2bdf 2011-11-28 16-45-59 -0600 Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, UPDATE, INFO, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE Supported: timer, precondition, path, replaces Event: resync;profile=http://10.20.30.40/profile.xml Allow-Events: talk, hold, presence, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer Subscription-State: terminated;reason=timeout Content-Type: application/simple-message-summary Content-Length: 0
event-string: resync' in the body then the unit will use its stored profile URI
sendevent SWITCH_EVENT_PHONE_FEATURE profile: internal user: ex1004 host: 3.local device: ex1004 Feature-Event: DoNotDisturbEvent doNotDisturbOn: on
The message must be of type "text/plain".
sendmsg <UUID> <headers> <body>
sendmsg is used to control the behavior of FreeSWITCH.
UUID is mandatory, and it refers to a specific call (i.e., a channel or call leg or session; see Call Legs and Creating a New Endpoint: Lifecycle of a Session).
What does this line mean? "originate a call directly to park by making an ext the ext part of the originate command &park()"
Since messaging format is similar to RFC 2822, if you are using any libraries that follow the line wrapping recommendation of RFC 2822 then make sure that you disable line wrapping as FreeSWITCH will ignore wrapped lines. See "FreeSWITCH EventSocket header length" post for more.
sendmsg <uuid> call-command: execute execute-app-name: playback execute-app-arg: /tmp/test.wav
execute is used to invoke dialplan applications, mirroring the function of the
execute method (in the Event Socket Library).
If you are using
You may force the command to wait by setting
The format should be:
sendmsg <uuid> call-command: execute execute-app-name: <one of the applications> execute-app-arg: <application data> loops: <number of times to invoke the command, default: 1>
This alternate format can be used for app args that are truncated by the module's 2048 octet limit:
sendmsg <uuid> call-command: execute execute-app-name: <one of the applications> loops: <number of times to invoke the command, default: 1> content-type: text/plain content-length: <content length> <application data>
When an application is executed via
CHANNEL_EXECUTE_COMPLETE events are going to be generated. If you would like to correlate these two events then add an
Event-UUID header with your custom UUID. In the corresponding events, the UUID will be in the
Application-UUID header. If you do not specify an
Event-UUID, Freeswitch will automatically generate a UUID for the
Hang up the call.
sendmsg <uuid> call-command: hangup hangup-cause: <one of the causes listed below>
unicast is used to hook up
mod_spandsp for faxing over a socket.
sendmsg <uuid> call-command: unicast local-ip: <default is 127.0.0.1> local-port: <default is 8025> remote-ip: <default is 127.0.0.1> remote-port: <default is 8026> transport: <either "tcp" or "udp", without the quotes> and optionally flags: native - don't transcode audio to/from L16
sendmsg <uuid> call-command: nomedia nomedia-uuid: <noinfo>
Document this command.
From Stéphane Alnet's comment:
Close the socket connection.
Enable log output. Levels same as the console.conf values
Disable log output previously enabled by the log command
nixevent <event types | ALL | CUSTOM custom event sub-class>
Suppress the specified type of event. Useful when you want to allow 'event all' followed by 'nixevent <some_event>' to see all but 1 type of event.
Disable all events that were previously enabled with event.