FreeSwitch SIP and Media Server

  • Architecture and Design of Freeswitch
    • Core
    • Threaded Model 
  • State Machine in Freeswitch Core
  • Channel Variables
  • Dialplan
    • Speak Time and Date on Call
    • Call Routing based on destination number and forwarding to voice mail on no answer
    • Call routing based on day and time
    • Match incoming network IP address with pre configured IP
    • Store captured values in standard variables 
    • Playback
      • Media recording and playback in audio (wav)
      • Routing by listening on the audio stream for a touch-tone followed by a single digit
    • some authentication and security related dialplan applications
      • Checking user is authenticated before routing call , else respond 407
      • Checking if there is TLS and SRTP security , else set not_secure
      • Catching invalid destinations or extensions
    • Call screening and blocking dialplan applications
    • Block caller
    • Block certain codes
    • DID – Direct Inward Dialling via dialplan Public.xml
    • IVR ( Interactive Voice Respondent ) using Menu
    • Find me Follow Me
    • Multiple Targets
    • Handle Failures and Early Media
  • Directory
  • Installation
  • Debugging and Call
  • Security

FreeSWITCH is free and open source communications software licensed under Mozilla Public License. It if often the core of voice core to provider call routing and media control . Its core library, libfreeswitch, is capable of being embedded into other projects, as well as being used as a stand-alone application.

FreeSWITCH can route and interconnect communication protocols using audio, video, text, or any other form of media. First released in January 2006, FreeSWITCH has grown to become the world’s premier open-source soft-switch platform. This versatile platform is used to power voice, video, and chat communications on devices ranging from single calls on a Raspberry Pi to large server clusters handling millions of calls. FreeSWITCH powers several commercial products from start-ups to Carriers.

It can perform the functions of  ( but not limited to )

  • PBX Server (Transcoding B2BUA)
  • IVR & Announcement Server
  • Conference host
  • Voicemail
  • Session Border Controller
  • Text to Speech (TTS)
  • VOIP endpoint
  • Class 5 softswitch

Freeswitch has a modular architecture that is both scalable and customisable. The most important modules are- Endpoint, dialplan and Application.

Application is the instruction added for a particular dial plan with an extension object. Data Arguments are also passed to an application. Examples like Set: configure extension parameter, Bridge: bridge a new channel to the existing one, Answer: answer the call for a channel, Hangup: hangup a current channel, Run an IVR menu etc

Protocols set up call legs/ channels, negotiate codecs and stream media. The endpoint module helps to bridge channels between different protocol supported endpoints like WebRTC , H323, SIP , Jingle etc. SIP being the most popular protocol for the VoIP session is implemented by mod_sofia module while RTP is inbuild into FreeSWITCH core. SRTP ( media protocol for webrtc ) is provided by mod_verto.

Architecture and Design of Freeswitch

Freeswitch can form the basis of complicated and sophisticated communications backend framework with thousand CPS(Call per second ). It can connect to VOIP ( voice over IP ) as well as PSTN ( Public Switched Telephone network ) and PRI ( Primary Rate Interfaces – used in enterprises communication).

Core

Data strutters are opaque and operations can be invoke by APIs with routines getting maximum reuse .

Threaded Model 

Enables parallel operation as every connection has its own thread. Event handlers push incoming events into threads .  Sub system run in background threads .

Freeswitch

State Machine in Freeswitch Core

Protocol module listens for call message and parses the call details inot an internal data structure for session management by the core’s state machine.

State Change CS_NEW -> CS_INIT
State NEW
Running State Change CS_INIT (Cur 1 Tot 274)
State INIT
SOFIA INIT
Standard INIT

The state is then changes to ROUTING. At this state the Dialplan’s is lookedup to see the operations that were defiendfor this call based on regex matching.

State Change CS_INIT -> CS_ROUTING
State INIT going to sleep
Running State Change CS_ROUTING (Cur 1 Tot 274)
Change DOWN -> RINGING
State ROUTING

Once the call flow logic is found and escuted form the dialplan the state is changes to EXECUTE.

