Hi all,

I've the following infrastructure

62.128.128.68 (Telco SBC Inbound)
      |
      | 
10.19.139.66 (Kamailio + RTPEngine)
      | 
      |
10.19.139.69 (Asterisk 13)
      | 
      |
62.128.128.68 (Telco SBC Outbound)

 
Test scenario is:
- a mobile calls a destination; the call comes in from Telco SBC Inbound, goes through Kamailio+RTPengine and then to Asterisk which redirects the call to Telco SBC Outbound.
- Asterisk box is set with canreinvite=no and nat=force_rport,comedia so it stays in the path

when a call comes in SBC Inbound, it is correctly redireted to SBC Outbound. The call is answered, and after 5 or so seconds, SBC Inbound sends a new INVITE to force codecs, which Asterisk replies correctly.
the problem is that between Kamailio and SBC Inbund, when Asterisk replies to the second invite, the media port changes, resulting in audio loss: during the call, audio from destination to originator works OK but originator to destination is mute.

According to the telco's guys,this is due to the fact that Kamailio is changing during call the media port from original media port to a new one, on reply to the second Invite, and this is wrong and reason why sound from the originator to destination is lost (but not from destination to originator)

I'm lost too here.....

Any clue? Can anyone help? Resuming I need to make sure that, if during a call some INVITES are sent from SBC to Asterisk, that the reply keeps the same IP_ADDR:port from beginning to the end of the call. As it is today, the second invite changes te RTP Media port and no audi is heard....

If needed I can send PCap files.

please find below my kamailio.cfg file

#!define WITH_NAT
#!define WITH_PSTN
/* enables Accounting Log functions */
#!define FLT_ACC 1
/* enable Accounting of missed or failed calls */
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3

/* sets the dispatcher list file path */
#!define DS_LIST "/etc/kamailio/dispatcher.list"

/* sets the RTP Engine address and port; RTP Engine is a NAT enabled RTP Proxy */
#!define RTP_ENGINE_ADDR "udp:127.0.0.1:60000
// was udp:localhost:60000

/* defines DB connection string */
#!ifndef DBURL
#!define DBURL "mysql://kamailio:kamailiorw@10.19.139.110/kamailio"
#!endif

# - the value for 'use_domain' parameters
#!define MULTIDOMAIN 1

####### Global Parameters #########

#!ifdef WITH_DEBUG
debug=4
log_stderror=yes
#!else
debug=2
log_stderror=no
#!endif

#!define FLT_DISPATCH_SETID 1
#!define FLT_FS 10
#!define FLT_NATS 5
#!define FLB_NATB 6
#!define FLB_NATSIPPING 7

memdbg=5
memlog=5

log_facility=LOG_LOCAL0

fork=yes
children=4

/* comment the next line to enable TCP */
disable_tcp=no

/* uncomment the next line to disable the auto discovery of local aliases
   based on revers DNS on IPs (default on) */
auto_aliases=no

/* add local domain aliases */
# alias="mysipserver.com"

port=5060

/* uncomment and configure the following line if you want Kamailio to 
   bind on a specific interface/port/proto (default bind on all available) */
//listen=udp:10.19.139.66:5060
listen=udp:eth1:5060

sip_warning=no;
####### Modules Section ########

#set module path
mpath="/usr/lib64/kamailio/modules/"

loadmodule "db_mysql.so"
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
/**************/
loadmodule "usrloc.so"
/**************/
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "acc.so"
loadmodule "path.so"
loadmodule "dispatcher.so"
loadmodule "rtpengine.so"
loadmodule "nathelper.so"
loadmodule "rtimer.so"
loadmodule "sqlops.so"
# ----------------- setting module-specific parameters ---------------
# ----- jsonrpcs params -----
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
modparam("jsonrpcs", "pretty_format", 1)


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


# ----- acc params -----
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_extra","src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si")

# ----- 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 we 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","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
/* enhanced DB accounting */
modparam("acc", "db_flag", FLT_ACC)
modparam("acc", "db_missed_flag", FLT_ACCMISSED)
modparam("acc", "db_url", DBURL)
modparam("acc", "db_extra","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd") //;calltype=$avp(calltype)")

