Hello,
rtpengine_manage() as well as rtpproxy_manage() do a delete command if it is a failure processing context, like failure_route or resuming a suspended transaction (which is like canceling the suspended branch).
The reason for doing delete is to allow disengaging rtpengine after a forwarding failure, to allow the option of no rtp relay for next attempts. The manage function has its roots in the default configuration time from several years ago where in failur_route there was an unforce proxy command, and engaging the rtpproxy was in branch route.
So, in such cases, if you want to route to a new destination, you should use the function in branch_route. Which is actually a good practice, using rtp relay makes sense only if there is an outgoing branch.
Cheers, Daniel
On 15.01.19 02:36, Alex Balashov wrote:
Hi,
I've run into an issue with handling reinvites in async task workers--which I need to do in order to introduce a small delay to avoid a UA race condition--in which some state that is necessary for rtpengine_manage() to do the right thing seems to be lost.
Specifically, if I do this:
-- loadmodule "mqueue" loadmodule "rtimer"
...
modparam("rtimer", "timer", "name=reinvite_q1;interval=10000u;mode=1;") modparam("rtimer", "exec", "timer=reinvite_q1;route=REINVITE_DEQUEUE")
modparam("mqueue", "mqueue", "name=reinvite_q");
...
route { ...
if(has_totag()) { if(loose_route()) { ...
if(is_method("INVITE")) { if(!t_suspend()) { sl_send_reply("500", "Server Internal Error"); exit; } mq_add("reinvite_q", "$T(id_index):$T(id_label)", ""); } else route(IN_DLG_REQ); exit;
}
... }
route[REINVITE_DEQUEUE] { while(mq_fetch("reinvite_q")) { $var(id) = $(mqk(reinvite_q){s.select,0,:}{s.int}); $var(label) = $(mqk(reinvite_q){s.select,1,:}{s.int});
t_continue("$var(id)", "$var(label)", "IN_DLG_REQ");
} }
route[IN_DLG_REQ] { handle_ruri_alias();
if(is_method("BYE")) rtpengine_manage(); else if(is_method("INVITE") && sdp_content()) rtpengine_manage("replace-origin replace-session-connection ICE=remove")
t_on_reply("MAIN_REPLY");
if(!t_relay()) sl_reply_error(); }
onreply_route[MAIN_REPLY] { if(is_method("INVITE") && sdp_content()) rtpengine_manage("replace-origin replace-session-connection ICE=remove"); } --
What I find is that if I generate a reinvite from either side, rtpengine_manage() passes through the SDP offer in the reinvite unadulterated, although the answer returns properly adulterated by RTPEngine.
The same thing occurs if I use 'async', which as I gather is just a wrapper of convenience around t_suspend/t_continue() anyway. That module won't do for my purposes because I need a millisecond-level delay resolution rather than second-level, anyhow.
Anyway, surely enough, this is because the execution context is one that insinuates a stream deletion. When the reinvite offer comes across and I call rtpengine_manage(), the command sent is 'delete':
-- Jan 14 20:24:23 staccato.evaristesys.com rtpengine[33830]: INFO: [c94347dcf92e7ccc10dee84c4e0d1c8a]: Received command 'delete' from 209.51.167.66:39788 --
The RTPEngine module documentation actually warns about this:
https://kamailio.org/docs/modules/5.2.x/modules/rtpengine.html#rtpengine.f.r...
But this insight is buried in the fourth bullet point:
"If BYE or CANCEL, or called within a FAILURE_ROUTE[], then call rtpengine_delete(). Be careful with calling this function after resuming a suspended transaction (e.g., after t_continue()), because the context of executed route is FAILURE ROUTE (in other words, rtpengine_manage() in the route block of t_continue() does the same as in failure_route)."
This would lead one to believe that it applies only in the context of handling a BYE or CANCEL in a resumed transaction, when in fact it seems to hold true of non-BYE/CANCEL and non-failure contexts as well, as can be clearly seen with the reinvite.
The behaviour is exactly as expected if I don't use rtpengine_manage() and instead manually call rtpengine_offer()/rtpengine_answer(). And expected behaviour comes from rtpengine_manage() if I don't handle the request in a resumed transaction context.
This yields the fundamental question:
Is there any way to have my cake and eat it too? I really want to use rtpengine_manage() because I need to handle a potential SDP offer-in-ACK scenario and don't want to do a bunch of state-keeping in order to use the correct choice of rtpengine_{offer|answer}() in the right context, which is a problem rtpengine_manage() solves beautifully. At the same time, I absolutely need the slight reinvite delay that can be accomplished via async processing; a UA on this side has a nasty habit of sending a reinvite almost simultaneously to the 2xx answer for the INVITE transaction, leading to indeterminate egress velocity for those respective messages out of Kamailio worker threads.
Many thanks in advance!
-- Alex