State Change CS_ROUTING -> CS_EXECUTE
State ROUTING going to sleep
Running State Change CS_EXECUTE (Cur 1 Tot 274)
State EXECUTE
SOFIA EXECUTE

State change to Active and Exchnage_media

entering state [completed][200]
Channel [sofia/internal/from_number@sometelco.com:5060] has been answered
Callstate Change EARLY -> ACTIVE
Originate Resulted in Success: [sofia/external/to_number@ip_addr]
State Change CS_CONSUME_MEDIA -> CS_EXCHANGE_MEDIA
Running State Change CS_EXCHANGE_MEDIA (Cur 2 Tot 275)
State EXCHANGE_MEDIA
SOFIA EXCHANGE_MEDIA

Channel Variables

Channel variables are used to manipulate dialplan execution, to control call progress, and to provide options to applications. They play a pervasive role, as FreeSWITCH™ frequently consults channel variables as a way to customize processing prior to a channel’s creation, during call progress, and after the channel hangs up.

  • $${variable} is expanded once when FreeSWITCH™ first parses the configuration on startup or after invoking reloadxml. It is suitable for variables that do not change, such as the domain of a single-tenant FreeSWITCH™ server.

<param name=”domain” value=”$${domain}”/>

  • ${variable} is expanded during each pass through the dialplan, so it is used for variables that are expected to change, such as the ${destination_number} or ${sip_to_user} fields.

Setting a channel variable :

<application="set" data="rtp_secure_media=true"/>

Reading a channel variable:

<route service="E2U+SIP" regex="sip:(.*)" replace="sofia/${use_profile}/$1;transport=udp"/>

Exporting channel variables in bridge operations

  • from one to another call leg using export_var
  • exporting to a list using export application
<action application="export" data="dialed_extension=$1"/>

Custom channel variables can be defined anytime too such as

<action application="set" data="conference_auto_outcall_caller_id_name=Mad Boss"/>

Also channel variables can be limited to scope on an extension . An example of passing some channel variable to log application .

<action application="log" data="INFO Inbound call CallUUID ${call_uuid} SIPCallID ${sip_call_id}- from ${caller_id_number} to ${destination_number}"/>

If the conditions are not met, optional anti-actions are executed.

<name="is_secure" continue="true">
<-- Only Truly consider it secure if its TLS and SRTP -->
<condition field="${sip_via_protocol}" expression="tls"/>
<condition field="${rtp_secure_media_confirmed}" expression="^true$">
    <action application="sleep" data="2000"/>
    <action application="playback" data="misc/call_secured.wav"/>
    <anti-action application="eval" data="not_secure"/>
<condition>
<extension>

Inline actions are executed during the hunting phase of dialplan

Dialplan

A Dialplan is designed to lookup list of instructions from the central XML registry within FreeSWITCH. In general dialplans are used to route a dialed call to an endpoint based on the extension and its  condition. When a matching extension is found, it executes its actions . The combination of the above can create detailed control and call flow plans. FS uses Perl-compatible regular expressions (PCRE) for pattern matching. Few formats

  • sofia/profile2/8765@1.2.3.4 , will dial out 8765 at host 1.2.3.4 using profile2
  • sofia/gateway/gateway11.com/5432 , will dial through a Gateway (SIP Provider) to user 5432
  • sofia/profile2/8765@1.2.3.4;transport=tcp , dialing with specific transport like TCP, UDP, TLS, or SCTP.
  • {absolute_codec_string=PCMU}sofia/external/sip:9106@${local_ip_v4}:5080 , to specify the codecs

Speak Time and Date on Call

when dialed number matches regular expression 9172 , then call is answered , put to sleep for 1 seconds and using say application current date and time is said , then application hangs up .

<include>
<extension name="speak_date_time" >
<condition field="destination_number" expression="^9172$">
    <action application="answer"/>
    <action application="sleep" data="1000"/>
    <action application="say" data="en CURRENT_DATE_TIME pronounced ${strepoch()}"/>
    <action application="hangup"/>
</condition>
</extension>
</include>

There may be 3 kinds of contexts  :

  1. default  : used for all internal users  such as PBX . Local_Extension can route the call between internal users .
  2. public  : used by external world users such as DID
  3. features : other custom in call features using bind_meta_app application etc

