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
--
Alex Balashov | Principal | Evariste Systems LLC
Tel: +1-706-510-6800 / +1-800-250-5920 (toll-free)
Web:
http://www.evaristesys.com/,
http://www.csrpswitch.com/