Call Us Today! 877.742.2583




Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Expand
titleTable of Contents (click to expand)


Panel
borderColorlightgray
bgColor#f7f7f7
borderWidth1
borderStyledashed

Table of Contents
maxLevel3
indent1em
excludeAbout
stylenone
printablefalse


...

0. Status

Expand
titleHistorical note (click to expand)


Note

This note has been created by John Boteler on 2014.04.10, and haven't been changed since. Although there was no major update in the source in at least 7 years, so this may still be accurate.


Panel
borderStyledashed

Maturing, I'll try to provide backwards compatibility for 2 FreeSWITCH releases if I have to make an API change.

TODO

  • Ability to have multiple event handler pids per node, each with their own event subscriptions?
  • Figure out how to handle premature exits of spawned outbound processes
  • Allow log/event handler and handle call processes to be registered processes or pids
  • Check pids obtained via 'get_pid' to determine the node they're on in case they're not the node we requested a pid from (load balancing)
  • Investigate supporting starting a gen_server/gen_fsm using proc_lib:spawn/4 and enter_loop
  • Make datastructures more proplist friendly



...

This module, just as mod_event_socket, operates in two modes, inbound and outbound.

...

titleTable of Contents (click to expand)
Panel
borderColorlightgray
bgColor#f7f7f7
borderWidth1
borderStyledashed

Table of Contents
maxLevel3
indent1em
excludeAbout
stylenone
printablefalse

2. Modes of operation

See mod_event_socket for a more detailed description.

2.1 Inbound mode

The external Erlang application (running locally or remotely) controls the FreeSWITCH instance by sending messages to it (e.g., to check status, originate calls, register to receive events, execute applications).

2.1.2 Example Inbound Connection

Here's a brief example of using the Erlang shell (erl) to communicate with FreeSWITCH™ using mod_erlang_event.

We assume FreeSWITCH

  • is running locally
  • with cookie set to 'ClueCon', 
  • nodename set to 'freeswitch' and
  • shortname enabled.

The host name is 'example.com', so the short node name will be freeswitch@example.

Info
titleTODO: What about remote Erlang nodes?

Update this section with info on how to achieve the same with remote nodes. My initial assumption was connecting remote nodes will only work with nodes with long names, but this seems to be wrong.

  1. Read up on it
  2. Add an example

Some resources:

2.1.2.1 Start a local Erlang node
Code Block
$ erl -sname test -setcookie ClueCon
Erlang (BEAM) emulator version 5.6.4 [source] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.6.4  (abort with ^G)
(test@example)1>{foo, freeswitch@example} ! {api, status, ""}.
{api,status,[]}

...