Call Routing based on destination number and forwarding to voice mail on no answer

Configure the sip driver to use the custom context while processing the call such as ,

<profile name="telco_custom_sipprofile">
    <param name="context" value="custom_sipcontext"/>
...
</profile>

When call arrives for destination 501 , the condition matches and this blocks action are executed such as in example below .
Exetnsion 501 rings , when not answered it sleeps or 1 seconds , then gets forwarded to voice mail .

If the call to 501 was answered ie handed off then further actions would not be executed

<context name="custom_sipcontext">
<extension name="501">
<condition field="destination_number" expression="^501$">
    <action application="bridge" data="user/501"/>
    <action application="answer"/>
    <action application="sleep" data="1000"/>
    <action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
</condition>
</extension>
</context>

Call routing based on day and time

<extension name="Time of day, day of week setup" continue="true">
<condition wday="2-6" hour="8-16 break="never">
<action application="set" data="office_status=open" inline="true"/>
<anti-action application="set" data="office_status=closed" inline="true"/>
</condition>
<condition wday="2-6" time-of-day="1:30-2:30" break="never">
<action application="set" data="office_status=lunch" inline="true"/>
</condition>
</extension>

inline= true states that channel variables will be used for later reference while break=never and continue=true tell the program to keep looking for more condition matches incase of failed or successful match respectively

Match incoming network IP address with pre configured IP

Store incoming number to $1 variable and bridge the call with custom profile . Read more about sip profiles in sections below .

<extension name="ipmatch">
<condition field="network_addr" expression="^198\.168\.1\.0$"/>
<condition field="destination_number" expression="^(\d+)$">
    <action application="bridge" data="sofia/customprofile/$1@198.168.2.0"/>
</condition>
</extension>

Note : $1 varibles value is not available outside of the condition block

Store captured values in standard variables 

<action application=”set” data=”domain_name=$${domain}”/>

Following example store stores destination_number ( freeswitch variable ) into ‘dialed_number’

<extension name="ipmatch_variable">
<condition field="destination_number" expression="^(\d+)$">
    <action application="set" data="dialed_number=$1"/>
</condition>
<condition field="network_addr" expression="^192\.168\.1\.1$">
    <action application="bridge" data="sofia/customprofile/${dialed_number}@192.168.2.2"/>
</condition>
</extension>

Playback

Media recording and playback in audio (wav)

<extension name="recording">
<condition field="destination_number" expression="^(4444)$">
    <action application="answer"/>
    <action application="set" data="playback_terminators=#"/>
    <action application="record" data="/tmp/audiofile.wav 20 200"/>
</condition>
</extension>

<extension name="playback">
<condition field="destination_number" expression="^(5555)$">
    <action application="answer"/>
    <action application="set" data="playback_terminators=#"/>
    <action application="playback" data="/tmp/audiofile.wav"/>
</condition>
</extension>

Routing by listening on the audio stream for a touch-tone * followed by a single digit.

If the called user dials *1, then the execute_extension::dx XML features command is executed.

<extension name="Local_Extension">
<condition field="destination_number" expression="^(10[01][0-9])$">
    <action application="export" data="dialed_extension=$1"/>
    <!-- bind_meta_app can have these args <key> [a|b|ab] [a|b|o|s] <app> -->
    <action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
    <action application="bind_meta_app" data="2 b s record_session::${recordings_dir}/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
    <action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
    <action application="bind_meta_app" data="4 b s execute_extension::att_xfer XML features"/>
..
</condition>
</extension>

The dx extension in features accepts the digits and proceeds as defined with the call

<extension name="dx">
<condition field="destination_number" expression="^dx$">
    <action application="answer"/>
    <action application="read" data="11 11 'tone_stream://%(10000,0,350,440)' digits 5000 #"/>
    <action application="execute_extension" data="is_transfer XML features"/>
</condition>
</extension>

Some authentication and security related dialplan applications

Checking user is authenticated before routing call , else respond 407

<extension name="9191">
<condition field="destination_number" expression="^9191$"/>
<condition field="${sip_authorized}" expression="true">
    <anti-action application="respond" data="407"/>
