Hi All,
I am using Kamailio with rtpengine and have a parallel forking scenario (single INVITE -> multiple branches via append_branch()). Incoming INVITE has SDP with video Goal: - For Main branch : keep audio + video - For Forked branch: strip video (audio only)
Problem: SDP manipulation seems to be applied globally to the message, not per branch.
What I tried: 1. Using textops: sdp_remove_media("video"); msg_apply_changes(); 2. Trying to do it per branch: I attempted to move this logic into branch_route, but msg_apply_changes() is not allowed there, so SDP changes are not applied. Documentation stated that it can be used from from REQUEST_ROUTE or REPLY_ROUTE.
3. Using rtpengine: According to rtpengine NG protocol, "offer" supports: "sdp-media-remove": ["video"] However, I cannot find a way to pass this parameter via Kamailio's rtpengine module. Tried to add flag sdp-media-remove=video to the rtpengine_manage() but it doesn't work.
Environment: - Kamailio version: 6.0.6 - rtpengine version: 13.5.1.6
Question: What is the correct way to modify SDP per branch in a parallel forking scenario in Kamailio? My test routing config: ``` request_route {
if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; }
if (!is_method("ACK")) { if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); }
# remove unused codecs and media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # }
if (is_method("INVITE") && !has_totag()) { dlg_manage(); }
remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) { record_route(); }
if ($rU==$null) { sl_send_reply("484","Address Incomplete"); exit; }
route(LOCATION);
return; }
route[RELAY] {
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; }
route[LOCATION] {
route(ADD_FORK); route(RELAY); }
route[ADD_FORK] { $avp(extNum) = "abcd@192.168.106.34"; append_branch("sip:" + $(avp(extNum))); }
branch_route[MANAGE_BRANCH] {
route(NATMANAGE); }
onreply_route[MANAGE_REPLY] { # remove video media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # }
if(status=~"[12][0-9][0-9]") { route(NATMANAGE); } }
failure_route[MANAGE_FAILURE] { route(NATMANAGE);
if (t_is_canceled()) exit;
}
route[NATMANAGE] {
if (is_request()) { if (has_body("application/sdp")) { xlog("L_INFO","Negotiate RTP offer for branch $T_branch_idx\n"); if ($ru =~ "^sip:1[0-9]{4}@v") { xlog("L_INFO","Main leg\n"); rtpengine_manage("replace-origin RTP/AVP external internal"); } else if ($ru =~ "192.168.106.34") { xlog("L_INFO","Forked leg\n"); rtpengine_manage("replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode external internal via-branch=1"); //rtpengine_manage("label=$fu--->$ru sdp-media-remove=video replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode ptime=20 external internal via-branch=1"); # only with patched module } } }
if (is_reply()) { if (has_body("application/sdp") && (status=="200")) { xlog("L_INFO","Negotiate RTP answer for branch $T_branch_idx\n"); } }
return; }
```
There is a branch_route where you need to do those manipulations per branch
On Thu, 9 Apr 2026, 17:28 e.titovets--- via sr-users, < sr-users@lists.kamailio.org> wrote:
Hi All,
I am using Kamailio with rtpengine and have a parallel forking scenario (single INVITE -> multiple branches via append_branch()). Incoming INVITE has SDP with video Goal:
- For Main branch : keep audio + video
- For Forked branch: strip video (audio only)
Problem: SDP manipulation seems to be applied globally to the message, not per branch.
What I tried:
- Using textops: sdp_remove_media("video"); msg_apply_changes();
- Trying to do it per branch:
I attempted to move this logic into branch_route, but msg_apply_changes() is not allowed there, so SDP changes are not applied. Documentation stated that it can be used from from REQUEST_ROUTE or REPLY_ROUTE.
- Using rtpengine:
According to rtpengine NG protocol, "offer" supports: "sdp-media-remove": ["video"] However, I cannot find a way to pass this parameter via Kamailio's rtpengine module. Tried to add flag sdp-media-remove=video to the rtpengine_manage() but it doesn't work.
Environment:
- Kamailio version: 6.0.6
- rtpengine version: 13.5.1.6
Question: What is the correct way to modify SDP per branch in a parallel forking scenario in Kamailio? My test routing config:
request_route { if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } if (!is_method("ACK")) { if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); } # remove unused codecs and media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # } if (is_method("INVITE") && !has_totag()) { dlg_manage(); } remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) { record_route(); } if ($rU==$null) { sl_send_reply("484","Address Incomplete"); exit; } route(LOCATION); return; } route[RELAY] { 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; } route[LOCATION] { route(ADD_FORK); route(RELAY); } route[ADD_FORK] { $avp(extNum) = "abcd@192.168.106.34"; append_branch("sip:" + $(avp(extNum))); } branch_route[MANAGE_BRANCH] { route(NATMANAGE); } onreply_route[MANAGE_REPLY] { # remove video media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # } if(status=~"[12][0-9][0-9]") { route(NATMANAGE); } } failure_route[MANAGE_FAILURE] { route(NATMANAGE); if (t_is_canceled()) exit; } route[NATMANAGE] { if (is_request()) { if (has_body("application/sdp")) { xlog("L_INFO","Negotiate RTP offer for branch $T_branch_idx\n"); if ($ru =~ "^sip:1[0-9]{4}@v") { xlog("L_INFO","Main leg\n"); rtpengine_manage("replace-origin RTP/AVP external internal"); } else if ($ru =~ "192.168.106.34") { xlog("L_INFO","Forked leg\n"); rtpengine_manage("replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode external internal via-branch=1"); //rtpengine_manage("label=$fu--->$ru sdp-media-remove=video replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode ptime=20 external internal via-branch=1"); # only with patched module } } } if (is_reply()) { if (has_body("application/sdp") && (status=="200")) { xlog("L_INFO","Negotiate RTP answer for branch $T_branch_idx\n"); } } return; }
Kamailio - Users Mailing List - Non Commercial Discussions -- sr-users@lists.kamailio.org To unsubscribe send an email to sr-users-leave@lists.kamailio.org Important: keep the mailing list in the recipients, do not reply only to the sender!
On 09/04/2026 10.54, e.titovets--- via sr-users wrote:
- Using rtpengine:
According to rtpengine NG protocol, "offer" supports: "sdp-media-remove": ["video"] However, I cannot find a way to pass this parameter via Kamailio's rtpengine module. Tried to add flag sdp-media-remove=video to the rtpengine_manage() but it doesn't work.
Environment:
- Kamailio version: 6.0.6
- rtpengine version: 13.5.1.6
You can enable debug logging on rtpengine and see what it has to say about what it receives from Kamailio when you do this.
In general: With these versions, you should be able to use the "extended" 2-argument syntax for rtpengine_offer/_answer/_manage, by putting the branch value (which you need anyway) as second argument, which allows you to use this syntax directly, for example:
rtpengine_manage("replace-origin RTP/AVP ... sdp-media-remove=[video]", "auto-next");
"auto-next" is to use the generated branch value in a branch route, and to use the value from the header in a response. Depending on your scenario and config you may have to use different values (rtpengine must be able to match an answer to the corresponding branched offer).
Cheers
Hi Richard!
Thank You for the idea.
I've been experimening with rtpengine debug. If I use rtpengine_manage("sdp-media-remove=video ..."), it sends {..., "sdp-media-remove": "video", ...} to rtpengine. Also tried rtpengine_manage("sdp-media-remove=[video],..."). In that case it sends {..., "sdp-media-remove": "[video]", ...} Looks like rtpengine just ignore it,
If I send a raw NG command via 3-rd party client (not from kamailio) it sends {..., "sdp-media-remove": [ "video" ], ...} So in this case, the key "sdp-media-remove" is sent as a list with one element. There is also a note in the rtpengine logs: "[core] Media type 'video' is to be removed by SDP manipulations.".
Looks like the issue is related to the data format.
On 10/04/2026 06.18, e.titovets--- via sr-users wrote:
Also tried rtpengine_manage("sdp-media-remove=[video],..."). In that case it sends {..., "sdp-media-remove": "[video]", ...} Looks like rtpengine just ignore it,
Were you using the two-argument form of the function call in your Kamailio script?
Richard Fuchs wrote:
Were you using the two-argument form of the function call in your
Kamailio script?
Wow, I didn't realize there was a difference at first. Indeed, it looks like two-argument form works as I need. I will experiment further. Thanks again for the referral.
Sorry, didn't see the full text of the message. Ignore my answer please.
On Thu, 9 Apr 2026, 17:28 e.titovets--- via sr-users, < sr-users@lists.kamailio.org> wrote:
Hi All,
I am using Kamailio with rtpengine and have a parallel forking scenario (single INVITE -> multiple branches via append_branch()). Incoming INVITE has SDP with video Goal:
- For Main branch : keep audio + video
- For Forked branch: strip video (audio only)
Problem: SDP manipulation seems to be applied globally to the message, not per branch.
What I tried:
- Using textops: sdp_remove_media("video"); msg_apply_changes();
- Trying to do it per branch:
I attempted to move this logic into branch_route, but msg_apply_changes() is not allowed there, so SDP changes are not applied. Documentation stated that it can be used from from REQUEST_ROUTE or REPLY_ROUTE.
- Using rtpengine:
According to rtpengine NG protocol, "offer" supports: "sdp-media-remove": ["video"] However, I cannot find a way to pass this parameter via Kamailio's rtpengine module. Tried to add flag sdp-media-remove=video to the rtpengine_manage() but it doesn't work.
Environment:
- Kamailio version: 6.0.6
- rtpengine version: 13.5.1.6
Question: What is the correct way to modify SDP per branch in a parallel forking scenario in Kamailio? My test routing config:
request_route { if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; } if (!is_method("ACK")) { if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); } # remove unused codecs and media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # } if (is_method("INVITE") && !has_totag()) { dlg_manage(); } remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) { record_route(); } if ($rU==$null) { sl_send_reply("484","Address Incomplete"); exit; } route(LOCATION); return; } route[RELAY] { 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; } route[LOCATION] { route(ADD_FORK); route(RELAY); } route[ADD_FORK] { $avp(extNum) = "abcd@192.168.106.34"; append_branch("sip:" + $(avp(extNum))); } branch_route[MANAGE_BRANCH] { route(NATMANAGE); } onreply_route[MANAGE_REPLY] { # remove video media # if (has_body("application/sdp")) { # sdp_remove_media("video"); # msg_apply_changes(); # } if(status=~"[12][0-9][0-9]") { route(NATMANAGE); } } failure_route[MANAGE_FAILURE] { route(NATMANAGE); if (t_is_canceled()) exit; } route[NATMANAGE] { if (is_request()) { if (has_body("application/sdp")) { xlog("L_INFO","Negotiate RTP offer for branch $T_branch_idx\n"); if ($ru =~ "^sip:1[0-9]{4}@v") { xlog("L_INFO","Main leg\n"); rtpengine_manage("replace-origin RTP/AVP external internal"); } else if ($ru =~ "192.168.106.34") { xlog("L_INFO","Forked leg\n"); rtpengine_manage("replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode external internal via-branch=1"); //rtpengine_manage("label=$fu--->$ru sdp-media-remove=video replace-origin RTP/AVP codec-mask=telephone-event transcode=PCMA always-transcode ptime=20 external internal via-branch=1"); # only with patched module } } } if (is_reply()) { if (has_body("application/sdp") && (status=="200")) { xlog("L_INFO","Negotiate RTP answer for branch $T_branch_idx\n"); } } return; }
Kamailio - Users Mailing List - Non Commercial Discussions -- sr-users@lists.kamailio.org To unsubscribe send an email to sr-users-leave@lists.kamailio.org Important: keep the mailing list in the recipients, do not reply only to the sender!