Proxying Media Streams via Kamailio’s RTP Proxy

Kamailio is a SIP server which does not play any role by itself in media transmission path. this behaviour leads to media packets having to attempt to stream peer to peer between caller and callee which in turn many a times causes them to get dropped in absence of NAT management

To ensure that media stream is proxied via an RTP proxy kamailio can use RTP proxy module combined with a RTP proxy.

This setup also provides other benefits such as controlling media media , security , Load balancing between many rtp proxies ,bridge signalling between multiple network interfaces etc.

RTP Proxy module

Used to proxy the media stream .

RTP proxies that can be used along with this module are:

RTP proxies can be used for bridging network interfaces , load distribution and balancing etc.It does not support transcoding.

Parameters :

rtpproxy_sock – binds a ip and port for rtp proxy

 modparam("rtpproxy", "rtpproxy_sock", "udp:localhost:12221")

rtpproxy_disable_tout – when rtp proxy is disabled then timeout till when it doesnt connect

rtpproxy_tout – timeout to wait for reply

rtpproxy_retr – num of retries after timeout

nortpproxy_str – sets the SDP attribute used by rtpproxy to mark the message’s SDP attachment with information that it have already been changed. Default value is


and others like


timeout_socket (string)

ice_candidate_priority_avp (string)

extra_id_pv (string)

db_url (string)

table_name (string)

rtp_inst_pvar (string)


set_rtp_proxy_set(setid) – Sets the Id of the rtpproxy set to be used for the next unforce_rtp_proxy(), rtpproxy_offer(), rtpproxy_answer() or rtpproxy_manage() command

rtpproxy_offer([flags [, ip_address]]) – to make the media pass through RTP the SDP is altered. Value of flag can be
1 – append first Via branch to Call-ID when sending command to rtpproxy.
2 – append second Via branch to Call-ID when sending command to rtpproxy. See flag ‘1’ for its meaning.
3 – behave like flag 1 is set for a request and like flag 2 is set for a reply
a – flags that UA from which message is received doesn’t support symmetric RTP. (automatically sets the ‘r’ flag)
b – append branch specific variable to Call-ID when sending command to rtpproxy
l – force “lookup”, that is, only rewrite SDP when corresponding session already exists in the RTP proxy
i, e – direction of the SIP message when rtpproxy is running in bridge mode. ‘i’ is internal network (LAN), ‘e’ is external network (WAN). Values ie , ei , ee and ii
x – shortcut for using the “ie” or “ei”-flags, to do automatic bridging between IPv4 on the “internal network” and IPv6 on the “external network”. Differentiated by IP type in the SDP, e.g. a IPv4 Address will always call “ie” to the RTPProxy (IPv4(i) to IPv6(e)) and an IPv6Address will always call “ei” to the RTPProxy (IPv6(e) to IPv4(i))
f – instructs rtpproxy to ignore marks inserted by another rtpproxy in transit to indicate that the session is already gone through another proxy. Allows creating a chain of proxies
r – IP address in SDP should be trusted. Without this flag, rtpproxy ignores address in the SDP and uses source address of the SIP message as media address which is passed to the RTP proxy
o – flags that IP from the origin description (o=) should be also changed.
c – flags to change the session-level SDP connection (c=) IP if media-description also includes connection information.
w – flags that for the UA from which message is received, support symmetric RTP must be forced.
zNN – perform re-packetization of RTP traffic coming from the UA which has sent the current message to increase or decrease payload size per each RTP packet forwarded if possible. The NN is the target payload size in ms, for the most codecs its value should be in 10ms increments, however for some codecs the increment could differ (e.g. 30ms for GSM or 20ms for G.723).
ip_address denotes the address of new SDP

such as : rtpproxy_offer(“FRWOC+PS”) is
rtpengine_offer(“force trust-address symmetric replace-origin replace-session-connection ICE=force RTP/SAVPF”);