</condition>
<condition>
    <action application="playback" data="misc/connected_securly.wav"/>
</condition>
</extension>

Checking if there is TLS and SRTP security , else set not_secure

<extension name="is_secure">
<condition field="${sip_via_protocol}" expression="tls"/>
<condition field="${rtp_secure_media_confirmed}" expression="^true$">
<action application="sleep" data="1000"/>
<action application="playback" data="misc/connected_securly.wav"/>
<anti-action application="eval" data="not_secure"/>
</condition>
</extension>

Catching invalid destinations or extensions

Catch numbers which didnt match any other case. Add this extension to bottom. It plays an invalid tune

<extension name="catchall">
<condition field="destination_number" expression=".*" continue="true">
    <action application="playback" data="misc/invalid_extension.wav"/>
</condition>
</extension>

Call screening and blocking dialplan applications

Call Screening by name announcement

User caller’s name store in wave file

<action application="set" data="call_screen_filename=/tmp/${caller_id_number}-name.wav"/>

Connect to the called party. On answer announce the name. since playback_terminators is set to digits , pressing any one of them will terminate the call

<action application="set" data="hangup_after_bridge=true" />
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="phrase" data="voicemail_record_name"/>
<action application="playback" data="tone_stream://%(500, 0, 640)"/>
<action application="set" data="playback_terminators=#*0123456789"/>
<action application="record" data="${call_screen_filename} 7 200 2"/>

If called party presses 1 connect the call, or hang up.

<action application="set" data="group_confirm_key=1"/>
<action application="set" data="fail_on_single_reject=true"/>
<action application="set" data="group_confirm_file=phrase:screen_confirm:${call_screen_filename}"/>
<action application="set" data="continue_on_fail=true"/>
<action application="bridge" data="user/$1"/>

If the called party hangs up, the caller is connected with voicemail.

<action application="voicemail" data="default ${domain} $1"/>

finally hangup

<action application="hangup"/>

Block caller

Dial *77 followed by the number to be blocked

<extension name="block_caller_id">
<condition field="destination_number" expression="^\*77(\d+)$">
<action application="privacy" data="full"/>
<action application="set" data="sip_h_Privacy=id"/>
<action application="set" data="privacy=yes"/>
<action application="transfer" data="$1 XML default"/>
</condition>
</extension>

Block certain codes

block certain NPAs that you do not want to terminate based on caller id area codes and respond with SIP:503 to your origination so that they can route advance if they have other carrier to terminate to.

<extension name="blocked_cid_npa">
<condition field="caller_id_number" expression="^(\+1|1)?((876|809)\d{7})$">
<action application="respond" data="503"/>
<action application="hangup"/>
</condition>
</extension>

DID – Direct Inward Dialling via dialplan Public.xml

Assume we have a DID number 676767 which is served by telco provider either over SIP trunk/PRI lines . When someone from external world calls this number , FE needs to route the call to an internal user for example user at extension 3003 ( in default .xml context)

<include>
<extension name="public_did">
<condition field="destination_number" expression="^\+?1?(676767)$">
    <action application="set" data="domain_name=${domain}"/>
    <action application="transfer" data="3003 XML default"/>
</condition>
</extension>
</include>

If we are on multi domain setup , we need to setup the domain correctly .$${domain} is the default domain set from vars.xml but you can set it to any domain we have setup in user directory. Added the extra characters in from of DID number to adjust for various ISD code and number formats suffixes such as +1- ,91- , 0- etc .

IVR ( Interactive Voice Respondent ) using Menu

Main Menu – uses tts enginer and 3 attempsts to repond with timeout 10 seconds
On pressing 1 – bridge the call to conference , on press 2 – transfer to 2222 using default
On press of 3 – transfer using enum while on press 4 – play submenu. On press of 9 – goto top menu