The example above shows how to start a node with a short name (which is also reflected in the erl  shell's prompt), but you can always start one with a long name using the -name switch instead.

Note

Don't forget to configure mod_erlang_event accordingly! Erlang node with short names cannot communicate with ones set up using long names, and vice versa. See Configuration and Configuration Parameters sections above.

Info

The -setcookie value is the same as the one used for the cookie parameter in <conf_dir>/autoload_configs/erlang_event.conf.xml.

2.1.2.2 FreeSWITCH API commands 

We've just sent the status FreeSWITCH API command to FreeSWITCH™. Note how the connection was negotiated automagically. FreeSWITCH™ will send the reply back to us asynchronously (all Erlang messages are asynchronous), so we have to explicitly receive it:

Code Block
(test@example)2> receive X -> X after 1000 -> timeout end.
{ok,"Content-Type: text/html\n\nUP 0 years, 0 days, 0 hours, 0 minutes, 35 seconds, 692 milliseconds, 193 microseconds\n0 session(s) since startup\n0 session(s) 0/30\n"}

We tried to receive anything in the current process' mailbox with a 1000 millisecond timeout that will return the atom timeout as the result of the expression instead. However, there was indeed something waiting for us in the mailbox: the result of the API command we just made.

Now, lets send an invalid command, and listen for the reply:

Code Block
(test@example)3> {foo, freeswitch@example} ! {api, wtf, ""}, receive Y -> Y after 1000 -> timeout end.
{error,"wtf: Command not found!\n"}

So, as we can see, the command wtf isn't valid. Note that in both cases, a 2 element tuple is returned. Depending on the result of the command, the first element is either the atom ok  or error .

Tip
titleErlang variables are immutable

Note that we had to use a different variable name (i.e., Y ) this time to receive the results. If we used X  again, Erlang would search the process' mailbox for an event that matched what X was bound.

You could also do f(X). to forget the value of X in the shell. See the erl  manual, or type help(). in erl . (Note: The dots at the end of the commands are important.)

2.1.2.3 Issue FreeSWITCH API commands in the background

We'll now issue the status FreeSWITCH API command in the background (using bgapi) as a final example:

Code Block
(test@example)4> {foo, freeswitch@example} ! {bgapi, status, ""}, receive Z -> Z after 1000 -> timeout end.
{ok,"191d2b07-58ac-dd11-829b-000f1f68e553"}
Note

Note that all we got was the Job-UUID of the background command.

There are two ways to get the results:

Use receive block one more time to read the direct reply from the process' mailbox (just as after we fired the status command the first time):

Code Block
(test@example)5> receive A -> A after 1000 -> timeout end.
{bgok,"191d2b07-58ac-dd11-829b-000f1f68e553",
     "Content-Type: text/html\n\nUP 0 years, 0 days, 1 hour, 11 minutes, 8 seconds, 654 milliseconds, 138
        microseconds\n0 session(s) since startup\n0 session(s) 0/30\n"}


...

Tip
titleapi vs bgapi

 FreeSWITCH API command called with bgapi 

  • will be executed in its own thread,
  • is non-blocking,
  • will only return a Job-UUID for future reference.

Once the command is finished executing, FreeSWITCH will fire an BACKGROUND_JOB event with the result, and the Job-UUID can be used to look up the result if multiple BACKGROUND_JOB events have been received. (Of course, one needs to subscribe to BACKGROUND_JOB events first.)

See Event Socket Library's "bgapi" section to see how to set custom Job-UUID .

2.2 Outbound mode

A dialplan extension can open a connection to an external application (running locally or on a remote host), and then forward all system events related to incoming calls to this extension. That is, if scenario can be handled in an extension, then it can be processed by, and the workload offloaded to an external application.

When an incoming call traverses the dialplan, and matches an extension that calls an outbound socket, the call gets parked first. System events relating to the call are then sent from FreeSWITCH to specified Erlang node.

2.2.1 Strategies to handle calls with Erlang processes

2.2.1.1 Handle all incoming calls in one registered Erlang process
Code Block
languagexml
title<conf_dir>/dialplan/default/ext_123456_erlang.xml
linenumberstrue
<include>
  <extension name="to_erlang">
    <condition field="destination_number" expression="^123456$"> 
      <action application="erlang" data="myhandler mynode@myserver"/>
    </condition>
  </extension>
</include>

The above extension will send calls for destination number 123456 to a registered process called myhandler on the (possibly remote) Erlang node mynode@myserver.

The myhandler process will handle all incoming calls to this extension sequentially.

To test it,

2.2.1.2 Spawn a process dynamically for each incoming call

Every incoming call will be handled in a newly spawned Erlang process, and the instructions handling the calls will be the same for all of them.

2.2.1.3 Distribute calls among Erlang processes

For example, process calls with different area codes in their caller ID (see Caller-ANI in Channel Variables) in Erlang processes that handle the specific area code. 

This is the most general of the three strategies. It could be used to

  • recreate the two preceding sections (2.2.1.1 and 2.2.1.2)
  • utilize already running (and maybe registered) worker processes (i.e., juggle their PIDs around based on the task)
  • only start a specific worker when it is necessary, and then reuse its PID (if it isn't a one-off process that is)
  • ?

Installation

2. Installation

2.1. Vanilla FreeSWITCH installation

If FreeSWITCH has been installed from pre-built binaries (see Installation), all documented modules come pre-compiled with it, along with their sample configuration files in in the <conf_dir>/autoload_configs/  directory. 

(comment: this should also be noted on the Modules page, along with specifics (i.e., exactly which modules come with the vanilla installation).)

2.2. Compiling from source

You need Erlang (and its development headers) installed to compile this module. You must have Erlang development files installed before running the FreeSWITCH ./configure (or rerun ./configure after having Erlang installed). The FreeSWITCH™ configure script now checks for the Erlang requirements, and configures the Makefile appropriately.

...

Code Block
languagexml
title<conf_dir>/autoload_configs/modules.conf.xml
linenumberstrue
<configuration name="modules.conf" description="Modules">
  <modules>
    <!-- ... other modules ... -->
    <load module="mod_erlang_event"/>
    <!-- ... other modules ... -->
  </modules>
</configuration>

Step 2. Configure


mod_erlang_event's configuration file (<conf_dir>/autoload_configs/erlang_event.conf.xml) is very similar to the one for mod_event_socket, but some parameters are different. See Configuration Parameters below.


Expand
titleDefault configuration for vanilla installations (click to expand)


Code Block
languagexml
title<conf_dir>/autoload_configs/erlang_event.conf.xml
linenumberstrue
<configuration name="erlang_event.conf" description="Erlang Socket Client">
  <settings>
    <param name="listen-ip" value="0.0.0.0"/>
    <param name="listen-port" value="8031"/>
    <!-- Specify the first part of the node name
         (the host part after the @ will be autodetected)
         OR pass a complete nodename to avoid autodetection
         eg. freeswitch@example or freeswitch@example.com.
         If you pass a complete node name, the 'shortname' parameter has no effect. -->
    <param name="nodename" value="freeswitch"/>
    <!-- Specify this OR 'cookie-file' or $HOME/.erlang.cookie will be read -->
    <param name="cookie" value="ClueCon"/>
    <!-- Read a cookie from an arbitary erlang cookie file instead -->
    <!--<param name="cookie-file" value="/$${temp_dir}/erlang.cookie"/>-->
    <param name="shortname" value="true"/>
    <!-- in additon to cookie, optionally restrict by ACL -->
    <!--<param name="apply-inbound-acl" value="lan"/>-->
    <!-- alternative is "binary" -->
    <!--<param name="encoding" value="string"/>--> 
    <!-- provide compatability with previous OTP release (use with care) -->
    <!--<param name="compat-rel" value="12"/> -->
  </settings>
</configuration>


...

  • max-event-bulk
  • max-log-bulk
  • stop-on-bind-error

2. Modes of operation

See mod_event_socket for a more detailed description.

2.1 Inbound mode

The external Erlang application (running locally or remotely) controls the FreeSWITCH instance by sending messages to it (e.g., to check status, originate calls, register to receive events, execute applications).

2.1.2 Example Inbound Connection

Here's a brief example of using the Erlang shell (erl) to communicate with FreeSWITCH™ using mod_erlang_event.

We assume FreeSWITCH

  • is running locally
  • with cookie set to 'ClueCon', 
  • nodename set to 'freeswitch' and
  • shortname enabled.

The host name is 'example.com', so the short node name will be freeswitch@example.

Info
titleTODO: What about remote Erlang nodes?


Expand
titleClick to expand ...

Update this section with info on how to achieve the same with remote nodes. My initial assumption was connecting remote nodes will only work with nodes with long names, but this seems to be wrong.

  1. Read up on it
  2. Add an example

Some resources:


2.1.2.1 Start a local Erlang node
Code Block
$ erl -sname test -setcookie ClueCon
Erlang (BEAM) emulator version 5.6.4 [source] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.6.4  (abort with ^G)
(test@example)1>{foo, freeswitch@example} ! {api, status, ""}.
{api,status,[]}


Tip

The example above shows how to start a node with a short name (which is also reflected in the erl  shell's prompt), but you can always start one with a long name using the -name switch instead.

Note

Don't forget to configure mod_erlang_event accordingly! Erlang node with short names cannot communicate with ones set up using long names, and vice versa. See Configuration and Configuration Parameters sections above.



Info

The -setcookie value is the same as the one used for the cookie parameter in <conf_dir>/autoload_configs/erlang_event.conf.xml.

2.1.2.2 FreeSWITCH API commands 

We've just sent the status FreeSWITCH API command to FreeSWITCH™. Note how the connection was negotiated automagically. FreeSWITCH™ will send the reply back to us asynchronously (all Erlang messages are asynchronous), so we have to explicitly receive it:

Code Block
(test@example)2> receive X -> X after 1000 -> timeout end.
{ok,"Content-Type: text/html\n\nUP 0 years, 0 days, 0 hours, 0 minutes, 35 seconds, 692 milliseconds, 193 microseconds\n0 session(s) since startup\n0 session(s) 0/30\n"}

We tried to receive anything in the current process' mailbox with a 1000 millisecond timeout that will return the atom timeout as the result of the expression instead. However, there was indeed something waiting for us in the mailbox: the result of the API command we just made.

Now, lets send an invalid command, and listen for the reply:

Code Block
(test@example)3> {foo, freeswitch@example} ! {api, wtf, ""}, receive Y -> Y after 1000 -> timeout end.
{error,"wtf: Command not found!\n"}

So, as we can see, the command wtf isn't valid. Note that in both cases, a 2 element tuple is returned. Depending on the result of the command, the first element is either the atom ok  or error .

Tip
titleErlang variables are immutable

Note that we had to use a different variable name (i.e., Y ) this time to receive the results. If we used X  again, Erlang would search the process' mailbox for an event that matched what X was bound.

You could also do f(X). to forget the value of X in the shell. See the erl  manual, or type help(). in erl . (Note: The dots at the end of the commands are important.)

2.1.2.3 Issue FreeSWITCH API commands in the background

We'll now issue the status FreeSWITCH API command in the background (using bgapi) as a final example:

Code Block
(test@example)4> {foo, freeswitch@example} ! {bgapi, status, ""}, receive Z -> Z after 1000 -> timeout end.
{ok,"191d2b07-58ac-dd11-829b-000f1f68e553"}


Note

Note that all we got was the Job-UUID of the background command.

There are two ways to get the results:

  1. Use receive block one more time to read the direct reply from the process' mailbox (just as after we fired the status command the first time):

    Code Block
    (test@example)5> receive A -> A after 1000 -> timeout end.
    {bgok,"191d2b07-58ac-dd11-829b-000f1f68e553",
         "Content-Type: text/html\n\nUP 0 years, 0 days, 1 hour, 11 minutes, 8 seconds, 654 milliseconds, 138
            microseconds\n0 session(s) since startup\n0 session(s) 0/30\n"}

    Note that the command's final result is tagged with bgok /bgerror.

  2. In addition to a directed reply, a normal BACKGROUND_JOB event (see Event List) is also fired whenever a FreeSWITCH API command is executed in the background, which you could alternately choose to receive.
Tip
titleapi vs bgapi

 FreeSWITCH API command called with bgapi 

  • will be executed in its own thread,
  • is non-blocking,
  • will only return a Job-UUID for future reference.

Once the command is finished executing, FreeSWITCH will fire an BACKGROUND_JOB event with the result, and the Job-UUID can be used to look up the result if multiple BACKGROUND_JOB events have been received. (Of course, one needs to subscribe to BACKGROUND_JOB events first.)

See Event Socket Library's "bgapi" section to see how to set custom Job-UUID .

2.2 Outbound mode

A dialplan extension can open a connection to an external application (running locally or on a remote host), and then forward all system events related to incoming calls to this extension. That is, if scenario can be handled in an extension, then it can be processed by, and the workload offloaded to an external application.

When an incoming call traverses the dialplan, and matches an extension that calls an outbound socket, the call gets parked first. System events relating to the call are then sent from FreeSWITCH to specified Erlang node.

2.2.1 Strategies to handle calls with Erlang processes

2.2.1.1 Handle all incoming calls in one registered Erlang process
Code Block
languagexml
title<conf_dir>/dialplan/default/ext_123456_erlang.xml
linenumberstrue
<include>
  <extension name="to_erlang">
    <condition field="destination_number" expression="^123456$"> 
      <action application="erlang" data="myhandler mynode@myserver"/>
    </condition>
  </extension>
</include>

The above extension will send calls for destination number 123456 to a registered process called myhandler on the (possibly remote) Erlang node mynode@myserver.

The myhandler process will handle all incoming calls to this extension sequentially.

To test it,

2.2.1.2 Spawn a process dynamically for each incoming call

Every incoming call will be handled in a newly spawned Erlang process, and the instructions handling the calls will be the same for all of them.

2.2.1.3 Distribute calls among Erlang processes

For example, process calls with different area codes in their caller ID (see Caller-ANI in Channel Variables) in Erlang processes that handle the specific area code. 

This is the most general of the three strategies. It could be used to

  • recreate the two preceding sections (2.2.1.1 and 2.2.1.2)
  • utilize already running (and maybe registered) worker processes (i.e., juggle their PIDs around based on the task)
  • only start a specific worker when it is necessary, and then reuse its PID (if it isn't a one-off process that is)
  • ?

Example Outbound Connection

The gist is that an XML Dialplan extension will invoke the remote Erlang node to handle incoming traffic. Depending on the conditions set up with the extension, this traffic could be an incoming call to a range of destination numbers for example.

...