# ----- usrloc params -----
/* enable DB persistency for location entries */
modparam("usrloc", "db_url", DBURL)
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "use_domain", MULTIDOMAIN)

# ----- tm params -----
# ----- the TM module enables stateful processing of SIP requests
modparam("tm", "fr_timer", 2000)
modparam("tm", "fr_inv_timer", 40000)

# ----- dispatcher params -----
modparam("dispatcher", "list_file", DS_LIST)
modparam("dispatcher", "flags", 2)
modparam("dispatcher", "dst_avp", "$avp(AVP_DST)")
modparam("dispatcher", "grp_avp", "$avp(AVP_GRP)")
modparam("dispatcher", "cnt_avp", "$avp(AVP_CNT)")
modparam("dispatcher", "sock_avp", "$avp(AVP_SOCK)")
modparam("dispatcher", "ds_hash_size", 9)
modparam("dispatcher", "dstid_avp", "$avp(dsdstid)")
modparam("path", "use_received", 1)

# ----- rtpproxy params -----
modparam("rtpengine", "rtpengine_sock", RTP_ENGINE_ADDR)
modparam("nathelper", "received_avp", "$avp(s:rcv)")

/************************/
# ----- nathelper params -----
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
modparam("nathelper", "sipping_from", "sip:ping@kamailio.org")

# params needed for NAT traversal in other modules
modparam("usrloc", "nat_bflag", FLB_NATB)
/***********************/

modparam("rtimer", "timer", "name=cdr;interval=300;mode=1;")
modparam("rtimer", "exec", "timer=cdr;route=CDRS")
modparam("sqlops", "sqlcon", "ca=>mysql://kamailio:**********@*************/kamailio")



####### Routing Logic ########


# main request routing logic

route {
xlog("L_INFO","$rm from $si");
xlog("L_DBG","[$fU@$si:$sp]{$rm} {$ru} ");


# OPTIONS requests without a username in the Request-URI but one
# of our domains or IPs are addressed to the proxy itself and
# can be answered statelessly.
if (is_method("OPTIONS")) // && $fU=="ping" )// && $si=="62.28.173.10" && $fU=="ping")// && strempty(@ruri.user) && (uri == myself))
{
sl_send_reply("200","OK");
exit;
}

# per request initial checks
route(REQINIT);
rtpengine_manage();
# NAT detection
route(NATDETECT);
# handle requests within SIP dialogs
### only initial requests (no To tag)
# CANCEL processing
if (is_method("CANCEL"))
{
if (t_check_trans()){
route(RELAY);
}
exit;
}
# handle retransmissions
if (!is_method("ACK")) {
if(t_precheck_trans()) {
t_check_trans();
exit;
}
t_check_trans();
}
route(WITHINDLG);

# record routing for dialog forming requests (in case they are routed)
                # - remove preloaded route headers
                xlog("L_INFO","Removing Headers");
                remove_hf("Route");
                if (is_method("INVITE|SUBSCRIBE")){
                        xlog("L_INFO","Recording Route");
                        record_route();

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

if (is_method("ACK") && has_body("application/sdp"))
        rtpengine_answer();

# account only INVITEs
                if (is_method("INVITE"))
                {
                        setflag(FLT_ACC); # do accounting
                }


//route(SIPOUT);


xlog("L_INFO","Setting PRESENCE");
# handle presence related requests
route(PRESENCE);

# handle registrations
xlog("L_INFO","Handling REGISTRAR");
route(REGISTRAR);

if ($rU==$null)
{
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}



# dispatch destinations to PSTN
//route(PSTN);

# dispatch destinations
route(DISPATCH);

xlog("L_INFO","**********END*************");
}

onreply_route[1]
{
    if (has_body("application/sdp"))
        rtpengine_answer();
}

onreply_route[2]
{
    if (has_body("application/sdp"))
        rtpengine_offer();
}

# Per SIP request initial checks
route[REQINIT] {
xlog("L_INFO","REQINIT Starting");
        if (!mf_process_maxfwd_header("10")) {
xlog("L_INFO","483 - Too Many Hops");
                sl_send_reply("483","Too Many Hops");
                exit;
        }

        if(!sanity_check("1511", "7"))
        {
                xlog("Sanity Check -> Malformed SIP message from $si:$sp\n");
                exit;
        }
xlog("L_INFO","REQINIT Finishing");
}

/***********************/
        # Caller NAT detection
        route[NATDETECT] {
xlog("L_INFO","Entering NATDTECT");
        #!ifdef WITH_NAT
                force_rport();
                if (nat_uac_test("19")) {
                        if (is_method("REGISTER")) {
xlog("L_INFO","Fix Nated Register");
                                fix_nated_register();
                        } else {
                              if(is_first_hop())
      {
  xlog("L_INFO","Set Contact Alias");
                                        set_contact_alias();
      }
                        }
xlog("L_INFO","Set FLT_NATS" + FLT_NATS);
                        setflag(FLT_NATS);
                }
        #!endif
xlog("L_INFO","NAT Detect set FLT_NTS = " + FLT_NATS);
xlog("L_INFO","Finishing NATDETECT");
           return;
        }
/***********************/


# Handle requests within SIP dialogs
route[WITHINDLG] {
xlog("L_INFO","Entering WITHDLG");
        if (!has_totag()) return;

        # sequential request withing a dialog should
        # take the path determined by record-routing
        if (loose_route()) {
                route(DLGURI);
                if (is_method("BYE")) {
                        setflag(FLT_ACC); # do accounting ...
                        setflag(FLT_ACCFAILED); # ... even if the transaction fails
                }
                else if ( is_method("ACK") ) {
                        # ACK is forwarded statelessy
xlog("L_INFO","Going to NATMANAGE");
                        route(NATMANAGE);
                }
                else if ( is_method("NOTIFY") ) {
                        # Add Record-Route for in-dialog NOTIFY as per RFC 6665.
                        record_route();
                }
                route(RELAY);
                exit;
        }

        if (is_method("SUBSCRIBE") && uri == myself) {
                # in-dialog subscribe requests
                route(PRESENCE);
                exit;
        }
        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
                        route(RELAY);
                        exit;
                } else {
                        # ACK without matching transaction.  Try to route anyway - being optimistic
                        # since it has at least a To Tag
                        route(RELAY);
                        exit;
                }
        }
        sl_send_reply("404","Not here");