<menu name="demo_ivr"
greet-long="say:Press 1 to join the conference, Press 2 to transfer, 3 to transfer, 4 to goto another menu"
greet-short="phrase:demo_ivr_main_menu_short"
invalid-sound="ivr/ivr-that_was_an_invalid_entry.wav"
exit-sound="voicemail/vm-goodbye.wav"
confirm-macro=""
confirm-key=""
tts-engine="flite"
tts-voice="rms"
confirm-attempts="3"
timeout="10000"
inter-digit-timeout="2000"
max-failures="3"
max-timeouts="3"
digit-len="4">
    <entry action="menu-exec-app" digits="1" param="bridge sofia/${domain}/888@conference.telcocompany.org"/>
    <entry action="menu-exec-app" digits="2" param="transfer 2222 XML default"/> 
    <entry action="menu-exec-app" digits="3" param="transfer 1234*256 enum"/> 
    <entry action="menu-sub" digits="4" param="demo_ivr_submenu"/> 
    <entry action="menu-exec-app" digits="/^(10[01][0-9])$/" param="transfer $1 XML features"/>
    <entry action="menu-top" digits="9"/> 
</menu>

Submenu – press * to repeat menu , # to exit . the timeout is 15 seconds

<menu name="demo_ivr_submenu"
greet-long="phrase:demo_ivr_sub_menu"
greet-short="phrase:demo_ivr_sub_menu_short"
invalid-sound="ivr/ivr-that_was_an_invalid_entry.wav"
exit-sound="voicemail/vm-goodbye.wav"
timeout="15000"
max-failures="3"
max-timeouts="3">
    <entry action="menu-top" digits="*"/>
    <entry action="menu-exit" digits="#"/>
</menu>

Find me Follow Me

If a users has lets say 3 phone – home , office and car then an incomming call should subesquently ring everywhere one by one till the user picks up the phone closet to him . leg_delay_start is the timer after which this endpoint will start riniging and leg_timeout is the duration till when this endpoint will ring.
Therfore as per below sample homephone will ring , after 5 sceonds office phone will ring and after 15 secons his cellphone 987654321 will ring . after 25 seconds call will end.

<action application="bridge" data="user/homephone0@mydomain.com, 
[leg_delay_start=5]user/officephone@mydomain.com, 
[leg_delay_start=15,leg_timeout=25] sofia/gateway/flowroute/987654321" />

DID can bridge to multiple extensions or gateways sequentially in a hunt pattern

<extension name="did_hunt">
<condition field="destination_number" expression="87654321">

<action application="set" data="hangup_after_bridge=true"/>
<action application="set" data="continue_on_fail=true"/>

<!-- this is needed to allow call_timeout to work after bridging to a gateway -->
<action application="set" data="ignore_early_media=true"/>

<!-- ring desk extension for 10 seconds. -->
<action application="set" data="call_timeout=10"/>
<action application="bridge" data="sofia/${domain}/1001"/>

<!-- Now try cell phone, hangup after 13 -->
<action application="set" data="call_timeout=13"/>
<action application="bridge" data="sofia/gateway/voicepulse/987654321" />

<!-- No answer, transfer to voicemail -->
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="voicemail" data="default ${domain} 1001"/>

</condition>
</extension>

Ring Multiple Targets

<action application="bridge" 
data="{ignore_early_media=true}user/7001@${domain}, 
user/7010@${domain}, user/7022@${domain}, user/7007@${domain}, 
sofia/gateway/flowroute/12345678901"/>

Handle Failures and Early Media

<action application="bridge" 
data="{ ignore_early_media=true, 
monitor_early_media_fail=user_busy:3:480+620!
destination_out_of_order:2:1776.7 }
sofia/internal/3000@local.telco.com|
sofia/internal/3004@local.telco.com"/>

To detect early media fail the conditions are

  • user busy – number of attempts is 3 and 480Hz 620Hz is the tone of frequency which is standard busy tone.
  • destination out of order – number of attempts 2 , 1776.7 Hz frequency .
    Note that as per condition only these frequencies are detected for action , others are ignored .

Directory

A simple directory listing containing two groups with 2 users each

<domain name="${domain}">
<params>
<param name="dial-string" value="{^^:sip_invite_domain=${dialed_domain}:
presence_id=${dialed_user}@${dialed_domain}}${sofia_contact(*/${dialed_user}@${dialed_domain})}/>
</params>

