mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	Make SIP early media work more efficiently without so many reinvites
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@26019 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -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
	
	Block a user