xlog("L_INFO","Finishing WITHINDLG");
        exit;
}

# Routing to foreign domains
route[SIPOUT] {
xlog("L_INFO","Entering SIPOUT");
if (uri==myself) 
{
xlog("L_INFO","URI is MySelf!");
return;
}

append_hf("P-hint: outbound\r\n");
xlog("L_INFO","Finishing SIPOUT");
route(RELAY);
exit;
}


# Wrapper for relaying requests
route[RELAY] {
xlog("L_INFO","******** RELAY *******");

# enable additional event routes for forwarded requests
# - serial forking, RTP relaying handling, a.s.o.
if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) {
xlog("L_INFO","branch_route NOT SET!");
t_on_branch("MANAGE_BRANCH");
}
}
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("onreply_route")) {
xlog("L_INFO","onreply_route NOT SET!");
t_on_reply("MANAGE_REPLY");
}
}
if (is_method("INVITE")) {
if(!t_is_set("failure_route")) {
xlog("L_INFO","failure_route NOT SET!");
t_on_failure("MANAGE_FAILURE");
}
}

if (!t_relay()) {
xlog("L_INFO","t_relay returns FALSE");
sl_reply_error();
}
exit;
}

# URI update for dialog requests
route[DLGURI] {
xlog("L_INFO","Entering DLGURI");
#!ifdef WITH_NAT
if(!isdsturiset()) {
xlog("L_INFO","Handle ruri ALIAS");
handle_ruri_alias();
}
#!endif
return;
}





# RTPProxy control and singaling updates for NAT traversal
route[NATMANAGE] {
xlog("L_INFO","Entering NATMANAGE");
#!ifdef WITH_NAT
if (is_request()) {
if(has_totag()) {
if(check_route_param("nat=yes")) {
xlog("L_INFO","nat=yes --- Setting FLB_NATB");
setbflag(FLB_NATB);
}
}
}
if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB) ))
{
xlog("L_INFO","NO FLT_NATS/B Set!!! Getting out of NATMANAGE");
return;
}
xlog("L_INFO","Starting RTPEngine");
rtpengine_manage();

