Make SIP early media work more efficiently without so many reinvites
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@26019 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
faf703671d
commit
3da3803c07
|
@ -482,7 +482,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||
ast_clear_flag(o, DIAL_STILLGOING);
|
||||
HANDLE_CAUSE(cause, in);
|
||||
} else {
|
||||
ast_rtp_make_compatible(c, in);
|
||||
ast_rtp_make_compatible(c, in, single);
|
||||
if (c->cid.cid_num)
|
||||
free(c->cid.cid_num);
|
||||
c->cid.cid_num = NULL;
|
||||
|
@ -550,6 +550,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
|
||||
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
|
||||
DIAL_NOFORWARDHTML);
|
||||
/* Setup early media if appropriate */
|
||||
ast_rtp_early_media(in, peer);
|
||||
}
|
||||
/* If call has been answered, then the eventual hangup is likely to be normal hangup */
|
||||
in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
|
||||
|
@ -576,6 +578,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||
case AST_CONTROL_RINGING:
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name);
|
||||
/* Setup early media if appropriate */
|
||||
if (single)
|
||||
ast_rtp_early_media(in, c);
|
||||
if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
|
||||
ast_indicate(in, AST_CONTROL_RINGING);
|
||||
(*sentringing)++;
|
||||
|
@ -584,6 +589,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||
case AST_CONTROL_PROGRESS:
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", c->name, in->name);
|
||||
/* Setup early media if appropriate */
|
||||
if (single)
|
||||
ast_rtp_early_media(in, c);
|
||||
if (!ast_test_flag(outgoing, OPT_RINGBACK))
|
||||
ast_indicate(in, AST_CONTROL_PROGRESS);
|
||||
break;
|
||||
|
@ -595,6 +603,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||
case AST_CONTROL_PROCEEDING:
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", c->name, in->name);
|
||||
if (single)
|
||||
ast_rtp_early_media(in, c);
|
||||
if (!ast_test_flag(outgoing, OPT_RINGBACK))
|
||||
ast_indicate(in, AST_CONTROL_PROCEEDING);
|
||||
break;
|
||||
|
@ -1056,7 +1066,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
|
|||
}
|
||||
|
||||
/* Setup outgoing SDP to match incoming one */
|
||||
ast_rtp_make_compatible(tmp->chan, chan);
|
||||
ast_rtp_make_compatible(tmp->chan, chan, !outgoing && !rest);
|
||||
|
||||
/* Inherit specially named variables from parent channel */
|
||||
ast_channel_inherit_variables(chan, tmp->chan);
|
||||
|
@ -1550,6 +1560,7 @@ out:
|
|||
sentringing = 0;
|
||||
ast_indicate(chan, -1);
|
||||
}
|
||||
ast_rtp_early_media(chan, NULL);
|
||||
hanguptree(outgoing, NULL);
|
||||
pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
|
||||
if (option_debug)
|
||||
|
|
|
@ -13588,6 +13588,7 @@ static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan)
|
|||
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
|
||||
{
|
||||
struct sip_pvt *p;
|
||||
int changed = 0;
|
||||
|
||||
p = chan->tech_pvt;
|
||||
if (!p)
|
||||
|
@ -13598,17 +13599,23 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
|
|||
ast_mutex_unlock(&p->lock);
|
||||
return 0;
|
||||
}
|
||||
if (rtp)
|
||||
ast_rtp_get_peer(rtp, &p->redirip);
|
||||
if (rtp)
|
||||
changed |= ast_rtp_get_peer(rtp, &p->redirip);
|
||||
else
|
||||
memset(&p->redirip, 0, sizeof(p->redirip));
|
||||
if (vrtp)
|
||||
ast_rtp_get_peer(vrtp, &p->vredirip);
|
||||
changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
|
||||
else
|
||||
memset(&p->vredirip, 0, sizeof(p->vredirip));
|
||||
p->redircodecs = codecs;
|
||||
if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
|
||||
if (!p->pendinginvite) {
|
||||
if (p->redircodecs != codecs) {
|
||||
p->redircodecs = codecs;
|
||||
changed = 1;
|
||||
}
|
||||
if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
ast_log(LOG_DEBUG, "Early media setting SIP '%s' - Sending early media to %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
|
||||
} else if (!p->pendinginvite) {
|
||||
if (option_debug > 2) {
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
|
||||
|
|
|
@ -97,7 +97,8 @@ struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io
|
|||
|
||||
void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
|
||||
|
||||
void ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
|
||||
/* Copies from rtp to them and returns 1 if there was a change or 0 if it was already the same */
|
||||
int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
|
||||
|
||||
void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us);
|
||||
|
||||
|
@ -154,7 +155,9 @@ int ast_rtp_proto_register(struct ast_rtp_protocol *proto);
|
|||
|
||||
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto);
|
||||
|
||||
int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src);
|
||||
int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media);
|
||||
|
||||
int ast_rtp_early_media(struct ast_channel *dest, struct ast_channel *src);
|
||||
|
||||
void ast_rtp_stop(struct ast_rtp *rtp);
|
||||
|
||||
|
|
97
rtp.c
97
rtp.c
|
@ -733,11 +733,83 @@ static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
|
|||
return cur;
|
||||
}
|
||||
|
||||
int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src)
|
||||
int ast_rtp_early_media(struct ast_channel *dest, struct ast_channel *src)
|
||||
{
|
||||
struct ast_rtp *destp, *srcp=NULL; /* Audio RTP Channels */
|
||||
struct ast_rtp *vdestp, *vsrcp=NULL; /* Video RTP channels */
|
||||
struct ast_rtp_protocol *destpr, *srcpr=NULL;
|
||||
int srccodec;
|
||||
/* Lock channels */
|
||||
ast_channel_lock(dest);
|
||||
if (src) {
|
||||
while(ast_channel_trylock(src)) {
|
||||
ast_channel_unlock(dest);
|
||||
usleep(1);
|
||||
ast_channel_lock(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find channel driver interfaces */
|
||||
destpr = get_proto(dest);
|
||||
if (src)
|
||||
srcpr = get_proto(src);
|
||||
if (!destpr) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", dest->name);
|
||||
ast_channel_unlock(dest);
|
||||
if (src)
|
||||
ast_channel_unlock(src);
|
||||
return 0;
|
||||
}
|
||||
if (!srcpr) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", src->name);
|
||||
ast_channel_unlock(dest);
|
||||
if (src)
|
||||
ast_channel_unlock(src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get audio and video interface (if native bridge is possible) */
|
||||
destp = destpr->get_rtp_info(dest);
|
||||
vdestp = (destpr->get_vrtp_info) ? destpr->get_vrtp_info(dest) : NULL;
|
||||
if (srcpr) {
|
||||
srcp = srcpr->get_rtp_info(src);
|
||||
vsrcp = (srcpr->get_vrtp_info) ? srcpr->get_vrtp_info(src) : NULL;
|
||||
}
|
||||
|
||||
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
|
||||
if (!destp) {
|
||||
/* Somebody doesn't want to play... */
|
||||
ast_channel_unlock(dest);
|
||||
if (src)
|
||||
ast_channel_unlock(src);
|
||||
return 0;
|
||||
}
|
||||
if (srcpr && srcpr->get_codec)
|
||||
srccodec = srcpr->get_codec(src);
|
||||
else
|
||||
srccodec = 0;
|
||||
/* Consider empty media as non-existant */
|
||||
if (srcp && !srcp->them.sin_addr.s_addr)
|
||||
srcp = NULL;
|
||||
/* Bridge early media */
|
||||
if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to send early media to '%s'\n", dest->name, src ? src->name : "<unspecified>");
|
||||
ast_channel_unlock(dest);
|
||||
if (src)
|
||||
ast_channel_unlock(src);
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Setting early media SDP of '%s' with that of '%s'\n", dest->name, src ? src->name : "<unspecified>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media)
|
||||
{
|
||||
struct ast_rtp *destp, *srcp; /* Audio RTP Channels */
|
||||
struct ast_rtp *vdestp, *vsrcp; /* Video RTP channels */
|
||||
struct ast_rtp_protocol *destpr, *srcpr;
|
||||
int srccodec;
|
||||
/* Lock channels */
|
||||
ast_channel_lock(dest);
|
||||
while(ast_channel_trylock(src)) {
|
||||
|
@ -780,6 +852,15 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src)
|
|||
ast_rtp_pt_copy(destp, srcp);
|
||||
if (vdestp && vsrcp)
|
||||
ast_rtp_pt_copy(vdestp, vsrcp);
|
||||
if (srcpr->get_codec)
|
||||
srccodec = srcpr->get_codec(src);
|
||||
else
|
||||
srccodec = 0;
|
||||
if (media) {
|
||||
/* Bridge early media */
|
||||
if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to send early media to '%s'\n", dest->name, src->name);
|
||||
}
|
||||
ast_channel_unlock(dest);
|
||||
ast_channel_unlock(src);
|
||||
if (option_debug)
|
||||
|
@ -1086,11 +1167,17 @@ void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
|
|||
rtp->rxseqno = 0;
|
||||
}
|
||||
|
||||
void ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
|
||||
int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
|
||||
{
|
||||
them->sin_family = AF_INET;
|
||||
them->sin_port = rtp->them.sin_port;
|
||||
them->sin_addr = rtp->them.sin_addr;
|
||||
if ((them->sin_family != AF_INET) ||
|
||||
(them->sin_port != rtp->them.sin_port) ||
|
||||
(them->sin_addr.s_addr != rtp->them.sin_addr.s_addr)) {
|
||||
them->sin_family = AF_INET;
|
||||
them->sin_port = rtp->them.sin_port;
|
||||
them->sin_addr = rtp->them.sin_addr;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us)
|
||||
|
|
Reference in New Issue