<variables>
<variable name="record_stereo" value="true"/>
<variable name="default_gateway" value="${default_provider}"/>
<variable name="default_areacode" value="${default_areacode}"/>
<variable name="transfer_fallback_extension" value="operator"/>
</variables>

<groups>
<group name="default">
    <users>
        <X-PRE-PROCESS cmd="include" data="default/*.xml"/>
    </users>
</group>

<group name="team1">
    <users>
        <user id="1000" type="pointer"/>
        <user id="1001" type="pointer"/>
    </users>
</group>

<group name="team2">
    <users>
        <user id="1002" type="pointer"/>
        <user id="1003" type="pointer"/>
    </users>
</group>

</groups>
</domain>

1001 user’s xml

<include>
<user id="1001">
<params>
<param name="password" value="${default_password}"/>
</params>
<variables>
    <variable name="toll_allow" value="domestic,international,local"/>
    <variable name="accountcode" value="1001"/>
    <variable name="user_context" value="default"/>
    <variable name="effective_caller_id_name" value="Extension 1001"/>
    <variable name="effective_caller_id_number" value="1001"/>
    <variable name="outbound_caller_id_name" value="${outbound_caller_name}"/>
    <variable name="outbound_caller_id_number" value="${outbound_caller_id}"/>
    <variable name="callgroup" value="team1"/>
</variables>
</user>
</include>

Adding users

/usr/src/freeswitch-debs/freeswitch# scripts/perl/add_user 3000

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
 LANGUAGE = (unset),
 LC_ALL = (unset),
 LC_CTYPE = "UTF-8",
 LANG = "en_US.UTF-8"
    are supported and installed on your system.

perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
Added 3000 in file /usr/local/freeswitch/conf/directory/default/3000.xml 
Operation complete. 1 user added.
Be sure to reloadxml.
Regular expression information:
            Sample regex for all new users: ^3000$
Sample regex for all new AND current users: ^(10(0[0-9]|1[0-9]|20)|3000)$

In the default configuration you can modify the expression in the condition for 'Local_Extension'.

Adding a range of users , 3000 to 3010

Since 3000 was already added previously , it threw a warning , rest were successfully added

/usr/src/freeswitch-debs/freeswitch# scripts/perl/add_user -users=3000-3010 

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
 LANGUAGE = (unset),
 LC_ALL = (unset),
 LC_CTYPE = "UTF-8",
 LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").

User id 3000 already exists, skipping...
Added 3001 in file /usr/local/freeswitch/conf/directory/default/3001.xml 
Added 3002 in file /usr/local/freeswitch/conf/directory/default/3002.xml 
Added 3003 in file /usr/local/freeswitch/conf/directory/default/3003.xml 
Added 3004 in file /usr/local/freeswitch/conf/directory/default/3004.xml 
Added 3005 in file /usr/local/freeswitch/conf/directory/default/3005.xml 
Added 3006 in file /usr/local/freeswitch/conf/directory/default/3006.xml 
Added 3007 in file /usr/local/freeswitch/conf/directory/default/3007.xml 
Added 3008 in file /usr/local/freeswitch/conf/directory/default/3008.xml 
Added 3009 in file /usr/local/freeswitch/conf/directory/default/3009.xml 
Added 3010 in file /usr/local/freeswitch/conf/directory/default/3010.xml 
Operation complete. 10 users added.
Be sure to reloadxml.
Regular expression information:
            Sample regex for all new users: ^30(0[123456789]|10)$
Sample regex for all new AND current users: ^(10(0[0-9]|1[0-9]|20)|30(0[0-9]|10))$
In the default configuration you can modify the expression in the condition for 'Local_Extension'.

After adding the user to directory , users can now make outbound calls . But howver cannot be rechable for incoming calls . To enable that e need to add them to dialplan .

Creating dialplan for the newly added users  in conf/dialplan/default.xml

update the existing condition 

<condition field="destination_number" expression="^(10[01][0-9])$"> with <condition field="destination_number" expression="^30(0[123456789]|10)$">

After this goto fs_cli cmd prompt and do reloadxml

Installation