if (is_request()) {
if (!has_totag()) {
if(t_is_branch_route()) {
xlog("L_INFO","adding nat=yes");
add_rr_param(";nat=yes");
}
}
}
if (is_reply()) {
if(isbflagset(FLB_NATB)) {
if(is_first_hop())
{
xlog("L_INFO","Set Contact Alias");
set_contact_alias();
}
}
}
  #!endif
return;
}




# Handle SIP registrations
route[REGISTRAR] {
if(!is_method("REGISTER"))
return;
add_path_received();
        route(DISPATCH);
}

# Presence server route
route[PRESENCE] {
if(!is_method("PUBLISH|SUBSCRIBE"))
return;

sl_send_reply("404", "Not here");
exit;
}

# PSTN GW routing
route[PSTN] {
#!ifdef WITH_PSTN
xlog("L_INFO","Entering PSTN");
# route to PSTN dialed numbers starting with '+' or '0000'
#     (international format)
# - update the condition to match your dialing rules for PSTN routing

if(!($rU=~"^(\+|00)[1-9][0-9]{3,20}$"))
{
xlog("L_INFO","$rU is not outbound call to PSTN");
return;
}
if (!starts_with("$si","10.19.139"))
{
xlog("L_INFO","$rU is not comming from any Media GW");
return;
}

# only local users allowed to call
         if(from_uri!=myself && !ds_is_from_list("1") ) 
{
          xlog("L_INFO", "from_uri $fu != myself, so this is Not Allowed!!");
         sl_send_reply("403", "Not Allowed");
        exit;
         }

xlog("L_INFO","$si request");
xlog("L_INFO","$rU is an outbound call to PSTN");
$ru = "sip:" + $rU + "@62.28.173.10"; // + $sel(cfg_get.pstn.gw_ip);
route(RELAY);
/*
if(!ds_select_dst("20", "4"))
         {
      xlog("L_INFO","no destination selected from dispatcher list!");
              send_reply("404", "No destination");
              exit;
         }
         xlog("L_DBG", "--- SCRIPT: going to <$ru> via <$du>\n");
         t_on_failure("RTF_DISPATCH");
         route(RELAY);
*/
exit;
#!endif

xlog("L_INFO"," NO PSTN SET!!");
    return;
}
# Dispatch requests
route[DISPATCH] {
xlog("L_INFO","Entering DISPATCH");
# hash over callerid dispatching on gateways group '1'
if(!ds_select_dst("1", "10","4"))
{
xlog("L_INFO","no destination selected from dispatcher list!");
send_reply("404", "No destination");
exit;
}
xlog("L_INFO","going to <$ru> via <$du>\n");

t_on_failure("RTF_DISPATCH");
route(RELAY);
exit;
}

# Dispatch requests
route[DISPATCH_TO_PSTN] {
        # round robin dispatching on gateways group '20' - PSTN
        if(!ds_select_dst("20", "10"))
        {
                send_reply("404", "No destination");
                exit;
        }
        xlog("L_DBG", "--- SCRIPT: going to <$ru> via <$du>\n");
        t_on_failure("RTF_DISPATCH");
        route(RELAY);
        exit;
}


# Sample failure route
failure_route[RTF_DISPATCH] {
if (t_is_canceled()) {
exit;
}
xlog("L_INFO", "Media server $du failed to answer, selecting other one!");
# next DST - only for 500 or local timeout
if ( t_check_status("500") || (t_branch_timeout() && !t_branch_replied()) )
{
#we mark the destination Inactive and Probing
                ds_mark_dst("ip");
if(ds_next_dst())
{
t_on_failure("RTF_DISPATCH");
route(RELAY);
exit;
}
}
}

route[CDRS]{
sql_query("ca","call kamailio_cdrs();","rb");
sql_query("ca","call kamailio_rating('default');","rb");
}


Cheers,

Sérgio