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.…
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
--
Daniel-Constantin Mierla --
www.asipto.com
www.twitter.com/miconda --
www.linkedin.com/in/miconda
Kamailio World Conference - May 6-8, 2019 --
www.kamailioworld.com
Kamailio Advanced Training - Mar 4-6, 2019 in Berlin; Mar 25-27, 2019, in Washington, DC,
USA --
www.asipto.com