Quick Installation on MacOS

Download and run the dmg.

Building from source on Ubuntu 16.04 Xenial

*experimental not suitable for production as per Freeswitch docs

The master branch depends on video libraries which are not available as packages in Debian distribution, but are available from FreeSWITCH repository , requires the use of the devscripts and cowbuilder packages.apt-get install git devscripts cowbuilder

Change to root and add freeswitch to sources.list

wget -O - https://files.freeswitch.org/repo/deb/freeswitch-1.8/fsstretch-archive-keyring.asc | apt-key add -
 
echo "deb http://files.freeswitch.org/repo/deb/freeswitch-1.8/ jessie main" > /etc/apt/sources.list.d/freeswitch.list
echo "deb-src http://files.freeswitch.org/repo/deb/freeswitch-1.8/ jessie main" >> /etc/apt/sources.list.d/freeswitch.list
 
apt-get update

apt-get build-dep freeswitch

cd /usr/src/

git clone https://freeswitch.org/stash/scm/fs/freeswitch.git -bv1.8 freeswitch

cd freeswitch

git config pull.rebase true

Enter freeswitch directory and Build

./bootstrap.sh -j
./configure
make
make install

for errors such as “The repository ‘http://files.freeswitch.org/repo/ubuntu-1604/freeswitch-unstable xenial InRelease’ is not signed.” and “The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 0xxxxxxx” please note than only debian 8 is the officially supported os version by FS now. hence is using AWS ( amazon web service ) stick with ubuntu v 14 ie Ubuntu Server 14.04 LTS (HVM), SSD Volume Type  which is also free tier eligible.

  Ubuntu      |       Debian  
18.04  bionic     buster  / sid   - 10
17.10  artful     stretch / sid   - 9
17.04  zesty      stretch / sid
16.10  yakkety    stretch / sid
16.04  xenial     stretch / sid
15.10  wily       jessie  / sid   - 8
15.04  vivid      jessie  / sid
14.10  utopic     jessie  / sid
14.04  trusty     jessie  / sid
13.10  saucy      wheezy  / sid   - 7
13.04  raring     wheezy  / sid
12.10  quantal    wheezy  / sid
12.04  precise    wheezy  / sid
11.10  oneiric    wheezy  / sid
11.04  natty      squeeze / sid   - 6
10.10  maverick   squeeze / sid
10.04  lucid      squeeze / sid

Manual Process of bootstarp and cofigure

Once build is successfull , install libtool-bin , libcurl4-openssl-dev , libpcre3-dev , libspeex-dev , libspeexdsp-dev ,libtiff5 ,libtiff5-dev , yasm for libvpx , liblua5.1-0-dev for scripting

For mod_enum support install libldns-dev or disable it in modules.conf

we can either install libedit-dev (>= 2.11) or configure with –disable-core-libedit-support

./bootstrap.sh
./configure 
make

For errors around lua file such as Cannot find lua.h header file , just do apt-get install lua5.2 and lua5.2-dev and copy the headers file manually to freeswitch languages folder such as
cp -R /usr/include/lua5.2/ src/mod/languages/mod_lua/
or you can copy these one by one lauxlib.h lua.h lua.hpp luaconf.h lualib.h

ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so llua

sudo make install
sudo make uhd-sounds-install
sudo make uhd-moh-install
sudo make samples

If you want to make lua from source

mkdir -p ~/Developing/third_party
cd Developing
wget https://www.lua.org/ftp/lua-5.3.2.tar.gz
tar xf lua-5.3.2.tar.gz
cd lua-5.3.2.tar.gz
make linux 
sudo make install INSTALL_TOP=/usr/local
cd ~/Developing/third_party/rtags/build
cmake -DLUA_INCLUDE_DIR=/usr/local/include/ -DLUA_LIBRARY=/usr/local/lib/liblua.a ../
aptitude install -y -r -o APT::Install-Suggests=true freeswitch-meta-vanilla
cp -a /usr/share/freeswitch/conf/vanilla /etc/freeswitch
/etc/init.d/freeswitch start

To see if freeswitch is running  – ps aux | grep freeswitch