route { 
if (is_method("INVITE")) 
    if (has_body("application/sdp")) 
        if (rtpproxy_offer()) t_on_reply("1"); 
    } else { 

if (is_method("ACK") && has_body("application/sdp")) rtpproxy_answer(); 
onreply_route[1] { 
   if (has_body("application/sdp")) rtpproxy_answer(); 
onreply_route[2] { 
   if (has_body("application/sdp")) rtpproxy_offer(); 

rtpproxy_answer([flags [, ip_address]])- rewrite SDP to proxy media , it can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.

rtpproxy_destroy([flags]) – tears down RTP proxy session for current call. Flags are ,
1 – append first Via branch to Call-ID
2 – append second Via branch to Call-ID
b – append branch specific variable to Call-ID
t – do not include To tag to “delete” command to rtpproxy thus causing full call to be deleted


rtpproxy_manage([flags [, ip_address]]) – Functionality is to use predfined logic for handling requests
If INVITE with SDP, then do rtpproxy_offer()
If INVITE with SDP, when the tm module is loaded, mark transaction with internal flag FL_SDP_BODY to know that the 1xx and 2xx are for rtpproxy_answer()
If ACK with SDP, then do rtpproxy_answer()
If BYE or CANCEL, or called within a FAILURE_ROUTE[], then call unforce_rtpproxy().
If reply to INVITE with code >= 300 do unforce_rtpproxy()
If reply with SDP to INVITE having code 1xx and 2xx, then do rtpproxy_answer() if the request had SDP or tm is not loaded, otherwise do rtpproxy_offer()
This function can be used from ANY_ROUTE.

rtpproxy_stream2uac(prompt_name, count) – stream prompt/announcement pre-encoded with the makeann command. The uac/uas suffix selects who will hear the announcement relatively to the current transaction – UAC or UAS. Also used for music on hold (MOH).
Params : prompt_name – path name of the prompt to stream
count – number of times the prompt should be repeated. When count is -1, the streaming will be in loop indefinitely until the appropriate rtpproxy_stop_stream2xxx is issued.
Example rtpproxy_stream2xxx usage

if (is_method("INVITE")) { 
if (is_audio_on_hold()) {
rtpproxy_stream2uas("/var/rtpproxy/prompts/music_on_hold", "-1");
} else {

rtpproxy_stream2uas(prompt_name, count)

rtpproxy_stop_stream2uac()- Stop streaming of announcement/prompt/MOH



Exported Pseudo Variables


RPC Commands


Ref :


This post describes the installation , setup and configuration of Office SIP server to provide a registrar to our SIP based WebRTC application .

1. Get office SIP from this website


2. Downloaded office sip executable on windows looks like this . double click on it to start installation .


3.Installation screen appears as follows


4. Terms and conditions


5. Destination folder for installation


6. Installing


7. Validating install


8. Installation completed


9. Launch icon on dekstop


10 . Office SIP web login screen


11. create account ( also known as realm or domain ) for users to register in their SIP and webrtc sip agents


12. Fill in account details for every account added to officeSIP


13. add users that will be registering to officeSIP server


14.Office SIP settings file can be modified for changing server parameters like ip and port


15 . Office SIP can now be used by sip agents like softphones , webRTC pages , etc to register with OfficeSIP server

BEA Weblogic SIP server

Bea server is a old SIP servlet container ie application server which is used to embed control logic in a program . It is supported on jdk1.5 hence the system’s environment variables must match . Otherwise in later stages deploying applications throw class version error .

1. Install Bea Weblogic

2. Follow the Installation steps

Make domain

3. Goto the installation directory . Usually C:/bea/user_projects/mydomain/ .

click on startweblogic.cmd in windows. In case the system is linux run script

4. Open Web console on url : Enter username password

default username password weblogic , weblogic .

It can also be customized for example my username and password are altanai , tcs@1234

5.  Make Converged SIP Servlet Application in any editor such as notepad , edit+ etc .

The project structure looks like

Call screening

The SIP servlet are put side directory structure of src

For example : sample application for Call screening

package com.altanai.voice;
import javax.servlet.*;
import javax.servlet.sip.*;
import javax.servlet.sip.Proxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.*;
public class CallScreening extends SipServlet
private static SipFactory factory;
private static SipApplicationSession sas;
private static Proxy proxy;
public void init(ServletConfig config) throws ServletException
System.out.println(“Call screening SIP servlet initiated”);
protected void doInvite(SipServletRequest req) throws java.lang.IllegalArgumentException,java.lang.IllegalStateException,javax.servlet.ServletException,
System.out.println(“Received an Invite Request”);
System.out.println(“User is blocked”);
System.out.println(“User is not blocked”);

6. Build it with ant . For this go inside the application folder and run ant. Output will either be “failed to build “ or “build successfully” .

The ant  command generates the war file from SIP servlet Web application .

7. Incase of successful build . Add the application to Weblogic web console install section and activate it .

I will demonstrate this process in step by step manner . First  click on “ Lock and Edit “ Button on the left panel . Then goto Install button in the centre area and browser to the location of application war or sar we have build through ant ,

8. We can delete an application in exactly the same way . click on “ Lock and Edit “ Button on the left panel . Then goto the delete button after selecting the radio button alongside the application we want to delete.

8. For enhanced application building we can also refer to sample provided along with bea weblogic . file:///C:/bea/sipserver30/samples/sipserver/examples/src/index.html

Kamailio Call routing and Control

Kamailio SIP server evolved from SER and OpenSER. Written in ANSI C , primarily it is an open source proxy SIP server. RFC 3261 compliant and has support for various Operating system to install and run on as alpine , centos , deb , fedora , freebsd , netbsd , obs , openbsd , opensuse , oracle , rhel , solaris so on .

With modular design it already has 150 + modules and can have third party addons like Databases , RTP engines etc. Anyone can contribute to extensions and modules read here. Also contains cmd line tool kamcmd , kamcli and Web management interface SIREMIS .

It has provisions for complex routing logic development through scripts and programming languages interpreter support.

Over the years kamailio as proven a key component of a “carrier-grade” SIP service delivery platform. Either as SBC interfacing internal softswitch with public internet and handling complex operation as NAT, auth , flood control, topology hiding etc or even as the core SIP Server handling RTP relay as well.

Kamailio’s call routing log can be divided into:

  • Core functions
  • Core modules needed for almost any useful configuration like transaction module , Record route module etc ( read more
  • Ancillary modules to provide specific functionality (e.g. JANSSON , PIKE)
  • Pseudo-variables , which hold read/writeable attributes and
  • Transformations and custom logic definition.

Kamailio config

kamailio confguration file should be composed of
Core configuration directives as


Global Parameters like


Loading Modules

loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""

Module parameters
For example considering for tm auto-discard branches from previous serial forking leg as failure_reply_mode ,30 sec as default retransmission timeout with 120 sec as invite retransmission timeout after 1xx

modparam("tm", "failure_reply_mode", 3)
modparam("tm", "fr_timer", 30000)
modparam("tm", "fr_inv_timer", 120000)

Subroutines (in essence, SIP event callbacks):
Request routes (request_route)
Reply routes (onreply_route)
Failure routes (failure_route)
Branch routes

For example consider main sip routing block

request_route {
    if (is_method("CANCEL"))
        if (t_check_trans()) {
    if (is_method("INVITE|SUBSCRIBE"))

Custom event routes (callbacks/event handlers exposed by modules).
Code for programming languages and runtimes:
String transformations
Ephemeral/scratch-pad variables ($var(…))
Transaction-persistent variables ($avp(…)/$xavp(…)) , extended AVP like AVP ar attached to transactions and not messages .
Dialog-persistent variables ($dlg_var(…))

$var(rc) = $rc;
switch ($var(rc)) {
    case -1:
    case -3:
        send_reply("404", "Not Found");
    case -2:
        send_reply("405", "Method Not Allowed");

This article describes call routing config for Kamailio under following roles

  • SIP Proxy
  • Registrar
  • Accountant
  • Session border Controller

Kamailio as Proxy Server

Simple Kamailio configuration with basic features like alias , accounting , record routing , handling SIP requests like INVITE and its replies . Also failure and NAT handling . More samples of Kamailio config and call routing are at


#Defined Values
!substdef "!MY_IP_ADDR!!g"
!substdef "!MY_EXTERNAL_IP!!g"
!substdef "!MY_UDP_PORT!!g"
!substdef "!MY_TCP_PORT!!g"
!substdef "!MY_UDP_ADDR!udp:MY_IP_ADDR:MY_UDP_PORT!g"
!substdef "!MY_TCP_ADDR!tcp:MY_IP_ADDR:MY_TCP_PORT!g"

; - flags
; FLT_ - per transaction (message) flags
; FLB_ - per branch flags
!define FLT_ACC 1
!define FLT_NATS 5
!define FLB_NATB 6

# Global Parameters
; LOG Levels:3 = DBG, 2 = INFO, 1 = NOTICE, 0 = WARN, -1 = ERR
debug = 2
log_stderror = no
memdbg = 5
memlog = 5
log_facility = LOG_LOCAL0
log_prefix = "{$mt $hdr(CSeq) $ci} "

/* number of SIP routing processes */
children = 2
/* uncomment the next line to disable TCP (default on) */
disable_tcp = yes
/* uncomment the next line to disable the auto discovery of local aliases based on reverse DNS on IPs (default on) */
auto_aliases = no

/* add local domain aliases */
alias = ""

/* listen addresses */
listen = udp:

# Modules Section
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""
loadmodule ""

----------------- setting module-specific parameters --------------

----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
/* set the path to RPC unix socket control file */
modparam("jsonrpcs", "dgram_socket", "/var/run/kamailio/kamailio_rpc.sock")

; ----- ctl params -----
/* set the path to RPC unix socket control file */
modparam("ctl", "binrpc", "unix:/var/run/kamailio/kamailio_ctl")

; ----- tm params -----
auto-discard branches from previous serial forking leg
modparam("tm", "failure_reply_mode", 3)
default retransmission timeout:30sec
modparam("tm", "fr_timer", 30000)
default invite retransmission timeout after 1xx:120sec
modparam("tm", "fr_inv_timer", 120000)

; ----- rr params -----
# set next param to 1 to add value to;lr param (helps with some UAs)
modparam("rr", "enable_full_lr", 0)
; do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

----- acc params -----
; /* what special events should be accounted ? / modparam("acc", "early_media", 0) modparam("acc", "report_ack", 0) modparam("acc", "report_cancels", 0) / by default ww do
; not adjust the direct of the sequential requests.
; if you enable this parameter, be sure the enable "append_fromtag"
; in "rr" module / 
modparam("acc", "detect_direction", 0) / account triggers (flags) */
modparam("acc", "log_flag", FLT_ACC)
modparam("acc", "log_missed_flag", FLT_ACCMISSED)
modparam("acc", "log_extra",
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)

# Routing Logic

/* Main SIP request routing logic*/
request_route {
;     per request initial checks
    ; CANCEL processing
    if (is_method("CANCEL")) {
        if (t_check_trans()) {
    ; handle retransmissions
    if (!is_method("ACK")) {
        if (t_precheck_trans()) {

    ; handle requests within SIP dialogs
    ;     only initial requests (no To tag)
    ; record routing for dialog forming requests ( in case they are routed)
    ; - remove preloaded route headers
    if (is_method("INVITE|SUBSCRIBE")) {
    ;     account only INVITEs
    if (is_method("INVITE")) {
        setflag(FLT_ACC); # do accounting
    if ($rU==$null) {
        # request with no Username in RURI
        sl_send_reply("484", "Address Incomplete");

    # update $du to set the destination address for proxying
    $du = "sip:" + $rd + ":9";

# Wrapper for relaying requests
route[RELAY] {
    if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {     
        if (!t_is_set("branch_route")) 

    if (is_method("INVITE|SUBSCRIBE|UPDATE")) {     
        if (!t_is_set("onreply_route")) 

    if (is_method("INVITE")) {
        if (!t_is_set("failure_route")) 

    if (!t_relay()) {     

#P er SIP request initial checks
route[REQINIT] {
    if ($ua = ~ "friendly-scanner|sipcli|VaxSIPUserAgent") {
        # sl_send_reply("200", "OK");
    if (!mf_process_maxfwd_header("10")) {
        sl_send_reply("483", "Too Many Hops");

    if (is_method("OPTIONS") && uri==myself && $rU==$null) {     
        sl_send_reply("200", "Keepalive");

    if (!sanity_check("1511", "7")) {
        xlog("Malformed SIP message from $si:$sp\n");

# Handle requests within SIP dialogs

route[WITHINDLG] {
    if (!has_totag()) 
        return ;
    if (loose_route()) {
        if (is_method("BYE")) {
            setflag(FLT_ACC); # do accounting ...         
            setflag(FLT_ACCFAILED); # ... even if the transaction fails
        } else{
            if (is_method("NOTIFY")) {
                # Add Record-Route for in -dialog NOTIFY as per RFC 6665.         

    if (is_method("ACK")) {
        if (t_check_trans()) {         
            # no loose-route, but stateful ACK;         
            must be an ACK after a 487 or e.g. 404 from upstream server         
        } else {
            # ACK without matching transaction, ignore and discard         
    sl_send_reply("404", "Not here"); exit;

    #Manage outgoing branches
    branch_route[MANAGE_BRANCH] {
    xdbg("new branch [$T_branch_idx] to $ru\n");

--# Manage incoming replies
onreply_route[MANAGE_REPLY] {
    xdbg("incoming reply\n");

--# Manage failure routing cases
failure_route[MANAGE_FAILURE] {
    if (t_is_canceled()) exit;

Controlling Call Routing from command Line

To find the loaded flags while starting kamailio

kamailio -v
version: kamailio 5.1.8 (x86_64/linux) d8e930
poll method support: poll, epoll_lt, epoll_et, sigio_rt, select.
id: d8e930 
compiled on 09:47:09 May  3 2019 with gcc 4.8.4


creates the database support for many kamailio modules such as auth , location , dispatcher , permission etc

make sure you load a DB engine , during kamailio installation and configuration . It can be either done though make command or though modules.lst file

 make include_modules="db_mysql" cfg
 make all
 make install

since json replaced all fifo command, ensure you do not get "json.h: No such file or directory” in server by install json either via libjson-c-dev or libjson-cpp-dev

apt-get install libjson-c-dev 

For uuid/uuid.h: No such file or directory install

apt-get install uuid-dev

For libpq-fe.h: No such file or directory install

apt-get install libpq-dev

kamdbctl command list

kamdbctl create <db name or db_path, optional> ...(creates a new database)
kamdbctl drop <db name or db_path, optional> .....(!entirely deletes tables!)
kamdbctl reinit <db name or db_path, optional> ...(!entirely deletes and than re-creates tables!)
kamdbctl backup <file> ...........................(dumps current database to file)
kamdbctl restore <file> ..........................(restores tables from a file)
kamdbctl copy <new_db> ...........................(creates a new db from an existing one)
kamdbctl presence ................................(adds the presence related tables)
kamdbctl extra ...................................(adds the extra tables)
kamdbctl dbuid ...................................(adds the uid tables)
kamdbctl dbonly ..................................(creates empty database)
kamdbctl grant ...................................(grant privileges to database)
kamdbctl revoke ..................................(revoke privileges to database)
kamdbctl add-tables <gid> ........................(creates only tables groupped in gid)

if you want to manipulate database as other database user than
root, want to change database name from default value "kamailio",
or want to use other values for users and password, edit the
"config vars" section of the command kamdbctl.

kamdbctl pframework create .......................(creates a sample provisioning framework file)

For psql: received invalid response to SSL negotiation: [
ERROR: Creating database failed!
errors . Remember for mysql the defaul port is 3306, but for psql it is 5432 . Hence make the change in /etc/kamailio/kamctlrc

database port


If kamctl isnt accessible from the machine installed with kamailio , just goto kamctl folder and compile it yourself . For example for me , I took the git pull of kamailio source code v 5.1.0 and went to util folder

cd  /kamailio_source_code/utils/kamctl 
make && make install 

some commands

‘acl’ – manage access control lists (acl)
‘lcr’ – manage least cost routes (lcr)
‘cr’ – manage carrierroute tables show|reload|dump
‘rpid’ – manage Remote-Party-ID (RPID)
‘add|passwd|rm’ – manage subscribers
‘add|dump|reload|rm|show’ – manage trusted
‘add|dump|reload|rm|show’ – manage address
‘add|dump|reload|rm|show’ – manage address
‘dispatcher’ – manage dispatcher

dispatcher add 1 sip: 1 5 'prefix=proxycall' 'gatewaye33'

‘dialog’ – manage dialog records
‘srv’ – server management commands
‘cisco_restart’ – restart CISCO phone (NOTIFY)
‘online’ – dump online users from memory
‘monitor’ – show internal status

[cycle #: 3; if constant make sure server lives]
Kamailio Runtime Details: 
kamailio 5.1.8 (x86_64/linux) d8e930
    now:  Fri May 24 13:39:19 2019
    up_since: Fri May 24 13:31:37 2019
    uptime: 462

Transaction Statistics: 
    tmx:UAS_transactions = 0        tmx:UAC_transactions = 0        tmx:active_transactions = 0     tmx:inuse_transactions = 0

Stateless Server Statistics: 
    sl:sent_replies = 0            sl:sent_err_replies = 0

UsrLoc Statistics: 
    usrloc:location-contacts = 0        usrloc:location-expires = 0         usrloc:location-users = 0           usrloc:registered_users = 0

Core Statistics: 
    core:rcv_requests = 0        core:fwd_requests = 0       core:rcv_replies = 0        core:fwd_replies = 0

Shared Memory Statistics: 
    shmem:fragments = 1                shmem:max_used_size = 2807640       shmem:total_size = 67108864
    shmem:free_size = 64301224            shmem:real_used_size = 2807640      shmem:used_size = 2566040

‘ping’ – ping a SIP URI (OPTIONS)
‘ul|alias’ – manage user location or aliases
‘ps’ – print details about running processes
‘ps’ – print details about running processes
‘stats’ – print internal statistics

  "jsonrpc":  "2.0",
  "result": [
    "core:bad_URIs_rcvd = 0",
    "core:bad_msg_hdr = 0",
    "core:drop_replies = 0",
    "core:drop_requests = 0",
    "core:err_replies = 0",
    "core:err_requests = 0",
    "core:fwd_replies = 0",
    "core:fwd_requests = 0",
    "core:rcv_replies = 0",
    "core:rcv_replies_18x = 0",
    "core:rcv_replies_1xx = 0",
    "core:rcv_replies_2xx = 0",
    "core:rcv_replies_3xx = 0",
    "core:rcv_replies_401 = 0",
    "core:rcv_replies_404 = 0",
    "core:rcv_replies_407 = 0",
    "core:rcv_replies_480 = 0",
    "core:rcv_replies_486 = 0",
    "core:rcv_replies_4xx = 0",
    "core:rcv_replies_5xx = 0",
    "core:rcv_replies_6xx = 0",
    "core:rcv_requests = 0",
    "core:rcv_requests_ack = 0",

‘rpc’ – send raw RPC commands


unix tool for interfacing with Kamailio using exported RPCs. It uses binrpc (a proprietary protocol, designed for minimal packet size and fast parsing) over a variety of transports (unix stream sockets, unix datagram sockets, udp or tcp).

 alias: ps
 alias: psx
 alias: list
 alias: ls
 alias: ver
 alias: version
 alias: who
 alias: listen
 alias: dns_mem_info
 alias: dns_debug
 alias: dns_debug_all
 alias: dst_blacklist_mem_info
 alias: dst_blacklist_debug
 builtin: ?
 builtin: help
 builtin: version
 builtin: quit
 builtin: exit
 builtin: warranty
 builtin: license

some examples of the kamcmd commands


> kamctl kamcmd 
current: 0     
waiting: 0     
total: 0     
total_local: 0     
rpl_received: 0     
rpl_generated: 0     
rpl_sent: 0     
6xx: 0     
5xx: 0     
4xx: 0     
3xx: 0     
2xx: 0     
created: 0     
freed: 0     
delayed_free: 0 

Get info about TLS

    max_connections: 2048
    opened_connections: 1
    clear_text_write_queued_bytes: 0

Get info about open sockets

kamcmd> core.sockets_list
    socket: {
        proto: udp
        port: 5060
        mcast: no
        mhomed: no
    socket: {
        proto: tcp
        port: 5060
        mcast: no
        mhomed: no
    socket: {
        proto: tcp
        port: 80
        mcast: no
        mhomed: no
    socket: {
        proto: tls
        port: 5061
        mcast: no
        mhomed: no
    socket: {
        proto: tls
        port: 443
        mcast: no
        mhomed: no

get core info

kamcmd >
    version: kamailio 5.2.3
    id: 4a4588 
    compiler: gcc 5.4.0
    compiled: 15:54:50 Jun 27 2019

Kamailio Transaction Module

Although most of kamailio module related description is covered here , I wanted to keep a separate space to describe and explain how kamailio handles transactions and in particular , Transaction Module .

Note : This article has been updated many time to match v5.1 since v3.0 from when it was written, if u see and outdated content or deprecated functions, please point them out to me in comments.

If you are new to kamailio , this post os not for you , instead read more on kamailio as a powerful sip server here or its application in telephony domain here .

Kamailio is basically only a transaction stateful proxy, without any dialog support build in. Here the TM module enables stateful processing of SIP transactions ( by maintaining state machine). State is a requirement for many complex logic such as accounting, forking , DNS resolution .

we know that SIP is a transactional protocol and every request and its response goes within a transaction. more on SIP as protocol is here

t_relay, t_relay_to_udp and t_relay_to_tcp are main functions to setup transaction state, absorb retransmissions from upstream, generate downstream retransmissions and correlate replies to requests.

Lifecycle of Transaction

Transactions lifecycle are controlled by various factors which includes coming from reliable ( TCP) or non reliable transport , invite or non invite transaction types etc.

Transaction are terminated either by final response or when timers are fired which control it.

Memory Management in Transactions

Transaction Module copies clones of received SIP messages in shared memory. non-TM functions operate over the received message in private memory. Therefore core operations ( like record_route) should not be called before settings the transaction state ( t_realy ) for state-fully processing a message.

An INVITE transaction will be kept in memory for maximum: max_inv_lifetime + fr_timer + wt_timer.
While A non-INVITE transaction will be kept in memory for a maximum: max_noninv_lifetime + wt_timer.


A single SIP INVITE request may be forked to multiple destinations , all of which together is called destination setse and Individual elements within the destination sets are called branches.

Serial , Parallel and Combined Forking – By default kamailio performs parallel forking sending msg to all destinations and waiting for response , however it can also do serail ie send request one by one and wait for reposne /timeout before sending next . By use of priorities ( q valaue 0 – 1.0), Kamailio can also intermix the forking technique ie decreasing priority oder for serial and same level for parallel . The destination uri are loaded using unctions t_load_contacts() and t_next_contacts().

parallel forking exmaple

request_route {


mixed forking exmaple

modparam("tm", "contacts_avp", "tm_contacts");
modparam("tm", "contact_flows_avp", "tm_contact_flows");

request_route {
  seturi(""); // lowest 0 
  append_branch("", "0.5"); // shoudl be in parallel with C
  append_branch("", "0.5"); // shoudl be in parallel with B
  append_branch("", "1.0"); // highest priority , should be tried first

  t_load_contacts();   // load all branches as per q values, store them in AVP configured in modparam 
  t_next_contacts();   // takes AVP and extracts higher q value branch


Code to terminate when no more branches are found ( -1 returned) and return the message upstream

   if (!t_next_contacts()) {

Transaction Module Parameters

various parameters are used to fine tune how trsnactions are handled and timedout in kamailio. Note all timers are set in miliseconds notation.

fr_timer (integer) – timer hit when no final reply for a request or ACK for a negative INVITE reply arrives. Default 30000 ms (30 seconds).

fr_inv_timer (integer) – timer hit when no final reply for an INVITE arrives after a provisional message was received on branch. Default 120000 ms (120 seconds).

restart_fr_on_each_reply (integer) – restart fr_inv_timer fir INVITE transaction for each provisional reply. Otherwise it will be sreatred only for fisrt and then increasing provisonal replies. Turn it off in cases when dealing with bad UAs that continuously retransmit 180s, not allowing the transaction to timeout.

max_inv_lifetime (integer) – Maximum time an INVITE transaction is allowed to be active in a tansaction. It starts from the time trnsaction was created and after this timer is hit , transaction is moved to either wait state or in the final response retransmission state. Default 180000 ms (180 seconds )

max_noninv_lifetime (integer) – Maximum time a non-INVITE transaction is allowed to be active. default 32000 ms (32 seconds )

wt_timer (integer) – Time for which a transaction stays in memory to absorb delayed messages after it completed.

delete_timer (integer) – Time after which a to-be-deleted transaction currently ref-ed by a process will be tried to be deleted again. This is now obsolte and now transaction is deleted the moment it’s not referenced anymore.

retr_timer1 (integer) – Initial retransmission period

retr_timer2 (integer) – Maximum retransmission period started increasingly from starts with retr_timer1 and stays constant after this

noisy_ctimer (integer) – if set, INVITE transactions that time-out (FR INV timer) will be always replied. Otherwise they will be quitely dropped without any 408 branch timeout resposne

auto_inv_100 (integer) – automatically send and 100 reply to INVITEs.

auto_inv_100_reason (string) – Set reason text of the automatically sent 100 to an INVITE.

unix_tx_timeout (integer) – nix socket transmission timeout,

aggregate_challenges (integer) – if more than one branch received a 401 or 407 as final response, then all the WWW-Authenticate and Proxy-Authenticate headers from all the 401 and 407 replies will be aggregated in a new final response.

blst_503 (integer) – reparse_invite=1.

blst_503_def_timeout (integer) – blacklist interval if no “Retry-After” header is present

blst_503_min_timeout / blst_503_max_timeout (integer) – minimum and maximun blacklist interval respectively

blst_methods_add (unsigned integer) – Bitmap of method types that trigger blacklisting on transaction timeouts and by default INVITE triggers blacklisting only

blst_methods_lookup (unsigned integer) – Bitmap of method types that are looked-up in the blacklist before being forwarded statefully. For default only applied to BYE.

reparse_invite (integer) – set if CANCEL and negative ACK requests are to be constructed from the INVITE message ( same record-set etc as INVITE ) which was sent out instead of building them from the received request.

ac_extra_hdrs (string) – Header fields prefixed by this parameter value are included in the CANCEL and negative ACK messages if they were present in the outgoing INVITE. Can be only used with reparse_invite=1.

reparse_on_dns_failover (integer) – SIP message after a DNS failover is constructed from the outgoing message buffer of the failed branch instead of from the received request.

on_sl_reply (string) – Sets reply route block, to which control is passed when a reply is received that has no associated transaction.

modparam("tm", "on_sl_reply", "stateless_replies")
onreply_route["stateless_replies"] {
    // return 0 if do not allow stateless replies to be forwarded
    return 1; // will pass to core for stateless forwading

xavp_contact (string) – name of XAVP storing the attributes per contact.

contacts_avp (string) – name of an XAVP that stores names of destination sets. Used by t_load_contacts() and t_next_contacts() for forking branches

contact_flows_avp (string) – name of an XAVP that were skipped

fr_timer_avp (string) – override teh value of fr_timer on per transactio basis , outdated

fr_inv_timer_avp (string) – same as abovel , outdated

cancel_b_method (integer) – method to CANCEL an unreplied transaction branch. Params :
0 will immediately stop the request (INVITE) retransmission on the branch so that unrpelied branches will be terminated
1 will keep retransmitting the request on unreplied branches.
2 end and retransmit CANCEL even on unreplied branches, stopping the request retransmissions.

unmatched_cancel (string) – sets how to forward CANCELs that do not match any transaction. Params :
0 statefully
1 statelessly
2 dropping them

ruri_matching (integer) – try to match the request URI when doing SIP 1.0 transaction matching as older SIP didnt have via cookies as in RFC 3261

via1_matching (integer) – match the topmost “Via” header when doing SIP 1.0 transaction matching

callid_matching (integer) – match the callid when doing transaction matching.

pass_provisional_replies (integer)

default_code (integer) – Default response code sent by t_reply() ( 500 )

default_reason (string) – Default SIP reason phrase sent by t_reply() ( “Server Internal Error” )

disable_6xx_block (integer)- treat all the 6xx replies like normal replies. However according to RFC receiving a 6xx will cancel all the running parallel branches, will stop DNS failover and forking.

local_ack_mode (integer) – where locally generated ACKs for 2xx replies to local transactions are sent. Params :
0 – the ACK destination is choosen according next hop in contact and the route set and then DNS resolution is used on it
1 – the ACK is sent to the same address as the corresponding INVITE branch
2 – the ACK is sent to the source of the 2xx reply.

failure_reply_mode (integer) – how branches are managed and replies are selected for failure_route handling. Params :
0 – all branches are kept
1 – all branches are discarded
2 – only the branches of previous leg of serial forking are discarded
3 – all previous branches are discarded
if you dont want to drop all branches then use t_drop_replies() to sleectively drop

faked_reply_prio (integer) – how branch selection is done.

local_cancel_reason (boolean) – add reason headers for CANCELs generated due to receiving a final reply.

e2e_cancel_reason (boolean) – add reason headers for CANCELs generated due to receiving a CANCEL

remap_503_500 (boolean) – conversion of 503 response code to 500. RFC requirnment.

failure_exec_mode (boolean) – Add local failed branches in timer to be considered for failure routing blocks.

dns_reuse_rcv_socket (boolean) – reuse of the receive socket for additional branches added by DNS failover.

event_callback (str) – function in the kemi configuration file (embedded scripting language such as Lua, Python, …) to be executed instead of event_route[tm:local-request] block. The function recives a string param with name of the event

modparam("tm", "event_callback", "ksr_tm_event")
function ksr_tm_event(evname)"===== TM module triggered event: " .. evname .. "\n");
    return 1;

relay_100 (str) – whether or not a SIP 100 response is proxied. not valid behavior when operating in stateful mode and only useful when in stateless mode

rich_redirect (int) – to add branch info in 3xx class reply. Params :
0 – no extra info is added (default)
1 – include branch flags as contact header parameter
2 – include path as contact uri Route header

Mobicents SIP server platform

We know that SIP is in the p2p session layer of the OSI mode and used to setup voip sessions and that a SIP Servlets must be executed within a SIP Servlets Container, which implements the SIP Servlet specification. Mobicents sip servlets have been extensively used to create , deploy and manage VOIP services. Also it has a converged application server where a web application is composed of one or more HTTP Servlets and one or more SIP Servlets.

Mobicents runs atop Jboss Application server and integrates sip protocol stack. Its roles

  • Handle the communication with the client.
  • Persist the data and handle communication with the database.
  • Execute the Beans which is a server-side component that encapsulates the business logic of an application
  • Provide clustering, fail-over and load-balancing.
  • Local memory access / caching.
  • Manage transactions

The Mobicent server bears 50% resemblance to Rhino TAS .

Mobicents application routers

Mobicents Sip Servlets ships with a default application router (DAR) which selects which application to execute in a container for a request.

So far , I have successfully done the following

1. installed the Mobicent platform on Linux machine
2.set up the environment to build and deploy the applications

sip server types

1.Mobicents as registrar

registrar is aware of the IP address of the client so when UA wants to opena dialog it contacts registrar for the address of the callee

2. Back to back user agent on mobicents sip server

B2BUA acts as an endpoint for two other agents and forwards requests and responses between those two agents. Unlike proxy servers , B2nua server maintain state for dialogs and transactions.

3. proxy application using Mobicents sip servlets

A SIP proxy is an agent which stands in the path of two UA. The proxy is used only for the INVITE request and answer. The following ACK is then sent directly from one UA to another. The main purpose of the SIP proxy is to route the INVITE request between the UA’s.

4. Mobicents as sip load balancer

The Mobicents SIP load balancer acts as an entry-point for the cluster. Can handle both SIP and HTTP traffic. Distributes the SIP messages among the alive nodes ( use a attributable algorithm) after checking their heartbeat.

The load balancer appends itself to the Via header of each request. Thus, responses are sent to the SIP load balancer before they are sent to the originating SIP application

tbd : Attached are the screen shots of the same .

1. User agent client (UAC) Dialog
2. User agent server (UAS) Dialog
3. Mobicent slee management console
4. Joboss status console
5. Admin console depicting applications installed .

Freeswitch Integration with Telecom Carrier

This articles is a follow up of the earlier freeswitch capability introduction and some generic usecases around dialplans and contexts. This post contains instructions on how to integrate your SIP VOIP Freeswitch server to ITSP ( Internet Telephony Service Providers) which are basically part of large telecommunications companies.

First we check the external profile via sofia status . We should’ve configured the internal ip to listen to domain address or public ip. The external profile on port 5080 is used for outgoing and incoming connections .

Screen Shot 2018-09-28 at 9.32.31 AM

Create a user profile for interacting with outside world

<user id="1001">
<param name="password" value="pass1234"/>

Next we should try and register any sip softphone with the freeswitch server . I used Xlite , screenshot below

Screen Shot 2018-09-28 at 9.30.07 AM

Configuring a SIP gateway  in sip_profiles -> external

Goto /usr/src/freeswitch-debs/freeswitch/conf/vanilla/sip_profiles/external and create a profile such as telco_profile.xml

<gateway name="telcoCompany">
<param name="realm" value=""/>
<param name="username" value="admin"/>
<param name="password" value="123456"/>
<param name="register" value="true"/>

and add the bridge to dialplan under usage

<extension name="telco gateway bridge">
<condition field="destination_number" expression="^(\d{10})$">
<action application="bridge" data="sofia/gateway/telcoCompany/$1"/>

note $1 contains the dialled number which will be passed to bridge to telcoCompany gateway. Therefore to add prefix for USA use +1$1 or for India +91$1 (  E.164 format) or some inline variable such as ${customercode}$1

After adding reloadxml and also run sofia profile external rescan to let freeswitch find the gateways

Monitoring gateways using OPTIONS

<param name="ping" value="20"/>

Codec Negotiation 

Late negotiations reduces re-sampling and codec changes

<param name="inbound-late-negotiation" value="true"/>

Other dial plan variables can also be set such as absolute_codec_string, inherit_codec , ep_codec_string. To avoid any codec negotiation on SDP use bypass_media=true .

<param name="inbound-codec-prefs" value="${global_codec_prefs}"/>
<param name="outbound-codec-prefs" value="${outbound_codec_prefs}"/>
<param name="inbound-codec-negotiation" value="generous"/>

CDR ( Call Detail Records )

can be used with modules mod_xml_cdr , mod_csv_cdr , mod_cdr_mongodb, mod_odbc_cdr , mod_cdr_pg_csv , mod_cdr_sqlite , mod_json_cdr , mod_radius_cdr

<configuration name="cdr_csv.conf" description="CDR CSV Format">
<!-- 'cdr-csv' will always be appended to log-base -->
<!--<param name="log-base" value="/var/log"/>-->
<param name="default-template" value="example"/>
<!-- This is like the info app but after the call is hung up -->
<!--<param name="debug" value="true"/>-->
<param name="rotate-on-hup" value="true"/>
<!-- may be a b or ab -->
<param name="legs" value="a"/>
<!-- Only log in Master.csv -->
<!-- <param name="master-file-only" value="true"/> -->
<template name="sql">INSERT INTO cdr VALUES ("${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}");</template>

event socket library (ESL)


Freeswitch Modules

modules supported on freeswitch

This section describes some of the popular and useful freeswitch module . Although there are many more modules , I have picked a few of commonly used one and divided them into following categories :

  • Loggers
  • XML Interfaces
  • Event Handlers
  • Application
  • Language




mod_enum is a dialplan interface, an application interface and an api command interface

XML Interfaces


Event Handlers



log call detail records (CDRs) to a text file using text generation templates as in /conf/autoload_configs/cdr_csv.conf.xml

<configuration name="cdr_csv.conf" description="CDR CSV Format">
<param name="default-template" value="example"/>
<param name="rotate-on-hup" value="true"/>
<!-- may be a b or ab -->
<param name="legs" value="a"/>
<template name="sql">INSERT INTO cdr VALUES ("${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}");</template>


Directory Interfaces


When any of the endpoints are loaded , they start listening for connection using configuration file . Dialstring identifies the recipient of the channel such as sofia/external/098099999 where sofia is the dial string prefix for SIP.

mod_sofia – SIP protocol support

mod_gsmopen –  Supports voice & SMS over a GSM network

mod_h323 – H.323 , ITU rich media communication protocol.

mod_opal – IAX2

mod_skypopen – Skype (discontinued )

mod_dingaling – Jingle , Google Talk, XMPP integration ( discontinued )





mod_freetdm – Provides support for telephony cards from manufacturers such as Digium, Sangoma and Zaptel. Can communicate in most legacy telephony protocols such as ISDN, SS7 & analog





RTMP protocol is primarily used by Flash for streaming audio, video, and data over the Internet.




inbound and outbound conference bridge, loaded from file  conf/autoload_configs/conference.conf.xml




Dialplan tools provide the apps (commands) to process call sessions in XML dialplans.


Answer the call for a channel.

<!-- a sample IVR( Interactive Voice Response ) -->
<extension name="ivr">
<condition field="destination_number" expression="^9000$">
    <action application="answer"/>
    <action application="sleep" data="1000"/>
    <action application="ivr" data="demo_ivr"/>


Attended Transfer.


Execute an operating system command in the background.

bind_digit_action – Bind a key sequence or regex to an action.


Respond to certain DTMF sequences on specified call leg(s) during a bridge and execute another dialplan application.


Block DTMFs from being sent or received on the channel.


Cancel an application currently running on the channel.


Bridge a new channel to the existing one.


Export a channel variable across any bridge.


Capture data into a channel variable.


Send a text message to an IM client


Block originating address unless it matches an ACL.Test the i.p. address that originates the call against an Access Control List or CIDR mask

  • clear_digit_action – Clear all digit bindings
  • clear_speech_cache – Clear speech handle cache.
  • cluechoo – Console-only “ConCon” choo-choo train
  • cng_plc – Packet Loss Concealment on lost packets + comfort noise generation
  • conference – Establish an inbound or outbound conference call
  • db – insert information into the database.
  • deflect – Send a call deflect/refer.
  • delay_echo – Echo audio at a specified delay.
  • detect_speech – Implements speech recognition.
  • digit_action_set_realm – Change binding realm.
  • displace_session – Displace audio on a channel.
  • early_hangup – Enable early hangup on a channel.


Spy on a channel.

<extension name="eavesdrop">
<condition field="destination_number" expression="^88(\d{4})$|^\*0(.*)$">
    <action application="answer"/>
    <action application="eavesdrop" data="${hash(select/${domain_name}-spymap/$1$2)}"/>


Echo audio and video back to the originator.


Enable Media Heartbeat.


Continuously play file to caller.

enum – Perform E.164 lookup.
erlang – Handle a call using Erlang.
eval – Evaluates a string.
event – Fire an event.


Execute an extension from within another extension and return.


Export a channel variable across a bridge <varname>=<value>

fax_detect – Detect FAX CNG – may be deprecated.
fifo – Send caller to a FIFO queue.
fifo_track_call – Count a call as a FIFO call in the manual_calls queue.
flush_dtmf – Flush any queued DTMF.
gentones – Generate TGML tones.
group – Insert or delete members in a group.


Hang up the current channel.

<extension name="show_info">
<condition field="destination_number" expression="^9192$">
<action application="answer"/>
<action application="info"/>
<action application="sleep" data="250"/>
<action application="hangup"/>

hash – Add a hash to the db.
hold – Send a hold message.


Send call control to a Web server with the HTTAPI infrastructure

info – Display Call Info.
intercept – Lets you pickup a call and take it over if you know the uuid.


Run an IVR menu.

javascript – Run a JavaScript script from the dialplan
jitterbuffer – Send a jitter buffer message to a session
limit – Set a limit on number of calls to/from a resource
limit_execute – Set the limit on a specific application
limit_hash – Set a limit on number of calls to/from a resource
limit_hash_execute – Set the limit on a specific application
log – Logs a channel variable for the channel calling the application
loop_playback – Playback a file to the channel looply for limted times
lua – Run a Lua script from the dialplan
media_reset – Reset all bypass/proxy media flags.
mkdir – Create a directory.
multiset – Set multiple channel variables with a single action.
mutex – Block on a call flow, allowing only one at a time
page – Play an audio file as a page.
park – Park a call.
park_state – Park State.
phrase – Say a Phrase.
pickup – Pickup a call.
play_and_detect_speech – Play while doing speech recognition.
play_and_get_digits – Play and get Digits.
play_fsv – Play an FSV file. FSV – (FS Video File Format) additional description needed
playback – Play a sound file to the originator.
pre_answer – Answer a channel in early media mode.[old wiki]
preprocess – description needed
presence – Send Presence
privacy – Set caller privacy on calls.
queue_dtmf – Send DTMF digits after a successful bridge.
read – Read Digits.
record – Record a file from the channel’s input.
record_fsv – Record a FSV file. FSV – (FS Video File Format) additional description needed
record_session – Record Session.
recovery_refresh – Send a recovery refresh.
redirect – Send a redirect message to a session.
regex – Perform a regex.
remove_bugs – Remove media bugs.
rename – Rename file.
respond – Send a respond message to a session.
ring_ready – Indicate Ring_Ready on a channel.
rxfax – Receive a fax as a tif file.


Say time/date/ip_address/digits/etc. With pre-recorded prompts.
sched_broadcast – Enable Scheduled Broadcast.
sched_cancel – Cancel a scheduled future broadcast/transfer.
sched_hangup – Enable Scheduled Hangup.
sched_heartbeat – Enable Scheduled Heartbeat.
sched_transfer – Enable Scheduled Transfer.
send_display – Sends an info packet with a sipfrag.
send_dtmf – Send inband DTMF, 2833, or SIP Info digits from a session.
send_info – Send info to the endpoint.
session_loglevel – Override the system’s loglevel for this channel.
set – Set a channel variable for the channel calling the application.
set_audio_level – Adjust the read or write audio levels for a channel.
set_global – Set a global variable.
set_name – Name the channel.
set_profile_var – Set a caller profile variable.
set_user – Set a user.
set_zombie_exec – Sets the zombie execution flag on the current channel.
sleep – Pause a channel.
socket – Establish an outbound socket connection.
sound_test – Analyze Audio.
speak – Speaks a string or file of text to the channel using the defined TTS engine.[old wiki]
soft_hold – Put a bridged channel on hold.
start_dtmf – Start inband DTMF detection.
stop_dtmf – Stop inband DTMF detection.
start_dtmf_generate – Start inband DTMF generation.
stop_displace_session – Stop displacement audio on a channel.
stop_dtmf_generate – Stop inband DTMF generation.
stop_record_session – Stop Record Session.
stop_tone_detect – Stop detecting tones.
strftime – Returns formatted date and time.
system – Execute an operating system command.
three_way – Three way call with a UUID.
tone_detect – Detect the presence of a tone and execute a command if found.
transfer – Immediately transfer the calling channel to a new extension.[old wiki]
translate – Number translation.
unbind_meta_app – Unbind a key from an application.
unset – Unset a variable.
unhold – Send a un-hold message.
verbose_events – Make ALL Events verbose (Make all variables appear in every single event for this channel).
wait_for_silence – Pause processing while waiting for silence on the channel.
wait_for_answer – Pause processing while waiting for the call to be answered.


chat – Send a text message to a IM client.
presence – Send Presence.
strepoch – Returns the date/time as a UNIX epoch (seconds elapsed since midnight UTC, January 1, 1970).
strftime – Returns formatted date and time.
strftime_tz – Returns formatted date and time in the timezone specified.

SNOM Module

This one only works on Linux for now

Dialplan Interfaces

Codec Interfaces

File Format Interfaces
For icecast/mp3 streams/files
For local streams (play all the files in a directory)



These scripting languages allow programming the call routing logic


FreeSWITCH has support for the Google V8 JavaScript (ECMAScript) engine. It needs to be uncommented in the modules.conf file

Screen Shot 2018-09-27 at 6.34.04 PM









Third party modules

FreeSwitch SIP and Media Server

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 is designed to route and interconnect popular 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 a number of 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 which 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 . SIP being the most popular protocol for 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)


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 .


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"/>

Inline actions are executed during the hunting phase of 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@ , will dial out 8765 at host using profile2
  • sofia/gateway/ , will dial through a Gateway (SIP Provider) to user 5432
  • sofia/profile2/8765@;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 .

<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"/>

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"/>

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}"/>

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 wday="2-6" time-of-day="1:30-2:30" break="never">
<action application="set" data="office_status=lunch" inline="true"/>

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@"/>

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 field="network_addr" expression="^192\.168\.1\.1$">
    <action application="bridge" data="sofia/customprofile/${dialed_number}@"/>


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"/>

<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"/>

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"/>

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"/>

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"/>
    <action application="playback" data="misc/connected_securly.wav"/>

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"/>

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"/>

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"/>

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"/>

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)

<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"/>

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 "
    <entry action="menu-exec-app" digits="1" param="bridge sofia/${domain}/"/>
    <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"/> 

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

<menu name="demo_ivr_submenu"
    <entry action="menu-top" digits="*"/>
    <entry action="menu-exit" digits="#"/>

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/, 
[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"/>


Ring Multiple Targets

<action application="bridge" 
user/7010@${domain}, user/7022@${domain}, user/7007@${domain}, 

Handle Failures and Early Media

<action application="bridge" 
data="{ ignore_early_media=true, 
destination_out_of_order:2:1776.7 }

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 .


A simple directory listing containing two groups with 2 users each

<domain name="${domain}">
<param name="dial-string" value="{^^:sip_invite_domain=${dialed_domain}:

<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"/>

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

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

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


1001 user’s xml

<user id="1001">
<param name="password" value="${default_password}"/>
    <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"/>

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

root@ip-172-31-27-106:/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


Quick Installation on MacOS

Download and run the dmg , screenshots attached .

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 - | apt-key add -
echo "deb jessie main" > /etc/apt/sources.list.d/freeswitch.list
echo "deb-src jessie main" >> /etc/apt/sources.list.d/freeswitch.list
apt-get update

apt-get build-dep freeswitch

cd /usr/src/

git clone -bv1.8 freeswitch

cd freeswitch

git config pull.rebase true

Enter freeswitch directory and Build

./ -j
make install

for errors such as “The repository ‘ 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


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/ 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
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

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

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
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
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



  • ACL
  • Fail2Ban
  • IPtables

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@ 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@ &echo()
switch_ivr_originate.c:2159 Parsing global variables
switch_channel.c:1104 New Channel sofia/internal/1002@ [5188806e-cabd-4acc-b20b-00620c3362ec]
mod_sofia.c:5026 (sofia/internal/1002@ State Change CS_NEW -> CS_INIT
switch_core_state_machine.c:584 (sofia/internal/1002@ Running State Change CS_INIT (Cur 5 Tot 122559)
switch_core_state_machine.c:627 (sofia/internal/1002@ State INIT
mod_sofia.c:93 sofia/internal/1002@ SOFIA INIT
sofia_glue.c:1299 sofia/internal/1002@ sending invite version: 1.9.0 -654-ed4920e 64bit
Local SDP:
o=FreeSWITCH 1538689496 1538689497 IN IP4
c=IN IP4
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
m=video 19042 RTP/AVP 102
a=rtpmap:102 VP8/90000
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@ Standard INIT
switch_core_state_machine.c:48 (sofia/internal/1002@ State Change CS_INIT -> CS_ROUTING
switch_core_state_machine.c:627 (sofia/internal/1002@ State INIT going to sleep
switch_core_state_machine.c:584 (sofia/internal/1002@ Running State Change CS_ROUTING (Cur 4 Tot 122612)
sofia.c:7291 Channel sofia/internal/1002@ entering state [calling][0]
sofia.c:7291 Channel sofia/internal/1002@ entering state [terminated][503]

Ref :

My freeswitch contributor profile

Freeswitch Wiki

Freeswitch bitbucket Codebase