Summary:ASTERISK-13790: directrpsetup=yes does not work when canreinvite=n
Reporter:Ryan Bullock (rrb3942)Labels:
Date Opened:2009-03-20 09:47:47Date Closed:2009-09-10 14:42:02
Versions:Frequency of
Environment:Attachments:( 0) canreinvite.txt
( 1) nocanreinvite.txt
Description:If directrtpsetup is set to to 'yes' and canreinvite is set to 'no' Asterisk will not perform native bridging on the channels during the call setup.

If directrtpsetup is set to 'yes' and canreinvite is set to 'yes' Asterisk will perform native bridging on the channels during the call setup.

I did not see any note in the documentation that directrtpsetup requires the peer to also support canreinvite=yes.

I am not sure if this is intended behavior because without being able to RE-INVITE Asterisk would not be able to re-insert itself into the media path for possible features later in the dialplan.


If a device does not work well with RE-INVITES but you still would like the media to flow directly between the two endpoints (knowing you will lose access to features, as asterisk cannot re-insert itself into the media path) you cannot use directrtpsetup=yes and canreinvite=no.

If you use directrtpsetup=yes and canreinvite=yes Asterisk will still issue a RE-INVITE before a BYE during a call hangup to the party that did not issue the original BYE to tear down the call. This may cause some unexpected/improper behavior during the call hangup.
Comments:By: Ryan Bullock (rrb3942) 2009-03-20 09:49:42

I have attached debug and verbose logs of calls with directrtpsetup=yes and with canreinvite=yes and canreinvite=no.

By: Leif Madsen (lmadsen) 2009-06-10 12:25:57

Assigned to file to determine if this expected, or unexpected behaviour. Thanks!

By: Shlomi Hazan (hzshlomi) 2009-07-26 06:03:50

This is not the complete story with "directrtpsetup":
the disconnect handling is wrong: when asterisk receives the BYE, it initiates a re-invite (connecting media back to asterisk) instead of simply disconnecting the call.
Further and much more problematic, if the re-invite fails, the call is left dangling forever! This is not a minor bug.

it should be at least possible to configure whether to re-invite on bye and maybe support it directly in Dial().

By: Shlomi Hazan (hzshlomi) 2009-07-26 09:25:29


I made a little hack in sip_set_rtp_peer() for the case where asterisk re-invites after BYE. Not a pretty one. here it is (see the /*SHLOMI*/):

static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
struct sip_pvt *p;
int changed = 0;

p = chan->tech_pvt;
if (!p)
return -1;

/* Disable early RTP bridge  */
if (chan->_state != AST_STATE_UP && !global_directrtpsetup) /* We are in early state */
return 0;

if (p->alreadygone) {
/* If we're destroyed, don't bother */
return 0;

/* if this peer cannot handle reinvites of the media stream to devices
  that are known to be behind a NAT, then stop the process now
if (nat_active && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
return 0;

if (rtp) {
changed |= ast_rtp_get_peer(rtp, &p->redirip);
} else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
memset(&p->redirip, 0, sizeof(p->redirip));
changed = 1;
if (vrtp) {
changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
} else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
memset(&p->vredirip, 0, sizeof(p->vredirip));
changed = 1;
if (trtp) {
changed |= ast_rtp_get_peer(trtp, &p->tredirip);
} else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
memset(&p->tredirip, 0, sizeof(p->tredirip));
changed = 1;
if (codecs && (p->redircodecs != codecs)) {
p->redircodecs = codecs;
changed = 1;
if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
if (chan->_state != AST_STATE_UP) { /* We are in early state */
if (p->do_history)
append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
} else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */
if (chan->_bridge && chan->_bridge->_softhangup) {
ast_verbose("Call %s is going down (Skipping SIP RE-INVITE) !\n", p->callid);
else {
ast_verbose("Call %s sending SIP RE-INVITE !\n", p->callid);
ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
transmit_reinvite_with_sdp(p, FALSE, FALSE);
} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
/* We have a pending Invite. Send re-invite when we're done with the invite */
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
/* Reset lastrtprx timer */
p->lastrtprx = p->lastrtptx = time(NULL);
return 0;

By: Olle Johansson (oej) 2009-09-03 14:39:51

1) Directrtpsetup is marked experimental and not officially supported

2) canreinvite=n is really overriding directrtpsetup and should, since you by setting this disable all remote bridges. We've renamed canreinvite to "directmedia" to give it a better name that is easier to understand.

So I don't consider the fact that directrtpsetup=y and canreinvite=n means that there will be no directrtpsetup. It's correct behaviour.

And yes, if you're using directrtpsetup a lot of strange stuff may happen. There's a reason why it's still considered experimental after many releases - it's very hard to fix it properly and will require a large rewrite of our media negotiation and handling structure.

By: Olle Johansson (oej) 2009-09-10 14:42:01

No comment from reporter after one week. Closing this issue.