fs_cli
Screen Shot 2018-09-20 at 10.45.47 AM

To check listening ports – ngrep -W byline -d any port 5060 or netstat -lnp | grep 5060

HTTPTCP800.0.0.0/0
HTTPTCP80::/0
Custom TCP RuleTCP5080 – 50810.0.0.0/0
Custom TCP RuleTCP5080 – 5081::/0
Custom UDP RuleUDP16384 – 327680.0.0.0/0
Custom UDP RuleUDP16384 – 32768::/0
All trafficAllAll0.0.0.0/0
All trafficAllAll::/0
SSHTCP220.0.0.0/0
Custom TCP RuleTCP80210.0.0.0/0
Custom TCP RuleTCP8021::/0
Custom UDP RuleUDP5060 – 50620.0.0.0/0
Custom UDP RuleUDP5060 – 5062::/0
Custom UDP RuleUDP5080 – 50810.0.0.0/0
Custom UDP RuleUDP5080 – 5081::/0
HTTPSTCP4430.0.0.0/0
HTTPSTCP443::/0
Custom TCP RuleTCP8081 – 80820.0.0.0/0
Custom TCP RuleTCP8081 – 8082::/0
Custom TCP RuleTCP5060 – 50610.0.0.0/0
Custom TCP RuleTCP5060 – 5061::/0

Debugging and Call

For internal calls , originate api can be used to initiate calls such as  originate ALEG BLEG

originate {origination_caller_id_number=9999988888}sofia/internal/1004@127.0.0.1:5060 91999998888 XML default CALLER_ID_NAME CALLER_ID_NUMBER

This will make a call out to sip:1004@1127.0.0.1 with the Caller ID number set to 999998888, then it will send the call to the XML dialplan using context=default. Then the dialplan will process call to 91999998888 with the Caller ID name and number specified in the fields CALLER_ID_NAME and CALLER_ID_NUMBER.

fsc_cli> originate sofia/internal/1002@127.0.0.1:5060 &echo()
switch_ivr_originate.c:2159 Parsing global variables
switch_channel.c:1104 New Channel sofia/internal/1002@127.0.0.1:5060 [5188806e-cabd-4acc-b20b-00620c3362ec]
mod_sofia.c:5026 (sofia/internal/1002@127.0.0.1:5060) State Change CS_NEW -> CS_INIT
switch_core_state_machine.c:584 (sofia/internal/1002@127.0.0.1:5060) Running State Change CS_INIT (Cur 5 Tot 122559)
switch_core_state_machine.c:627 (sofia/internal/1002@127.0.0.1:5060) State INIT
mod_sofia.c:93 sofia/internal/1002@127.0.0.1:5060 SOFIA INIT
sofia_glue.c:1299 sofia/internal/1002@127.0.0.1:5060 sending invite version: 1.9.0 -654-ed4920e 64bit
Local SDP:
v=0
o=FreeSWITCH 1538689496 1538689497 IN IP4 172.31.27.106
s=FreeSWITCH
c=IN IP4 172.31.27.106
t=0 0
m=audio 24636 RTP/AVP 9 0 8 101
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=sendrecv
m=video 19042 RTP/AVP 102
b=AS:1024
a=rtpmap:102 VP8/90000
a=sendrecv
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 ccm tmmbr
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
switch_core_state_machine.c:40 sofia/internal/1002@127.0.0.1:5060 Standard INIT
switch_core_state_machine.c:48 (sofia/internal/1002@127.0.0.1:5060) State Change CS_INIT -> CS_ROUTING
switch_core_state_machine.c:627 (sofia/internal/1002@127.0.0.1:5060) State INIT going to sleep
switch_core_state_machine.c:584 (sofia/internal/1002@127.0.0.1:5060) Running State Change CS_ROUTING (Cur 4 Tot 122612)
sofia.c:7291 Channel sofia/internal/1002@127.0.0.1:5060 entering state [calling][0]
sofia.c:7291 Channel sofia/internal/1002@127.0.0.1:5060 entering state [terminated][503]

Security

-tbd

  • ACL
  • Fail2Ban
  • IPtables

Ref :

My freeswitch contributor profile