Hello Experts,
I'm not an expert in Kamailio, but thanks to some excellent online resources, I
managed to set up a basic interconnection between Teams and Kamailio.
So far, outbound calls, as well as blind and attended call transfers, are working
smoothly. However, I'm facing a challenge with call disconnection for outbound calls.
Specifically, when an outbound call is made and the called party hangs up, the BYE message
isn't being relayed properly towards the Teams side.
In my routing configurations, I remove the Record-Route header received from Teams and add
a new Record-Route header with Kamailio's IP before forwarding it to my IP PBX
(FreeSwitch). For the BYE message to be processed correctly, Microsoft Teams requires the
original contact in the Request URI (RURI) and the Route header to match the initial
Record-Route included in the INVITE. Currently, my BYE message appears as follows:
BYE
sip:api-du-a-auea.pstnhub.microsoft.com:443;x-i=5e96d703-b1e7-449c-aebf-a87bfa628176;x-c=f61b674bc597513ab8d888dbe7c560fb/d/8/9a6c508a9cbd44ebb892b62c33ba9b67
SIP/2.0
Via: SIP/2.0/UDP x.x.x.x:5060;branch=z9hG4bKeab5.b657e3455b6d11ed6975c69882632a27.0
Via: SIP/2.0/UDP x.x.x.x;received=x.x.x.x;rport=5060;branch=z9hG4bKK3HKQBUvX42ya
Max-Forwards: 69
From: <sip:+61403225xxx@kamsbc.xyzdomain.com:5061;user=phone>;tag=j5gptBSXXrXDc
To: "XYZ Pty Ltd"
<sip:+61291455xxx@sip.pstnhub.microsoft.com:5061;user=phone>;tag=3a5f0c9e32bc4eb1bffed29dc954118f
Call-ID: f61b674bc597513ab8d888dbe7c560fb
CSeq: 80555743 BYE
User-Agent: Unknown/v1.0
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Reason: MVTSLocal;cause=10;text="BYE received"
Content-Length: 0
Kamailio conducts a lookup for
api-du-a-auea.pstnhub.microsoft.com but ends up sending the
BYE message to an incorrect IP.
Below is a snippet of my routing block configurations:
####### Routing Logic ########
/* Main SIP request routing logic
* - processing of any incoming SIP request starts with this route
* - note: this is the same as route { ... } */
request_route {
# per request initial checks
route(REQINIT);
#check who is the sender
route(INITCHECK);
# 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();
}
# handle requests within SIP dialogs
route(WITHINDLG);
### only initial requests (no To tag)
# record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
remove_hf("Route");
if (is_method("INVITE|SUBSCRIBE")) {
record_route();
}
# 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");
exit;
}
# update $du to set the destination address for proxying
#$du = "sip:" + $rd + ":9";
route(RELAY);
exit;
}
route[INITCHECK] {
if(from_uri =~ ".*microsoft.com")
{
setflag(FROM_TEAMS);
$du = "sip:" + "MY_PBX_IP" + ":" +
"5060";
//added by SHK
remove_hf("Record-Route"); // Remove existing Record-Route
header
append_hf("Record-Route:
<sip:KAM_IP:5060;transport=udp>\r\n");
route(HANDLE_RTP_FROM_TEAMS);
}
if(from_uri =~ ".*" + "MY_PBX_IP")
{
setflag(FROM_PBX);
$du="sip:sip.pstnhub.microsoft.com;transport=tls";
route(HANDLE_RTP_FROM_PBX);
}
}
#Manage RTP & transcoding comming from Teams to PBX
route[HANDLE_RTP_FROM_TEAMS] {
t_on_reply("PBX_REPLY_TO_TEAMS");
if (has_body("application/sdp"))
{
rtpengine_manage("RTP codec-mask=all codec-transcode=PCMA
replace-origin replace-session-connection ICE=remove media-address=HOST_IP");
// record_route();
t_relay_to_udp("MY_PBX_IP","5060");
}
else
{
rtpengine_manage();
}
}
#Manage RTP & transcoding comming from PBX to Teams
route[HANDLE_RTP_FROM_PBX] {
t_on_reply("TEAMS_REPLY_TO_PBX");
if (has_body("application/sdp"))
{
rtpengine_manage("SRTP codec-mask=all ICE=force codec-transcode=PCMA
replace-origin replace-session-connection media-address=ADVERTISE_IP");
$rd = "sip.pstnhub.microsoft.com";
$td = "kamsbc.xyzdomain.com";
$fd = "kamsbc.xyzdomain.com";
// record_route();
#Set TLS SNI (server name & server id)
$xavp(tls=>server_name) = "kamsbc.xyzdomain.com";
$xavp(tls=>server_id) = "kamsbc.xyzdomain.com";
t_relay();
}
else
{
rtpengine_manage();
}
}
# Wrapper for relaying requests
route[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"))
t_on_branch("MANAGE_BRANCH");
}
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("onreply_route"))
t_on_reply("MANAGE_REPLY");
}
if (is_method("INVITE")) {
if(!t_is_set("failure_route"))
t_on_failure("MANAGE_FAILURE");
}
if (!t_relay()) {
sl_reply_error();
}
exit;
}
# Per SIP request initial checks
route[REQINIT] {
if($ua =~ "friendly-scanner|sipcli|VaxSIPUserAgent") {
# silent drop for scanners - uncomment next line if want to reply
# sl_send_reply("200", "OK");
exit;
}
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if(is_method("OPTIONS")) {
sl_send_reply("200","Keepalive");
exit;
}
if(!sanity_check("1511", "7")) {
xlog("Malformed SIP message from $si:$sp\n");
exit;
}
}
# Handle requests within SIP dialogs
route[WITHINDLG] {
if (!has_totag()) return;
#Teams reINVITEs
if(isflagset(FROM_TEAMS)) {
loose_route();
t_relay();
exit;
}
if(isflagset(FROM_PBX)) {
#Set TLS SNI (server name & server id)
$xavp(tls=>server_name) = "kamsbc.xyzdomain.com";
$xavp(tls=>server_id) = "kamsbc.xyzdomain.com";
loose_route();
t_relay();
exit;
}
# sequential request withing a dialog should
# take the path determined by record-routing
if (loose_route()) {
if (is_method("BYE")) {
setflag(FLT_ACC); # do accounting ...
setflag(FLT_ACCFAILED); # ... even if the transaction fails
#set coresponding cert on transactions
if($fd == "kamsbc.xyzdomain.com") {
$xavp(tls=>server_name) =
"kamsbc.xyzdomain.com";
$xavp(tls=>server_id) =
"kamsbc.xyzdomain.com";
}
} else if ( is_method("NOTIFY") ) {
# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
record_route();
}
route(RELAY);
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 ... ignore and discard
exit;
}
}
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");
}
#PBX On Reply
onreply_route[PBX_REPLY_TO_TEAMS]
{
if (has_body("application/sdp"))
{
rtpengine_manage("SRTP codec-mask=all codec-transcode=PCMA
replace-origin replace-session-connection media-address=ADVERTISE_IP");
}
else
{
rtpengine_manage();
}
//added by SHK
if (status == "200" && method == "INVITE") {
remove_hf("Contact"); # Remove existing Contact header
append_hf("Contact:
<sip:kamsbc.xyzdomain.com:5061;transport=tls>\r\n");
}
if (status=="200")
{
remove_hf("ALLOW:");
append_hf("ALLOW: INVITE,ACK,OPTIONS,CANCEL,BYE,NOTIFY
\r\n","CONTENT-TYPE");
}
}
#From Teams On Reply
onreply_route[TEAMS_REPLY_TO_PBX]
{
if (has_body("application/sdp"))
{
rtpengine_manage("RTP codec-mask=all codec-transcode=PCMA
replace-origin replace-session-connection media-address=HOST_IP");
}
else
{
rtpengine_manage();
}
}
# Manage failure routing cases
failure_route[MANAGE_FAILURE] {
if (t_is_canceled()) exit;
}
event_route[tm:local-request] {
if(is_method("OPTIONS") && $ru =~
"pstnhub.microsoft.com") {
append_hf("Contact:
<sip:kamsbc.xyzdomain.com:SBC_PORT;transport=tls>\r\n");
}
xlog("L_INFO", "Sent out tm request: $mb\n");
}
####### Routing Logic End ########
Given these details, I suspect the issue might be related to how I'm handling the
Record-Route headers or potentially a misconfiguration in directing the BYE message. I
would greatly appreciate any insights, suggestions, or guidance on how to correctly relay
the BYE message back to Teams, or further refine my existing configuration.
Thank you in advance for your help and support!
Regards,
Shah Hussain